coradoc 0.3.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -0
  3. data/exe/reverse_adoc +24 -3
  4. data/lib/coradoc/document.rb +1 -0
  5. data/lib/coradoc/element/admonition.rb +2 -2
  6. data/lib/coradoc/element/attribute.rb +2 -2
  7. data/lib/coradoc/element/attribute_list.rb +94 -15
  8. data/lib/coradoc/element/audio.rb +13 -2
  9. data/lib/coradoc/element/author.rb +4 -2
  10. data/lib/coradoc/element/base.rb +70 -7
  11. data/lib/coradoc/element/block/core.rb +8 -4
  12. data/lib/coradoc/element/block/quote.rb +1 -1
  13. data/lib/coradoc/element/block/side.rb +1 -1
  14. data/lib/coradoc/element/break.rb +1 -1
  15. data/lib/coradoc/element/document_attributes.rb +6 -6
  16. data/lib/coradoc/element/header.rb +4 -2
  17. data/lib/coradoc/element/image/block_image.rb +13 -2
  18. data/lib/coradoc/element/image/core.rb +37 -6
  19. data/lib/coradoc/element/image/inline_image.rb +2 -2
  20. data/lib/coradoc/element/inline/anchor.rb +4 -2
  21. data/lib/coradoc/element/inline/bold.rb +9 -4
  22. data/lib/coradoc/element/inline/cross_reference.rb +4 -2
  23. data/lib/coradoc/element/inline/hard_line_break.rb +1 -1
  24. data/lib/coradoc/element/inline/highlight.rb +11 -6
  25. data/lib/coradoc/element/inline/italic.rb +9 -4
  26. data/lib/coradoc/element/inline/link.rb +22 -6
  27. data/lib/coradoc/element/inline/monospace.rb +9 -4
  28. data/lib/coradoc/element/inline/quotation.rb +3 -1
  29. data/lib/coradoc/element/inline/subscript.rb +4 -2
  30. data/lib/coradoc/element/inline/superscript.rb +4 -2
  31. data/lib/coradoc/element/list/core.rb +15 -7
  32. data/lib/coradoc/element/list/definition.rb +22 -1
  33. data/lib/coradoc/element/list/ordered.rb +1 -1
  34. data/lib/coradoc/element/list/unordered.rb +1 -1
  35. data/lib/coradoc/element/list.rb +1 -0
  36. data/lib/coradoc/element/list_item.rb +16 -3
  37. data/lib/coradoc/element/list_item_definition.rb +32 -0
  38. data/lib/coradoc/element/paragraph.rb +6 -4
  39. data/lib/coradoc/element/revision.rb +4 -2
  40. data/lib/coradoc/element/section.rb +27 -4
  41. data/lib/coradoc/element/table.rb +32 -10
  42. data/lib/coradoc/element/text_element.rb +48 -8
  43. data/lib/coradoc/element/title.rb +27 -7
  44. data/lib/coradoc/element/video.rb +32 -5
  45. data/lib/coradoc/reverse_adoc/README.adoc +14 -8
  46. data/lib/coradoc/reverse_adoc/cleaner.rb +21 -10
  47. data/lib/coradoc/reverse_adoc/config.rb +35 -16
  48. data/lib/coradoc/reverse_adoc/converters/a.rb +17 -12
  49. data/lib/coradoc/reverse_adoc/converters/aside.rb +0 -4
  50. data/lib/coradoc/reverse_adoc/converters/audio.rb +0 -4
  51. data/lib/coradoc/reverse_adoc/converters/base.rb +48 -44
  52. data/lib/coradoc/reverse_adoc/converters/blockquote.rb +2 -11
  53. data/lib/coradoc/reverse_adoc/converters/br.rb +0 -4
  54. data/lib/coradoc/reverse_adoc/converters/bypass.rb +0 -4
  55. data/lib/coradoc/reverse_adoc/converters/code.rb +5 -42
  56. data/lib/coradoc/reverse_adoc/converters/div.rb +0 -4
  57. data/lib/coradoc/reverse_adoc/converters/dl.rb +55 -0
  58. data/lib/coradoc/reverse_adoc/converters/em.rb +5 -43
  59. data/lib/coradoc/reverse_adoc/converters/figure.rb +0 -4
  60. data/lib/coradoc/reverse_adoc/converters/h.rb +0 -4
  61. data/lib/coradoc/reverse_adoc/converters/head.rb +0 -4
  62. data/lib/coradoc/reverse_adoc/converters/hr.rb +0 -4
  63. data/lib/coradoc/reverse_adoc/converters/img.rb +30 -18
  64. data/lib/coradoc/reverse_adoc/converters/li.rb +0 -4
  65. data/lib/coradoc/reverse_adoc/converters/mark.rb +5 -11
  66. data/lib/coradoc/reverse_adoc/converters/markup.rb +27 -0
  67. data/lib/coradoc/reverse_adoc/converters/ol.rb +0 -4
  68. data/lib/coradoc/reverse_adoc/converters/p.rb +0 -4
  69. data/lib/coradoc/reverse_adoc/converters/pre.rb +0 -4
  70. data/lib/coradoc/reverse_adoc/converters/q.rb +0 -4
  71. data/lib/coradoc/reverse_adoc/converters/strong.rb +5 -41
  72. data/lib/coradoc/reverse_adoc/converters/sub.rb +6 -4
  73. data/lib/coradoc/reverse_adoc/converters/sup.rb +7 -5
  74. data/lib/coradoc/reverse_adoc/converters/table.rb +240 -4
  75. data/lib/coradoc/reverse_adoc/converters/td.rb +1 -7
  76. data/lib/coradoc/reverse_adoc/converters/text.rb +1 -38
  77. data/lib/coradoc/reverse_adoc/converters/tr.rb +0 -4
  78. data/lib/coradoc/reverse_adoc/converters/video.rb +0 -4
  79. data/lib/coradoc/reverse_adoc/converters.rb +24 -1
  80. data/lib/coradoc/reverse_adoc/html_converter.rb +109 -20
  81. data/lib/coradoc/reverse_adoc/plugin.rb +131 -0
  82. data/lib/coradoc/reverse_adoc/plugins/plateau.rb +206 -0
  83. data/lib/coradoc/reverse_adoc/postprocessor.rb +152 -0
  84. data/lib/coradoc/reverse_adoc.rb +3 -0
  85. data/lib/coradoc/util.rb +10 -0
  86. data/lib/coradoc/version.rb +1 -1
  87. data/lib/coradoc.rb +1 -0
  88. data/lib/reverse_adoc.rb +1 -1
  89. metadata +9 -3
  90. data/lib/coradoc/element/inline/image.rb +0 -26
@@ -8,10 +8,6 @@ module Coradoc::ReverseAdoc
8
8
  Coradoc::Element::Block::Example.new(title, lines: content, id: id)
9
9
  end
10
10
 
11
- def convert(node, state = {})
12
- Coradoc::Generator.gen_adoc(to_coradoc(node, state))
13
- end
14
-
15
11
  def extract_title(node)
16
12
  title = node.at("./figcaption")
17
13
  return "" if title.nil?
@@ -15,10 +15,6 @@ module Coradoc::ReverseAdoc
15
15
  Coradoc::Element::Title.new(content, level, id: id)
16
16
  end
17
17
 
18
- def convert(node, state = {})
19
- Coradoc::Generator.gen_adoc(to_coradoc(node, state))
20
- end
21
-
22
18
  def treat_children_no_anchors(node, state)
23
19
  node.children.reject { |a| a.name == "a" }.inject([]) do |memo, child|
24
20
  memo << treat_coradoc(child, state)
@@ -6,10 +6,6 @@ module Coradoc::ReverseAdoc
6
6
  Coradoc::Element::Header.new(title)
7
7
  end
8
8
 
9
- def convert(node, state = {})
10
- Coradoc::Generator.gen_adoc(to_coradoc(node, state))
11
- end
12
-
13
9
  def extract_title(node)
14
10
  title = node.at("./title")
15
11
  return "(???)" if title.nil?
@@ -4,10 +4,6 @@ module Coradoc::ReverseAdoc
4
4
  def to_coradoc(_node, _state = {})
5
5
  Coradoc::Element::Break::ThematicBreak.new
6
6
  end
7
-
8
- def convert(node, state = {})
9
- Coradoc::Generator.gen_adoc(to_coradoc(node, state))
10
- end
11
7
  end
12
8
 
13
9
  register :hr, Hr.new
@@ -19,22 +19,32 @@ module Coradoc::ReverseAdoc
19
19
  end
20
20
 
21
21
  def datauri2file(src)
22
+ return unless src
23
+
22
24
  %r{^data:image/(?:[^;]+);base64,(?<imgdata>.+)$} =~ src
23
25
 
24
26
  dest_dir = Pathname.new(Coradoc::ReverseAdoc.config.destination).dirname
25
27
  images_dir = dest_dir.join("images")
26
28
  FileUtils.mkdir_p(images_dir)
27
29
 
28
- ext, image_src_path = determine_image_src_path(src, imgdata)
30
+ ext, image_src_path, tempfile = determine_image_src_path(src, imgdata)
29
31
  image_dest_path = images_dir + "#{image_number}.#{ext}"
30
32
 
31
33
  # puts "image_dest_path: #{image_dest_path.to_s}"
32
34
  # puts "image_src_path: #{image_src_path.to_s}"
33
35
 
34
- FileUtils.cp(image_src_path, image_dest_path)
36
+ if File.exist?(image_src_path)
37
+ FileUtils.cp(image_src_path, image_dest_path)
38
+ else
39
+ @annotate_missing = image_src_path
40
+ Kernel.warn "Image #{image_src_path} does not exist"
41
+ end
42
+
35
43
  image_number_increment
36
44
 
37
45
  image_dest_path.relative_path_from(dest_dir)
46
+ ensure
47
+ tempfile&.close!
38
48
  end
39
49
 
40
50
  def determine_image_src_path(src, imgdata)
@@ -45,13 +55,13 @@ module Coradoc::ReverseAdoc
45
55
  end
46
56
 
47
57
  def copy_temp_file(imgdata)
48
- Tempfile.open(["radoc", ".jpg"]) do |f|
49
- f.binmode
50
- f.write(Base64.strict_decode64(imgdata))
51
- f.rewind
52
- ext = Marcel::MimeType.for(f).sub(%r{^[^/]+/}, "")
53
- [ext, f.path]
54
- end
58
+ f = Tempfile.open(["radoc", ".jpg"])
59
+ f.binmode
60
+ f.write(Base64.strict_decode64(imgdata))
61
+ f.rewind
62
+ ext = Marcel::MimeType.for(f).sub(%r{^[^/]+/}, "")
63
+ ext = "svg" if ext == "svg+xml"
64
+ [ext, f.path, f]
55
65
  end
56
66
 
57
67
  def to_coradoc(node, _state = {})
@@ -61,6 +71,9 @@ module Coradoc::ReverseAdoc
61
71
  width = node["width"]
62
72
  height = node["height"]
63
73
 
74
+ width = width.to_i if width&.match?(/\A\d+\z/)
75
+ height = height.to_i if height&.match?(/\A\d+\z/)
76
+
64
77
  title = extract_title(node)
65
78
 
66
79
  if Coradoc::ReverseAdoc.config.external_images
@@ -73,21 +86,20 @@ module Coradoc::ReverseAdoc
73
86
  if alt # && !alt.to_s.empty?
74
87
  attributes.add_positional(alt)
75
88
  elsif width || height
76
- attributes.add_positional("\"\"")
89
+ attributes.add_positional(nil)
77
90
  end
78
- # attributes.add_named("title", title) if title
91
+ attributes.add_named("title", title) if title && !title.empty?
79
92
  attributes.add_positional(width) if width
80
93
  attributes.add_positional(height) if height
81
94
 
82
- Coradoc::Element::Image::BlockImage.new(title, id, src,
83
- attributes: attributes)
84
- end
85
-
86
- def convert(node, state = {})
87
- Coradoc::Generator.gen_adoc(to_coradoc(node, state))
95
+ if src
96
+ Coradoc::Element::Image::BlockImage.new(title, id, src,
97
+ attributes: attributes,
98
+ annotate_missing: @annotate_missing)
99
+ end
88
100
  end
89
101
  end
90
102
 
91
- register :img, Img.new
103
+ register :img, Img
92
104
  end
93
105
  end
@@ -6,10 +6,6 @@ module Coradoc::ReverseAdoc
6
6
  content = treat_children_coradoc(node, state)
7
7
  Coradoc::Element::ListItem.new(content, id: id)
8
8
  end
9
-
10
- def convert(node, state = {})
11
- Coradoc::Generator.gen_adoc(to_coradoc(node, state))
12
- end
13
9
  end
14
10
 
15
11
  register :li, Li.new
@@ -1,18 +1,12 @@
1
1
  module Coradoc::ReverseAdoc
2
2
  module Converters
3
- class Mark < Base
4
- def to_coradoc(node, state = {})
5
- content = treat_children(node, state.merge(already_strong: true))
6
-
7
- if content.strip.empty? || state[:already_strong]
8
- return content
9
- end
10
-
11
- Coradoc::Element::Inline::Highlight.new(content, constrained?(node))
3
+ class Mark < Markup
4
+ def coradoc_class
5
+ Coradoc::Element::Inline::Highlight
12
6
  end
13
7
 
14
- def convert(node, state = {})
15
- Coradoc::Generator.gen_adoc(to_coradoc(node, state))
8
+ def markup_ancestor_tag_names
9
+ %w[mark]
16
10
  end
17
11
  end
18
12
 
@@ -0,0 +1,27 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Markup < Base
4
+ def to_coradoc(node, state = {})
5
+ u_before = unconstrained_before?(node)
6
+ u_after = unconstrained_after?(node)
7
+
8
+ leading_whitespace, trailing_whitespace =
9
+ extract_leading_trailing_whitespace(node)
10
+
11
+ content = treat_children_coradoc(node, state)
12
+
13
+ if node_has_ancestor?(node, markup_ancestor_tag_names)
14
+ content
15
+ elsif node.children.empty?
16
+ leading_whitespace.to_s
17
+ else
18
+ u = (u_before && leading_whitespace.nil?) ||
19
+ (u_after && trailing_whitespace.nil?)
20
+
21
+ e = coradoc_class.new(content, unconstrained: u)
22
+ [leading_whitespace, e, trailing_whitespace]
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -23,10 +23,6 @@ module Coradoc::ReverseAdoc
23
23
  end
24
24
  end
25
25
 
26
- def convert(node, state = {})
27
- Coradoc::Generator.gen_adoc(to_coradoc(node, state))
28
- end
29
-
30
26
  def get_list_type(node, _state)
31
27
  case node.name
32
28
  when "ol"
@@ -12,10 +12,6 @@ module Coradoc::ReverseAdoc
12
12
 
13
13
  Coradoc::Element::Paragraph.new(content, options)
14
14
  end
15
-
16
- def convert(node, state = {})
17
- Coradoc::Generator.gen_adoc(to_coradoc(node, state))
18
- end
19
15
  end
20
16
 
21
17
  register :p, P.new
@@ -22,10 +22,6 @@ module Coradoc::ReverseAdoc
22
22
  )
23
23
  end
24
24
 
25
- def convert(node, state = {})
26
- Coradoc::Generator.gen_adoc(to_coradoc(node, state))
27
- end
28
-
29
25
  private
30
26
 
31
27
  def treat(node, _state)
@@ -5,10 +5,6 @@ module Coradoc::ReverseAdoc
5
5
  content = treat_children(node, state)
6
6
  Coradoc::Element::Inline::Quotation.new(content)
7
7
  end
8
-
9
- def convert(node, state = {})
10
- Coradoc::Generator.gen_adoc(to_coradoc(node, state))
11
- end
12
8
  end
13
9
 
14
10
  register :q, Q.new
@@ -1,48 +1,12 @@
1
1
  module Coradoc::ReverseAdoc
2
2
  module Converters
3
- class Strong < Base
4
- def to_coradoc(node, state = {})
5
- content = treat_children_coradoc(node,
6
- state.merge(already_strong: true))
7
-
8
- if Coradoc::Generator.gen_adoc(content).strip.empty?
9
- return ""
10
- end
11
-
12
- if node_has_ancestor?(node, ["strong", "b"])
13
- return content
14
- end
15
-
16
- u_before = unconstrained_before?(node)
17
- u_after = unconstrained_after?(node)
18
- node.text =~ /^(\s+)/
19
- leading_whitespace = $1
20
- has_leading_whitespace = !leading_whitespace.nil?
21
-
22
- if has_leading_whitespace
23
- first_text = node.at_xpath("./text()[1]")
24
- first_text.replace(first_text.text.lstrip)
25
- leading_whitespace = u_before ? " " : " " # ########################33 somethings wrong in here
26
- end
27
-
28
- node.text =~ /(\s+)$/
29
- trailing_whitespace = $1
30
- has_trailing_whitespace = !trailing_whitespace.nil?
31
-
32
- if has_trailing_whitespace
33
- last_text = node.at_xpath("./text()[last()]")
34
- last_text.replace(last_text.text.rstrip)
35
- trailing_whitespace = u_after ? "" : "" ###############################
36
- end
37
-
38
- u = !((!u_before || has_leading_whitespace) && (!u_after || has_trailing_whitespace))
39
- e = Coradoc::Element::Inline::Bold.new(content, u)
40
-
41
- [leading_whitespace, e, trailing_whitespace]
3
+ class Strong < Markup
4
+ def coradoc_class
5
+ Coradoc::Element::Inline::Bold
42
6
  end
43
7
 
44
- def convert(node, state = {})
45
- Coradoc::Generator.gen_adoc(to_coradoc(node, state))
8
+ def markup_ancestor_tag_names
9
+ %w[strong b]
46
10
  end
47
11
  end
48
12
 
@@ -2,12 +2,14 @@ module Coradoc::ReverseAdoc
2
2
  module Converters
3
3
  class Sub < Base
4
4
  def to_coradoc(node, state = {})
5
+ leading_whitespace, trailing_whitespace = extract_leading_trailing_whitespace(node)
6
+
5
7
  content = treat_children_coradoc(node, state)
6
- Coradoc::Element::Inline::Subscript.new(content)
7
- end
8
8
 
9
- def convert(node, state = {})
10
- Coradoc::Generator.gen_adoc(to_coradoc(node, state))
9
+ return content if Coradoc::Generator.gen_adoc(content).strip.empty?
10
+
11
+ e = Coradoc::Element::Inline::Subscript.new(content)
12
+ [leading_whitespace, e, trailing_whitespace]
11
13
  end
12
14
  end
13
15
 
@@ -2,12 +2,14 @@ module Coradoc::ReverseAdoc
2
2
  module Converters
3
3
  class Sup < Base
4
4
  def to_coradoc(node, state = {})
5
- content = treat_children(node, state)
6
- Coradoc::Element::Inline::Superscript.new(content)
7
- end
5
+ leading_whitespace, trailing_whitespace = extract_leading_trailing_whitespace(node)
6
+
7
+ content = treat_children_coradoc(node, state)
8
+
9
+ return content if Coradoc::Generator.gen_adoc(content).strip.empty?
8
10
 
9
- def convert(node, state = {})
10
- Coradoc::Generator.gen_adoc(to_coradoc(node, state))
11
+ e = Coradoc::Element::Inline::Superscript.new(content)
12
+ [leading_whitespace, e, trailing_whitespace]
11
13
  end
12
14
  end
13
15
 
@@ -9,10 +9,6 @@ module Coradoc::ReverseAdoc
9
9
  Coradoc::Element::Table.new(title, content, { id: id, attrs: attrs })
10
10
  end
11
11
 
12
- def convert(node, state = {})
13
- Coradoc::Generator.gen_adoc(to_coradoc(node, state))
14
- end
15
-
16
12
  def extract_title(node)
17
13
  title = node.at("./caption")
18
14
  return "" if title.nil?
@@ -57,11 +53,251 @@ module Coradoc::ReverseAdoc
57
53
  rules_attr = rules(node)
58
54
  attrs.add_named("rules", rules_attr) if rules_attr
59
55
 
56
+ # We can't, and shouldn't do those calculation if the table we are
57
+ # processing is empty.
58
+ unless empty?(node)
59
+ cols = ensure_row_column_integrity_and_get_column_sizes(node)
60
+ attrs.add_named("cols", cols)
61
+
62
+ # Header first rows can't span multiple riws - drop header if they do.
63
+ header = node.at_xpath(".//tr")
64
+ unless header.xpath("./td | ./th").all? { |i| [nil, "1", ""].include? i["rowspan"] }
65
+ attrs.add_named("options", ["noheader"])
66
+ end
67
+ end
68
+
60
69
  # This line should be removed.
61
70
  return "" if attrs.empty?
62
71
 
63
72
  attrs
64
73
  end
74
+
75
+ def empty?(node)
76
+ !node.at_xpath(".//td | .//th")
77
+ end
78
+
79
+ def ensure_row_column_integrity_and_get_column_sizes(node)
80
+ rows = node.xpath(".//tr")
81
+ num_rows = rows.length
82
+ computed_columns_per_row = [0] * num_rows
83
+ # Both those variables may seem the same, but they have a crucial
84
+ # difference.
85
+ #
86
+ # cell_references don't necessarily contain an image of created
87
+ # table. New cells are pushed to it as needed, so if we have a
88
+ # one cell with colspan and rowspan of 2 on the previous row,
89
+ # those will always be first in the row, regardless of their
90
+ # position. This array is only used to warrant the table
91
+ # integrity.
92
+ #
93
+ # cell_matrix, on the other hand, can't be constructed outright.
94
+ # It will be incorrect as long as the table isn't fixed. So we
95
+ # can't use it to correct colspans/rowspans/missing rows. Once
96
+ # we have it constructed, only then we can calculate the correct
97
+ # column widths.
98
+ cell_references = [nil] * num_rows
99
+ cell_matrix = [nil] * num_rows
100
+
101
+ recompute = proc do
102
+ return ensure_row_column_integrity_and_get_column_sizes(node)
103
+ end
104
+
105
+ fits_in_cell_matrix = proc do |y,x,rowspan,colspan|
106
+ rowspan.times.all? do |yy|
107
+ colspan.times.all? do |xx|
108
+ !cell_matrix.dig(y+yy, x+xx)
109
+ end
110
+ end
111
+ end
112
+
113
+ rows.each_with_index do |row, i|
114
+ columns = row.xpath("./td | ./th")
115
+ column_id = 0
116
+
117
+ columns.each do |cell|
118
+ colspan = cell["colspan"]&.to_i || 1
119
+ rowspan = cell["rowspan"]&.to_i || 1
120
+
121
+ column_id += 1 until fits_in_cell_matrix.(i,column_id,rowspan,colspan)
122
+
123
+ rowspan.times do |j|
124
+ # Let's increase the table for particularly bad documents
125
+ computed_columns_per_row[i + j] ||= 0
126
+ computed_columns_per_row[i + j] += colspan
127
+
128
+ cell_references[i + j] ||= []
129
+ cell_matrix[i + j] ||= []
130
+ colspan.times do |k|
131
+ cell_references[i + j] << [cell, k > 0]
132
+ cell_matrix[i + j][column_id] = cell
133
+ column_id += 1
134
+ end
135
+ column_id -= colspan
136
+ end
137
+ column_id += colspan
138
+ end
139
+ end
140
+
141
+ ##### Fixups
142
+ cpr = computed_columns_per_row
143
+
144
+ # Some cell has too high colspan
145
+ if cpr.length > num_rows
146
+ cell_references[num_rows].each do |cell,|
147
+ next unless cell
148
+
149
+ cell["rowspan"] = cell["rowspan"].to_i - 1
150
+ end
151
+
152
+ # Let's recompute the numbers
153
+ recompute.()
154
+ end
155
+
156
+ if [cpr.first] * num_rows != cpr
157
+ # Colspan inconsistencies
158
+ modified = false
159
+ cpr_max = cpr.max
160
+ max_rows = cell_references.sort_by(&:length).reverse
161
+ max_rows.each do |row|
162
+ break if row.length != cpr_max
163
+
164
+ cell, spanning = row.last
165
+
166
+ if spanning
167
+ modified = true
168
+ cell["colspan"] = cell["colspan"].to_i - 1
169
+ end
170
+ end
171
+
172
+ recompute.() if modified
173
+
174
+ # We are out of colspans to fix. If we are at this point, this
175
+ # means there is an inconsistent number of TH/TDs simply.
176
+ # Here, the solution is to add empty TDs.
177
+ min_rows = cell_references.sort_by(&:length)
178
+ cpr_min = cpr.min
179
+ min_rows.each do |row|
180
+ break if row.length != cpr_min
181
+
182
+ row_obj = row.last.first.parent
183
+ doc = row_obj.document
184
+ added_node = Nokogiri::XML::Node.new("td", doc)
185
+ added_node["x-added"] = "x-added"
186
+ row_obj.add_child(added_node)
187
+
188
+ modified = true
189
+ end
190
+
191
+ recompute.() if modified
192
+
193
+ ### We should have a correct document now and we should never
194
+ ### end up here.
195
+ warn "**** Couldn't fix table sizes for table on line #{node.line}"
196
+ end
197
+
198
+ # For column size computation, we must have an integral cell_matrix.
199
+ # Let's verify that all columns and rows are populated.
200
+ cell_matrix_correct = cell_matrix.length.times.all? do |y|
201
+ cell_matrix[y].length.times.all? do |x|
202
+ cell_matrix[y][x]
203
+ end
204
+ end
205
+
206
+ unless cell_matrix_correct
207
+ # It may be a special case that we need to add virtual cells at the
208
+ # beginning not the end of a row.
209
+ needs_recompute = false
210
+ cell_matrix.each do |row|
211
+ if row.compact.length != row.length
212
+ last_cell = row.last
213
+ if last_cell["x-added"]
214
+ last_cell.parent.prepend_child(last_cell)
215
+ needs_recompute = true
216
+ end
217
+ end
218
+ end
219
+ recompute.() if needs_recompute
220
+
221
+ # But otherwise... we've got a really nasty table.
222
+ warn <<~WARNING.gsub("\n", " ")
223
+ **** Couldn't construct a valid image of a table on line
224
+ #{node.line}. We need that to reliably compute column
225
+ widths of that table. Please report a bug to metanorma/coradoc
226
+ repository.
227
+ WARNING
228
+ end
229
+
230
+ # Compute column sizes
231
+ column_sizes = []
232
+ cell_matrix.each do |row|
233
+ row.each_with_index do |(cell,_), i|
234
+ next unless !cell || [nil, "", "1"].include?(cell["colspan"])
235
+
236
+ column_sizes[i] ||= []
237
+ column_sizes[i] << cell["width"]
238
+ end
239
+ end
240
+
241
+ document_width = Coradoc::ReverseAdoc.config.doc_width.to_r
242
+
243
+ column_sizes += [nil] * (cpr.first - column_sizes.length)
244
+
245
+ sizes = column_sizes.map do |col|
246
+ col = [] if col.nil?
247
+
248
+ max = col.map do |i|
249
+ if i.nil?
250
+ 0r
251
+ elsif i.end_with?("%")
252
+ document_width * i.to_i / 100
253
+ else
254
+ i.to_r
255
+ end
256
+ end.max
257
+
258
+ if max.nil? || max.negative?
259
+ 0r
260
+ else
261
+ max
262
+ end
263
+ end
264
+
265
+ # The table seems bigger than the document... let's scale all
266
+ # values.
267
+ while sizes.map { |i|
268
+ i.zero? ? document_width / 3 / sizes.length : i
269
+ }.sum > document_width
270
+
271
+ sizes = sizes.map { |i| i * 4 / 5 }
272
+ end
273
+
274
+ rest = document_width - sizes.sum
275
+ unset = sizes.count(&:zero?)
276
+
277
+ # Fill in zeros with remainder space
278
+ sizes = sizes.map do |i|
279
+ if i.zero?
280
+ rest / unset
281
+ else
282
+ i
283
+ end
284
+ end
285
+
286
+ # Scale to integers
287
+ lcm = sizes.map(&:denominator).inject(1) { |i,j| i.lcm(j) }
288
+ sizes = sizes.map { |i| i * lcm }.map(&:to_i)
289
+
290
+ # Scale down by gcd
291
+ gcd = sizes.inject(sizes.first) { |i,j| i.gcd(j) }
292
+ sizes = sizes.map { |i| i / gcd }
293
+
294
+ # Try to generate a shorter definition
295
+ if [sizes.first] * sizes.length == sizes
296
+ sizes.length
297
+ else
298
+ sizes.join(",")
299
+ end
300
+ end
65
301
  end
66
302
 
67
303
  register :table, Table.new
@@ -11,11 +11,10 @@ module Coradoc::ReverseAdoc
11
11
  singlepara = node.elements.size == 1 && node.elements.first.name == "p"
12
12
  state[:tdsinglepara] = singlepara if singlepara
13
13
 
14
- adoccell = node.at(".//ul | .//ol | .//pre | .//blockquote | .//br | .//hr") ||
14
+ adoccell = node.at(".//ul | .//ol | .//pre | .//blockquote | .//br | .//hr | .//img[@src]") ||
15
15
  node.at(".//p") && !singlepara
16
16
 
17
17
  style = "a" if adoccell
18
- delim = adoccell ? "\n" : " "
19
18
  content = treat_children_coradoc(node, state)
20
19
  options = {}.tap do |hash|
21
20
  hash[:id] = id
@@ -23,16 +22,11 @@ module Coradoc::ReverseAdoc
23
22
  hash[:alignattr] = alignattr
24
23
  hash[:style] = style
25
24
  hash[:content] = content
26
- hash[:delim] = delim
27
25
  end
28
26
 
29
27
  Coradoc::Element::Table::Cell.new(options)
30
28
  end
31
29
 
32
- def convert(node, state = {})
33
- Coradoc::Generator.gen_adoc(to_coradoc(node, state))
34
- end
35
-
36
30
  def cellstyle(_node)
37
31
  ""
38
32
  end