coradoc 0.3.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.
- checksums.yaml +4 -4
- data/README.md +4 -0
- data/exe/reverse_adoc +24 -3
- data/lib/coradoc/document.rb +1 -0
- data/lib/coradoc/element/admonition.rb +2 -2
- data/lib/coradoc/element/attribute.rb +2 -2
- data/lib/coradoc/element/attribute_list.rb +94 -15
- data/lib/coradoc/element/audio.rb +13 -2
- data/lib/coradoc/element/author.rb +4 -2
- data/lib/coradoc/element/base.rb +70 -7
- data/lib/coradoc/element/block/core.rb +8 -4
- data/lib/coradoc/element/block/quote.rb +1 -1
- data/lib/coradoc/element/break.rb +1 -1
- data/lib/coradoc/element/document_attributes.rb +6 -6
- data/lib/coradoc/element/header.rb +4 -2
- data/lib/coradoc/element/image/block_image.rb +13 -2
- data/lib/coradoc/element/image/core.rb +34 -5
- data/lib/coradoc/element/image/inline_image.rb +2 -2
- data/lib/coradoc/element/inline/anchor.rb +4 -2
- data/lib/coradoc/element/inline/bold.rb +9 -4
- data/lib/coradoc/element/inline/cross_reference.rb +4 -2
- data/lib/coradoc/element/inline/hard_line_break.rb +1 -1
- data/lib/coradoc/element/inline/highlight.rb +11 -6
- data/lib/coradoc/element/inline/italic.rb +9 -4
- data/lib/coradoc/element/inline/link.rb +22 -6
- data/lib/coradoc/element/inline/monospace.rb +9 -4
- data/lib/coradoc/element/inline/quotation.rb +3 -1
- data/lib/coradoc/element/inline/subscript.rb +4 -2
- data/lib/coradoc/element/inline/superscript.rb +4 -2
- data/lib/coradoc/element/list/core.rb +9 -6
- data/lib/coradoc/element/list/definition.rb +19 -0
- data/lib/coradoc/element/list/ordered.rb +1 -1
- data/lib/coradoc/element/list/unordered.rb +1 -1
- data/lib/coradoc/element/list.rb +1 -0
- data/lib/coradoc/element/list_item.rb +8 -3
- data/lib/coradoc/element/list_item_definition.rb +32 -0
- data/lib/coradoc/element/paragraph.rb +4 -2
- data/lib/coradoc/element/revision.rb +4 -2
- data/lib/coradoc/element/section.rb +21 -4
- data/lib/coradoc/element/table.rb +27 -10
- data/lib/coradoc/element/text_element.rb +48 -8
- data/lib/coradoc/element/title.rb +26 -6
- data/lib/coradoc/element/video.rb +32 -5
- data/lib/coradoc/reverse_adoc/README.adoc +14 -8
- data/lib/coradoc/reverse_adoc/cleaner.rb +20 -8
- data/lib/coradoc/reverse_adoc/config.rb +35 -16
- data/lib/coradoc/reverse_adoc/converters/a.rb +17 -12
- data/lib/coradoc/reverse_adoc/converters/aside.rb +0 -4
- data/lib/coradoc/reverse_adoc/converters/audio.rb +0 -4
- data/lib/coradoc/reverse_adoc/converters/base.rb +48 -44
- data/lib/coradoc/reverse_adoc/converters/blockquote.rb +2 -11
- data/lib/coradoc/reverse_adoc/converters/br.rb +0 -4
- data/lib/coradoc/reverse_adoc/converters/bypass.rb +0 -4
- data/lib/coradoc/reverse_adoc/converters/code.rb +5 -42
- data/lib/coradoc/reverse_adoc/converters/div.rb +0 -4
- data/lib/coradoc/reverse_adoc/converters/dl.rb +55 -0
- data/lib/coradoc/reverse_adoc/converters/em.rb +5 -43
- data/lib/coradoc/reverse_adoc/converters/figure.rb +0 -4
- data/lib/coradoc/reverse_adoc/converters/h.rb +0 -4
- data/lib/coradoc/reverse_adoc/converters/head.rb +0 -4
- data/lib/coradoc/reverse_adoc/converters/hr.rb +0 -4
- data/lib/coradoc/reverse_adoc/converters/img.rb +21 -16
- data/lib/coradoc/reverse_adoc/converters/li.rb +0 -4
- data/lib/coradoc/reverse_adoc/converters/mark.rb +5 -11
- data/lib/coradoc/reverse_adoc/converters/markup.rb +27 -0
- data/lib/coradoc/reverse_adoc/converters/ol.rb +0 -4
- data/lib/coradoc/reverse_adoc/converters/p.rb +0 -4
- data/lib/coradoc/reverse_adoc/converters/pre.rb +0 -4
- data/lib/coradoc/reverse_adoc/converters/q.rb +0 -4
- data/lib/coradoc/reverse_adoc/converters/strong.rb +5 -41
- data/lib/coradoc/reverse_adoc/converters/sub.rb +6 -4
- data/lib/coradoc/reverse_adoc/converters/sup.rb +7 -5
- data/lib/coradoc/reverse_adoc/converters/table.rb +215 -4
- data/lib/coradoc/reverse_adoc/converters/td.rb +1 -7
- data/lib/coradoc/reverse_adoc/converters/text.rb +1 -38
- data/lib/coradoc/reverse_adoc/converters/tr.rb +0 -4
- data/lib/coradoc/reverse_adoc/converters/video.rb +0 -4
- data/lib/coradoc/reverse_adoc/converters.rb +21 -0
- data/lib/coradoc/reverse_adoc/html_converter.rb +109 -20
- data/lib/coradoc/reverse_adoc/plugin.rb +131 -0
- data/lib/coradoc/reverse_adoc/plugins/plateau.rb +174 -0
- data/lib/coradoc/reverse_adoc/postprocessor.rb +148 -0
- data/lib/coradoc/reverse_adoc.rb +3 -0
- data/lib/coradoc/version.rb +1 -1
- data/lib/reverse_adoc.rb +1 -1
- metadata +8 -3
- data/lib/coradoc/element/inline/image.rb +0 -26
|
@@ -19,13 +19,15 @@ 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}"
|
|
@@ -35,6 +37,8 @@ module Coradoc::ReverseAdoc
|
|
|
35
37
|
image_number_increment
|
|
36
38
|
|
|
37
39
|
image_dest_path.relative_path_from(dest_dir)
|
|
40
|
+
ensure
|
|
41
|
+
tempfile&.close!
|
|
38
42
|
end
|
|
39
43
|
|
|
40
44
|
def determine_image_src_path(src, imgdata)
|
|
@@ -45,13 +49,13 @@ module Coradoc::ReverseAdoc
|
|
|
45
49
|
end
|
|
46
50
|
|
|
47
51
|
def copy_temp_file(imgdata)
|
|
48
|
-
Tempfile.open(["radoc", ".jpg"])
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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]
|
|
55
59
|
end
|
|
56
60
|
|
|
57
61
|
def to_coradoc(node, _state = {})
|
|
@@ -61,6 +65,9 @@ module Coradoc::ReverseAdoc
|
|
|
61
65
|
width = node["width"]
|
|
62
66
|
height = node["height"]
|
|
63
67
|
|
|
68
|
+
width = width.to_i if width&.match?(/\A\d+\z/)
|
|
69
|
+
height = height.to_i if height&.match?(/\A\d+\z/)
|
|
70
|
+
|
|
64
71
|
title = extract_title(node)
|
|
65
72
|
|
|
66
73
|
if Coradoc::ReverseAdoc.config.external_images
|
|
@@ -73,18 +80,16 @@ module Coradoc::ReverseAdoc
|
|
|
73
80
|
if alt # && !alt.to_s.empty?
|
|
74
81
|
attributes.add_positional(alt)
|
|
75
82
|
elsif width || height
|
|
76
|
-
attributes.add_positional(
|
|
83
|
+
attributes.add_positional(nil)
|
|
77
84
|
end
|
|
78
|
-
|
|
85
|
+
attributes.add_named("title", title) if title && !title.empty?
|
|
79
86
|
attributes.add_positional(width) if width
|
|
80
87
|
attributes.add_positional(height) if height
|
|
81
88
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def convert(node, state = {})
|
|
87
|
-
Coradoc::Generator.gen_adoc(to_coradoc(node, state))
|
|
89
|
+
if src
|
|
90
|
+
Coradoc::Element::Image::BlockImage.new(title, id, src,
|
|
91
|
+
attributes: attributes)
|
|
92
|
+
end
|
|
88
93
|
end
|
|
89
94
|
end
|
|
90
95
|
|
|
@@ -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 <
|
|
4
|
-
def
|
|
5
|
-
|
|
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
|
|
15
|
-
|
|
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
|
|
@@ -1,48 +1,12 @@
|
|
|
1
1
|
module Coradoc::ReverseAdoc
|
|
2
2
|
module Converters
|
|
3
|
-
class Strong <
|
|
4
|
-
def
|
|
5
|
-
|
|
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
|
|
45
|
-
|
|
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
|
-
|
|
10
|
-
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
10
|
-
|
|
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,226 @@ module Coradoc::ReverseAdoc
|
|
|
57
53
|
rules_attr = rules(node)
|
|
58
54
|
attrs.add_named("rules", rules_attr) if rules_attr
|
|
59
55
|
|
|
56
|
+
cols = ensure_row_column_integrity_and_get_column_sizes(node)
|
|
57
|
+
attrs.add_named("cols", cols)
|
|
58
|
+
|
|
59
|
+
# Header first rows can't span multiple riws - drop header if they do.
|
|
60
|
+
header = node.at_xpath(".//tr")
|
|
61
|
+
unless header.xpath("./td | ./th").all? { |i| [nil, "1", ""].include? i["rowspan"] }
|
|
62
|
+
attrs.add_named("options", ["noheader"])
|
|
63
|
+
end
|
|
64
|
+
|
|
60
65
|
# This line should be removed.
|
|
61
66
|
return "" if attrs.empty?
|
|
62
67
|
|
|
63
68
|
attrs
|
|
64
69
|
end
|
|
70
|
+
|
|
71
|
+
def ensure_row_column_integrity_and_get_column_sizes(node)
|
|
72
|
+
rows = node.xpath(".//tr")
|
|
73
|
+
num_rows = rows.length
|
|
74
|
+
computed_columns_per_row = [0] * num_rows
|
|
75
|
+
# Both those variables may seem the same, but they have a crucial
|
|
76
|
+
# difference.
|
|
77
|
+
#
|
|
78
|
+
# cell_references don't necessarily contain an image of created
|
|
79
|
+
# table. New cells are pushed to it as needed, so if we have a
|
|
80
|
+
# one cell with colspan and rowspan of 2 on the previous row,
|
|
81
|
+
# those will always be first in the row, regardless of their
|
|
82
|
+
# position. This array is only used to warrant the table
|
|
83
|
+
# integrity.
|
|
84
|
+
#
|
|
85
|
+
# cell_matrix, on the other hand, can't be constructed outright.
|
|
86
|
+
# It will be incorrect as long as the table isn't fixed. So we
|
|
87
|
+
# can't use it to correct colspans/rowspans/missing rows. Once
|
|
88
|
+
# we have it constructed, only then we can calculate the correct
|
|
89
|
+
# column widths.
|
|
90
|
+
cell_references = [nil] * num_rows
|
|
91
|
+
cell_matrix = [nil] * num_rows
|
|
92
|
+
|
|
93
|
+
recompute = proc do
|
|
94
|
+
return ensure_row_column_integrity_and_get_column_sizes(node)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
fits_in_cell_matrix = proc do |y,x,rowspan,colspan|
|
|
98
|
+
rowspan.times.all? do |yy|
|
|
99
|
+
colspan.times.all? do |xx|
|
|
100
|
+
!cell_matrix.dig(y+yy, x+xx)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
rows.each_with_index do |row, i|
|
|
106
|
+
columns = row.xpath("./td | ./th")
|
|
107
|
+
column_id = 0
|
|
108
|
+
|
|
109
|
+
columns.each do |cell|
|
|
110
|
+
colspan = cell["colspan"]&.to_i || 1
|
|
111
|
+
rowspan = cell["rowspan"]&.to_i || 1
|
|
112
|
+
|
|
113
|
+
column_id += 1 until fits_in_cell_matrix.(i,column_id,rowspan,colspan)
|
|
114
|
+
|
|
115
|
+
rowspan.times do |j|
|
|
116
|
+
# Let's increase the table for particularly bad documents
|
|
117
|
+
computed_columns_per_row[i + j] ||= 0
|
|
118
|
+
computed_columns_per_row[i + j] += colspan
|
|
119
|
+
|
|
120
|
+
cell_references[i + j] ||= []
|
|
121
|
+
cell_matrix[i + j] ||= []
|
|
122
|
+
colspan.times do |k|
|
|
123
|
+
cell_references[i + j] << [cell, k > 0]
|
|
124
|
+
cell_matrix[i + j][column_id] = cell
|
|
125
|
+
column_id += 1
|
|
126
|
+
end
|
|
127
|
+
column_id -= colspan
|
|
128
|
+
end
|
|
129
|
+
column_id += colspan
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
##### Fixups
|
|
134
|
+
cpr = computed_columns_per_row
|
|
135
|
+
|
|
136
|
+
# Some cell has too high colspan
|
|
137
|
+
if cpr.length > num_rows
|
|
138
|
+
cell_references[num_rows].each do |cell,|
|
|
139
|
+
next unless cell
|
|
140
|
+
|
|
141
|
+
cell["rowspan"] = cell["rowspan"].to_i - 1
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Let's recompute the numbers
|
|
145
|
+
recompute.()
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
if [cpr.first] * num_rows != cpr
|
|
149
|
+
# Colspan inconsistencies
|
|
150
|
+
modified = false
|
|
151
|
+
cpr_max = cpr.max
|
|
152
|
+
max_rows = cell_references.sort_by(&:length).reverse
|
|
153
|
+
max_rows.each do |row|
|
|
154
|
+
break if row.length != cpr_max
|
|
155
|
+
|
|
156
|
+
cell, spanning = row.last
|
|
157
|
+
|
|
158
|
+
if spanning
|
|
159
|
+
modified = true
|
|
160
|
+
cell["colspan"] = cell["colspan"].to_i - 1
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
recompute.() if modified
|
|
165
|
+
|
|
166
|
+
# We are out of colspans to fix. If we are at this point, this
|
|
167
|
+
# means there is an inconsistent number of TH/TDs simply.
|
|
168
|
+
# Here, the solution is to add empty TDs.
|
|
169
|
+
min_rows = cell_references.sort_by(&:length)
|
|
170
|
+
cpr_min = cpr.min
|
|
171
|
+
min_rows.each do |row|
|
|
172
|
+
break if row.length != cpr_min
|
|
173
|
+
|
|
174
|
+
row_obj = row.last.first.parent
|
|
175
|
+
doc = row_obj.document
|
|
176
|
+
row_obj.add_child(Nokogiri::XML::Node.new("td", doc))
|
|
177
|
+
|
|
178
|
+
modified = true
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
recompute.() if modified
|
|
182
|
+
|
|
183
|
+
### We should have a correct document now and we should never
|
|
184
|
+
### end up here.
|
|
185
|
+
warn "**** Couldn't fix table sizes for table on line #{node.line}"
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# For column size computation, we must have an integral cell_matrix.
|
|
189
|
+
# Let's verify that all columns and rows are populated.
|
|
190
|
+
cell_matrix_correct = cell_matrix.length.times.all? do |y|
|
|
191
|
+
cell_matrix[y].length.times.all? do |x|
|
|
192
|
+
cell_matrix[y][x]
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
unless cell_matrix_correct
|
|
197
|
+
warn <<~WARNING.gsub("\n", " ")
|
|
198
|
+
**** Couldn't construct a valid image of a table on line
|
|
199
|
+
#{node.line}. We need that to reliably compute column
|
|
200
|
+
widths of that table. Please report a bug to metanorma/coradoc
|
|
201
|
+
repository.
|
|
202
|
+
WARNING
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Compute column sizes
|
|
206
|
+
column_sizes = []
|
|
207
|
+
cell_matrix.each do |row|
|
|
208
|
+
row.each_with_index do |(cell,_), i|
|
|
209
|
+
next unless !cell || [nil, "", "1"].include?(cell["colspan"])
|
|
210
|
+
|
|
211
|
+
column_sizes[i] ||= []
|
|
212
|
+
column_sizes[i] << cell["width"]
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
document_width = Coradoc::ReverseAdoc.config.doc_width.to_r
|
|
217
|
+
|
|
218
|
+
column_sizes += [nil] * (cpr.first - column_sizes.length)
|
|
219
|
+
|
|
220
|
+
sizes = column_sizes.map do |col|
|
|
221
|
+
col = [] if col.nil?
|
|
222
|
+
|
|
223
|
+
max = col.map do |i|
|
|
224
|
+
if i.nil?
|
|
225
|
+
0r
|
|
226
|
+
elsif i.end_with?("%")
|
|
227
|
+
document_width * i.to_i / 100
|
|
228
|
+
else
|
|
229
|
+
i.to_r
|
|
230
|
+
end
|
|
231
|
+
end.max
|
|
232
|
+
|
|
233
|
+
if max.nil? || max.negative?
|
|
234
|
+
0r
|
|
235
|
+
else
|
|
236
|
+
max
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# The table seems bigger than the document... let's scale all
|
|
241
|
+
# values.
|
|
242
|
+
while sizes.map { |i|
|
|
243
|
+
i.zero? ? document_width / 3 / sizes.length : i
|
|
244
|
+
}.sum > document_width
|
|
245
|
+
|
|
246
|
+
sizes = sizes.map { |i| i * 4 / 5 }
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
rest = document_width - sizes.sum
|
|
250
|
+
unset = sizes.count(&:zero?)
|
|
251
|
+
|
|
252
|
+
# Fill in zeros with remainder space
|
|
253
|
+
sizes = sizes.map do |i|
|
|
254
|
+
if i.zero?
|
|
255
|
+
rest / unset
|
|
256
|
+
else
|
|
257
|
+
i
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Scale to integers
|
|
262
|
+
lcm = sizes.map(&:denominator).inject(1) { |i,j| i.lcm(j) }
|
|
263
|
+
sizes = sizes.map { |i| i * lcm }.map(&:to_i)
|
|
264
|
+
|
|
265
|
+
# Scale down by gcd
|
|
266
|
+
gcd = sizes.inject(sizes.first) { |i,j| i.gcd(j) }
|
|
267
|
+
sizes = sizes.map { |i| i / gcd }
|
|
268
|
+
|
|
269
|
+
# Try to generate a shorter definition
|
|
270
|
+
if [sizes.first] * sizes.length == sizes
|
|
271
|
+
sizes.length
|
|
272
|
+
else
|
|
273
|
+
sizes.join(",")
|
|
274
|
+
end
|
|
275
|
+
end
|
|
65
276
|
end
|
|
66
277
|
|
|
67
278
|
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
|
|
@@ -4,11 +4,7 @@ module Coradoc::ReverseAdoc
|
|
|
4
4
|
def to_coradoc(node, state = {})
|
|
5
5
|
return treat_empty(node, state) if node.text.strip.empty?
|
|
6
6
|
|
|
7
|
-
Coradoc::Element::TextElement.new(
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def convert(node, state = {})
|
|
11
|
-
Coradoc::Generator.gen_adoc(to_coradoc(node, state))
|
|
7
|
+
Coradoc::Element::TextElement.new(node.text)
|
|
12
8
|
end
|
|
13
9
|
|
|
14
10
|
private
|
|
@@ -25,39 +21,6 @@ module Coradoc::ReverseAdoc
|
|
|
25
21
|
""
|
|
26
22
|
end
|
|
27
23
|
end
|
|
28
|
-
|
|
29
|
-
def treat_text(node)
|
|
30
|
-
text = node.text
|
|
31
|
-
text = preserve_nbsp(text)
|
|
32
|
-
text = remove_border_newlines(text)
|
|
33
|
-
text = remove_inner_newlines(text)
|
|
34
|
-
text = escape_keychars(text)
|
|
35
|
-
|
|
36
|
-
text = preserve_keychars_within_backticks(text)
|
|
37
|
-
escape_links(text)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def preserve_nbsp(text)
|
|
41
|
-
text.gsub(/\u00A0/, " ")
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def escape_links(text)
|
|
45
|
-
text.gsub(/<<([^>]*)>>/, "\\<<\\1>>")
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def remove_border_newlines(text)
|
|
49
|
-
text.gsub(/\A\n+/, "").gsub(/\n+\z/, "")
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def remove_inner_newlines(text)
|
|
53
|
-
text.tr("\n\t", " ").squeeze(" ")
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def preserve_keychars_within_backticks(text)
|
|
57
|
-
text.gsub(/`.*?`/) do |match|
|
|
58
|
-
match.gsub('\_', "_").gsub('\*', "*")
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
24
|
end
|
|
62
25
|
|
|
63
26
|
register :text, Text.new
|
|
@@ -7,10 +7,6 @@ module Coradoc::ReverseAdoc
|
|
|
7
7
|
Coradoc::Element::Table::Row.new(content, header)
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
def convert(node, state = {})
|
|
11
|
-
Coradoc::Generator.gen_adoc(to_coradoc(node, state))
|
|
12
|
-
end
|
|
13
|
-
|
|
14
10
|
def table_header_row?(node)
|
|
15
11
|
# node.element_children.all? {|child| child.name.to_sym == :th}
|
|
16
12
|
node.previous_element.nil?
|
|
@@ -13,6 +13,27 @@ module Coradoc::ReverseAdoc
|
|
|
13
13
|
@@converters[tag_name.to_sym] or default_converter(tag_name)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
# Note: process won't run plugin hooks
|
|
17
|
+
def self.process(node, state)
|
|
18
|
+
node = node.to_a if node.is_a? Nokogiri::XML::NodeSet
|
|
19
|
+
return node.map { |i| process(i, state) }.join if node.is_a? Array
|
|
20
|
+
|
|
21
|
+
lookup(node.name).convert(node, state)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.process_coradoc(node, state)
|
|
25
|
+
node = node.to_a if node.is_a? Nokogiri::XML::NodeSet
|
|
26
|
+
return node.map { |i| process_coradoc(i, state) } if node.is_a? Array
|
|
27
|
+
|
|
28
|
+
plugins = state[:plugin_instances] || {}
|
|
29
|
+
process = proc { lookup(node.name).to_coradoc(node, state) }
|
|
30
|
+
plugins.each do |i|
|
|
31
|
+
prev_process = process
|
|
32
|
+
process = proc { i.html_tree_run_hooks(node, state, &prev_process) }
|
|
33
|
+
end
|
|
34
|
+
process.(node, state)
|
|
35
|
+
end
|
|
36
|
+
|
|
16
37
|
def self.default_converter(tag_name)
|
|
17
38
|
case Coradoc::ReverseAdoc.config.unknown_tags.to_sym
|
|
18
39
|
when :pass_through
|