isodoc 1.7.4 → 1.7.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.
- checksums.yaml +4 -4
- data/isodoc.gemspec +7 -5
- data/lib/isodoc/class_utils.rb +25 -2
- data/lib/isodoc/convert.rb +2 -0
- data/lib/isodoc/function/to_word_html.rb +2 -1
- data/lib/isodoc/function/utils.rb +34 -14
- data/lib/isodoc/html_function/comments.rb +107 -111
- data/lib/isodoc/html_function/footnotes.rb +68 -67
- data/lib/isodoc/html_function/html.rb +113 -103
- data/lib/isodoc/presentation_function/block.rb +73 -78
- data/lib/isodoc/presentation_function/concept.rb +68 -0
- data/lib/isodoc/presentation_function/image.rb +112 -0
- data/lib/isodoc/presentation_function/inline.rb +20 -49
- data/lib/isodoc/presentation_xml_convert.rb +1 -0
- data/lib/isodoc/version.rb +1 -1
- data/lib/isodoc/word_function/body.rb +176 -174
- data/lib/isodoc/word_function/comments.rb +117 -112
- data/lib/isodoc/word_function/footnotes.rb +88 -86
- data/lib/isodoc/word_function/inline.rb +42 -67
- data/lib/isodoc/word_function/postprocess_cover.rb +121 -110
- data/lib/isodoc/xref/xref_gen.rb +153 -150
- data/lib/isodoc/xref/xref_sect_gen.rb +134 -129
- data/lib/isodoc/xslfo_convert.rb +7 -6
- data/spec/assets/i18n.yaml +3 -1
- data/spec/assets/odf.svg +1 -4
- data/spec/isodoc/blocks_spec.rb +229 -157
- data/spec/isodoc/i18n_spec.rb +3 -3
- data/spec/isodoc/inline_spec.rb +304 -105
- data/spec/isodoc/postproc_spec.rb +38 -0
- data/spec/isodoc/presentation_xml_spec.rb +60 -0
- data/spec/isodoc/section_spec.rb +125 -0
- data/spec/isodoc/terms_spec.rb +116 -0
- data/spec/isodoc/xslfo_convert_spec.rb +16 -4
- metadata +57 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5df030f2a89267d4acde57361f2c6338b29bf5928b5bb3c7b24a18903adf1531
|
4
|
+
data.tar.gz: 7e1923d7293b6b0703a15799e9bc3334637145adf8219c4230c63809267770cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24e8cf7a71167da62d5bdea85b009f982996e1513db82b42d6c01edf031b045dac7f9992a10e29946368df70dc32301e5edfa5937fad11e49e661edf8311058c
|
7
|
+
data.tar.gz: f61bb6a9b3833c0c4080c0804ae12869f15051ebec0f3fa6b3cc7d925b44de41559d472dde0ad737f54b02b040532a0a944e90a563fd1fcec4566965bda26fa4
|
data/isodoc.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
spec.email = ["open.source@ribose.com"]
|
12
12
|
|
13
13
|
spec.summary = "Convert documents in IsoDoc into Word and HTML "\
|
14
|
-
|
14
|
+
"in AsciiDoc."
|
15
15
|
spec.description = <<~DESCRIPTION
|
16
16
|
isodoc converts documents in the IsoDoc document model into
|
17
17
|
Microsoft Word and HTML.
|
@@ -32,25 +32,27 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.add_dependency "html2doc", "~> 1.1.1"
|
33
33
|
spec.add_dependency "htmlentities", "~> 4.3.4"
|
34
34
|
spec.add_dependency "liquid", "~> 4"
|
35
|
-
#spec.add_dependency "metanorma", ">= 1.2.0"
|
36
|
-
spec.add_dependency "
|
35
|
+
# spec.add_dependency "metanorma", ">= 1.2.0"
|
36
|
+
spec.add_dependency "emf2svg", "~> 1"
|
37
|
+
spec.add_dependency "mathml2asciimath"
|
38
|
+
spec.add_dependency "metanorma-utils"
|
39
|
+
spec.add_dependency "nokogiri", "~> 1.12.0"
|
37
40
|
spec.add_dependency "relaton-cli"
|
38
41
|
spec.add_dependency "roman-numerals"
|
39
42
|
spec.add_dependency "thread_safe"
|
40
43
|
spec.add_dependency "twitter_cldr", ">= 6.6.0"
|
41
44
|
spec.add_dependency "uuidtools"
|
42
|
-
spec.add_dependency "mathml2asciimath"
|
43
45
|
|
44
46
|
spec.add_development_dependency "byebug", "~> 9.1"
|
45
47
|
spec.add_development_dependency "equivalent-xml", "~> 0.6"
|
46
48
|
spec.add_development_dependency "guard", "~> 2.14"
|
47
49
|
spec.add_development_dependency "guard-rspec", "~> 4.7"
|
50
|
+
spec.add_development_dependency "metanorma-iso"
|
48
51
|
spec.add_development_dependency "rake", "~> 13.0"
|
49
52
|
spec.add_development_dependency "rexml"
|
50
53
|
spec.add_development_dependency "rspec", "~> 3.6"
|
51
54
|
spec.add_development_dependency "rubocop", "~> 1.5.2"
|
52
55
|
spec.add_development_dependency "sassc", "~> 2.4.0"
|
53
56
|
spec.add_development_dependency "simplecov", "~> 0.15"
|
54
|
-
spec.add_development_dependency "metanorma-iso"
|
55
57
|
spec.add_development_dependency "timecop", "~> 0.9"
|
56
58
|
end
|
data/lib/isodoc/class_utils.rb
CHANGED
@@ -23,9 +23,32 @@ module IsoDoc
|
|
23
23
|
# unescape HTML escapes in doc
|
24
24
|
doc = doc.split(%r<(\{%|%\})>).each_slice(4).map do |a|
|
25
25
|
a[2] = a[2].gsub("<", "<").gsub(">", ">") if a.size > 2
|
26
|
-
a.join
|
27
|
-
end.join
|
26
|
+
a.join
|
27
|
+
end.join
|
28
28
|
Liquid::Template.parse(doc)
|
29
29
|
end
|
30
|
+
|
31
|
+
def case_strict(text, casing, script)
|
32
|
+
return text unless %w(Latn Cyrl Grek Armn).include?(script)
|
33
|
+
|
34
|
+
letters = text.chars
|
35
|
+
case casing
|
36
|
+
when "capital" then letters.first.upcase!
|
37
|
+
when "lowercase" then letters.first.downcase!
|
38
|
+
end
|
39
|
+
letters.join
|
40
|
+
end
|
41
|
+
|
42
|
+
def case_with_markup(linkend, casing, script)
|
43
|
+
seen = false
|
44
|
+
xml = Nokogiri::XML("<root>#{linkend}</root>")
|
45
|
+
xml.traverse do |b|
|
46
|
+
next unless b.text? && !seen
|
47
|
+
|
48
|
+
b.replace(Common::case_strict(b.text, casing, script))
|
49
|
+
seen = true
|
50
|
+
end
|
51
|
+
xml.root.children.to_xml
|
52
|
+
end
|
30
53
|
end
|
31
54
|
end
|
data/lib/isodoc/convert.rb
CHANGED
@@ -101,6 +101,8 @@ module IsoDoc
|
|
101
101
|
@htmlToClevels = 2 if @htmlToClevels.zero?
|
102
102
|
@bookmarks_allocated = { "X" => true }
|
103
103
|
@fn_bookmarks = {}
|
104
|
+
@baseassetpath = options[:baseassetpath]
|
105
|
+
@aligncrosselements = options[:aligncrosselements]
|
104
106
|
end
|
105
107
|
|
106
108
|
def tmpimagedir_suffix
|
@@ -21,7 +21,8 @@ module IsoDoc
|
|
21
21
|
filename = filepath.sub_ext("").sub(/\.presentation$/, "").to_s
|
22
22
|
dir = init_dir(filename, debug)
|
23
23
|
@filename = filename
|
24
|
-
@localdir =
|
24
|
+
@localdir = @baseassetpath || filepath.parent.to_s
|
25
|
+
@localdir += "/"
|
25
26
|
@sourcedir = @localdir
|
26
27
|
@sourcefilename and
|
27
28
|
@sourcedir = "#{Pathname.new(@sourcefilename).parent}/"
|
@@ -37,14 +37,14 @@ module IsoDoc
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def attr_code(attributes)
|
40
|
-
attributes = attributes.
|
40
|
+
attributes = attributes.compact.map
|
41
41
|
attributes.map do |k, v|
|
42
42
|
[k, v.is_a?(String) ? HTMLEntities.new.decode(v) : v]
|
43
43
|
end.to_h
|
44
44
|
end
|
45
45
|
|
46
46
|
DOCTYPE_HDR = "<!DOCTYPE html SYSTEM "\
|
47
|
-
|
47
|
+
'"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
|
48
48
|
|
49
49
|
def to_xhtml(xml)
|
50
50
|
xml = to_xhtml_prep(xml)
|
@@ -55,7 +55,7 @@ module IsoDoc
|
|
55
55
|
f.write xml
|
56
56
|
end
|
57
57
|
abort "Malformed Output XML for #{@format}: #{e} "\
|
58
|
-
|
58
|
+
"(see #{@filename}.#{@format}.err)"
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
@@ -67,7 +67,7 @@ module IsoDoc
|
|
67
67
|
HTMLEntities.new.encode(HTMLEntities.new.decode(t), :hexadecimal)
|
68
68
|
else t
|
69
69
|
end
|
70
|
-
end.join
|
70
|
+
end.join
|
71
71
|
end
|
72
72
|
|
73
73
|
def to_xhtml_fragment(xml)
|
@@ -148,18 +148,12 @@ module IsoDoc
|
|
148
148
|
elem.name == "span" && /mso-bookmark/.match(elem["style"])
|
149
149
|
end
|
150
150
|
|
151
|
-
=begin
|
152
|
-
def liquid(doc)
|
153
|
-
self.class.liquid(doc)
|
154
|
-
end
|
155
|
-
=end
|
156
|
-
|
157
151
|
def liquid(doc)
|
158
152
|
# unescape HTML escapes in doc
|
159
153
|
doc = doc.split(%r<(\{%|%\})>).each_slice(4).map do |a|
|
160
154
|
a[2] = a[2].gsub(/</, "<").gsub(/>/, ">") if a.size > 2
|
161
|
-
a.join
|
162
|
-
end.join
|
155
|
+
a.join
|
156
|
+
end.join
|
163
157
|
Liquid::Template.parse(doc)
|
164
158
|
end
|
165
159
|
|
@@ -181,8 +175,9 @@ module IsoDoc
|
|
181
175
|
end
|
182
176
|
|
183
177
|
def save_dataimage(uri, _relative_dir = true)
|
184
|
-
%r{^data:(image|application)/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ uri
|
185
|
-
imgtype
|
178
|
+
%r{^data:(?<imgclass>image|application)/(?<imgtype>[^;]+);(charset=[^;]+;)?base64,(?<imgdata>.+)$} =~ uri
|
179
|
+
imgtype = "emf" if emf?("#{imgclass}/#{imgtype}")
|
180
|
+
imgtype = imgtype.sub(/\+[a-z0-9]+$/, "") # svg+xml
|
186
181
|
imgtype = "png" unless /^[a-z0-9]+$/.match? imgtype
|
187
182
|
Tempfile.open(["image", ".#{imgtype}"]) do |f|
|
188
183
|
f.binmode
|
@@ -206,6 +201,31 @@ module IsoDoc
|
|
206
201
|
!node.ancestors("example, requirement, recommendation, permission, "\
|
207
202
|
"note, table, figure, sourcecode").empty?
|
208
203
|
end
|
204
|
+
|
205
|
+
def emf?(type)
|
206
|
+
%w(application/emf application/x-emf image/x-emf image/x-mgx-emf
|
207
|
+
application/x-msmetafile image/x-xbitmap).include? type
|
208
|
+
end
|
209
|
+
|
210
|
+
def cleanup_entities(text)
|
211
|
+
c = HTMLEntities.new
|
212
|
+
text.split(/([<>])/).each_slice(4).map do |a|
|
213
|
+
a[0] = c.encode(c.decode(a[0]), :hexadecimal)
|
214
|
+
a[2] = c.encode(c.decode(a[2]), :hexadecimal) if a.size >= 3
|
215
|
+
a
|
216
|
+
end.join
|
217
|
+
end
|
218
|
+
|
219
|
+
def external_path(path)
|
220
|
+
win = !!((RUBY_PLATFORM =~ /(win|w)(32|64)$/) ||
|
221
|
+
(RUBY_PLATFORM =~ /mswin|mingw/))
|
222
|
+
if win
|
223
|
+
path.gsub!(%{/}, "\\")
|
224
|
+
path[/\s/] ? "\"#{path}\"" : path
|
225
|
+
else
|
226
|
+
path
|
227
|
+
end
|
228
|
+
end
|
209
229
|
end
|
210
230
|
end
|
211
231
|
end
|
@@ -1,146 +1,142 @@
|
|
1
|
-
module IsoDoc
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module IsoDoc
|
2
|
+
module HtmlFunction
|
3
|
+
module Comments
|
4
|
+
def in_comment
|
5
|
+
@in_comment
|
6
|
+
end
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
def comments(div)
|
9
|
+
# return if @comments.empty?
|
10
|
+
# div.div **{ style: "mso-element:comment-list" } do |div1|
|
11
|
+
# @comments.each { |fn| div1.parent << fn }
|
12
|
+
# end
|
13
13
|
end
|
14
|
-
=end
|
15
|
-
end
|
16
14
|
|
17
|
-
|
18
|
-
=
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
=end
|
25
|
-
end
|
15
|
+
def review_note_parse(node, out)
|
16
|
+
# fn = @comments.length + 1
|
17
|
+
# make_comment_link(out, fn, node)
|
18
|
+
# @in_comment = true
|
19
|
+
# @comments << make_comment_text(node, fn)
|
20
|
+
# @in_comment = false
|
21
|
+
end
|
26
22
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
23
|
+
def comment_link_attrs(fnote, node)
|
24
|
+
{ style: "MsoCommentReference", target: fnote,
|
25
|
+
class: "commentLink", from: node["from"],
|
26
|
+
to: node["to"] }
|
27
|
+
end
|
32
28
|
|
33
|
-
|
34
|
-
|
35
|
-
|
29
|
+
# add in from and to links to move the comment into place
|
30
|
+
def make_comment_link(out, fnote, node)
|
31
|
+
out.span(**comment_link_attrs(fnote, node)) do |s1|
|
36
32
|
s1.a **{ style: "mso-comment-reference:SMC_#{fnote};"\
|
37
|
-
|
33
|
+
"mso-comment-date:#{node['date'].gsub(/[-:Z]/,
|
34
|
+
'')}" }
|
38
35
|
end
|
39
|
-
|
36
|
+
end
|
40
37
|
|
41
|
-
|
42
|
-
|
38
|
+
def make_comment_target(out)
|
39
|
+
out.span **{ style: "MsoCommentReference" } do |s1|
|
43
40
|
s1.span **{ style: "mso-special-character:comment" }
|
44
41
|
end
|
45
|
-
|
42
|
+
end
|
46
43
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
44
|
+
def make_comment_text(node, fnote)
|
45
|
+
noko do |xml|
|
46
|
+
xml.div **{ style: "mso-element:comment", id: fnote } do |div|
|
47
|
+
div.span **{ style: %{mso-comment-author:"#{node['reviewer']}"} }
|
48
|
+
make_comment_target(div)
|
49
|
+
node.children.each { |n| parse(n, div) }
|
50
|
+
end
|
51
|
+
end.join("\n")
|
52
|
+
end
|
56
53
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
=end
|
63
|
-
end
|
54
|
+
def comment_cleanup(docxml)
|
55
|
+
# move_comment_link_to_from(docxml)
|
56
|
+
# reorder_comments_by_comment_link(docxml)
|
57
|
+
# embed_comment_in_comment_list(docxml)
|
58
|
+
end
|
64
59
|
|
65
|
-
|
66
|
-
|
67
|
-
|
60
|
+
COMMENT_IN_COMMENT_LIST =
|
61
|
+
'//div[@style="mso-element:comment-list"]//'\
|
62
|
+
'span[@style="MsoCommentReference"]'.freeze
|
68
63
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
64
|
+
def embed_comment_in_comment_list(docxml)
|
65
|
+
docxml.xpath(COMMENT_IN_COMMENT_LIST).each do |x|
|
66
|
+
n = x.next_element
|
67
|
+
n&.children&.first&.add_previous_sibling(x.remove)
|
68
|
+
end
|
69
|
+
docxml
|
73
70
|
end
|
74
|
-
docxml
|
75
|
-
end
|
76
71
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
72
|
+
def move_comment_link_to_from1(x, fromlink)
|
73
|
+
x.remove
|
74
|
+
link = x.at(".//a")
|
75
|
+
fromlink.replace(x)
|
76
|
+
link.children = fromlink
|
77
|
+
end
|
83
78
|
|
84
|
-
|
85
|
-
|
86
|
-
|
79
|
+
def comment_attributes(docxml, x)
|
80
|
+
fromlink = docxml.at("//*[@id='#{x['from']}']")
|
81
|
+
return(nil) if fromlink.nil?
|
87
82
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
83
|
+
tolink = docxml.at("//*[@id='#{x['to']}']") || fromlink
|
84
|
+
target = docxml.at("//*[@id='#{x['target']}']")
|
85
|
+
{ from: fromlink, to: tolink, target: target }
|
86
|
+
end
|
92
87
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
88
|
+
def wrap_comment_cont(from, target)
|
89
|
+
s = from.replace("<span style='mso-comment-continuation:#{target}'>")
|
90
|
+
s.first.children = from
|
91
|
+
end
|
97
92
|
|
98
|
-
|
99
|
-
|
100
|
-
|
93
|
+
def skip_comment_wrap(from)
|
94
|
+
from["style"] != "mso-special-character:comment"
|
95
|
+
end
|
101
96
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
(from = following.shift) && incl_to = from.at(".//*[@id='#{upto}']")
|
107
|
-
while !incl_to.nil? && !from.nil? && skip_comment_wrap(from)
|
97
|
+
def insert_comment_cont(from, upto, target)
|
98
|
+
# includes_to = from.at(".//*[@id='#{upto}']")
|
99
|
+
while !from.nil? && from["id"] != upto
|
100
|
+
following = from.xpath("./following::*")
|
108
101
|
(from = following.shift) && incl_to = from.at(".//*[@id='#{upto}']")
|
102
|
+
while !incl_to.nil? && !from.nil? && skip_comment_wrap(from)
|
103
|
+
(from = following.shift) && incl_to = from.at(".//*[@id='#{upto}']")
|
104
|
+
end
|
105
|
+
wrap_comment_cont(from, target) if !from.nil?
|
109
106
|
end
|
110
|
-
wrap_comment_cont(from, target) if !from.nil?
|
111
107
|
end
|
112
|
-
end
|
113
108
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
109
|
+
def move_comment_link_to_from(docxml)
|
110
|
+
docxml.xpath('//span[@style="MsoCommentReference"][@from]').each do |x|
|
111
|
+
attrs = comment_attributes(docxml, x) || next
|
112
|
+
move_comment_link_to_from1(x, attrs[:from])
|
113
|
+
insert_comment_cont(attrs[:from], x["to"], x["target"])
|
114
|
+
end
|
119
115
|
end
|
120
|
-
end
|
121
116
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
117
|
+
def get_comments_from_text(docxml, link_order)
|
118
|
+
comments = []
|
119
|
+
docxml.xpath("//div[@style='mso-element:comment']").each do |c|
|
120
|
+
next unless c["id"] && !link_order[c["id"]].nil?
|
126
121
|
|
127
|
-
|
122
|
+
comments << { text: c.remove.to_s, id: c["id"] }
|
123
|
+
end
|
124
|
+
comments.sort! { |a, b| link_order[a[:id]] <=> link_order[b[:id]] }
|
125
|
+
# comments
|
128
126
|
end
|
129
|
-
comments.sort! { |a, b| link_order[a[:id]] <=> link_order[b[:id]] }
|
130
|
-
# comments
|
131
|
-
end
|
132
127
|
|
133
|
-
|
134
|
-
|
128
|
+
COMMENT_TARGET_XREFS =
|
129
|
+
"//span[@style='mso-special-character:comment']/@target".freeze
|
135
130
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
131
|
+
def reorder_comments_by_comment_link(docxml)
|
132
|
+
link_order = {}
|
133
|
+
docxml.xpath(COMMENT_TARGET_XREFS).each_with_index do |target, i|
|
134
|
+
link_order[target.value] = i
|
135
|
+
end
|
136
|
+
comments = get_comments_from_text(docxml, link_order)
|
137
|
+
list = docxml.at("//*[@style='mso-element:comment-list']") || return
|
138
|
+
list.children = comments.map { |c| c[:text] }.join("\n")
|
140
139
|
end
|
141
|
-
comments = get_comments_from_text(docxml, link_order)
|
142
|
-
list = docxml.at("//*[@style='mso-element:comment-list']") || return
|
143
|
-
list.children = comments.map { |c| c[:text] }.join("\n")
|
144
140
|
end
|
145
141
|
end
|
146
142
|
end
|
@@ -1,90 +1,91 @@
|
|
1
|
-
module IsoDoc
|
2
|
-
module
|
1
|
+
module IsoDoc
|
2
|
+
module HtmlFunction
|
3
|
+
module Footnotes
|
4
|
+
def footnotes(div)
|
5
|
+
return if @footnotes.empty?
|
3
6
|
|
4
|
-
|
5
|
-
return if @footnotes.empty?
|
6
|
-
|
7
|
-
@footnotes.each { |fn| div.parent << fn }
|
8
|
-
end
|
9
|
-
|
10
|
-
def make_table_footnote_link(out, fnid, fnref)
|
11
|
-
attrs = { href: "##{fnid}", class: "TableFootnoteRef" }
|
12
|
-
out.a **attrs do |a|
|
13
|
-
a << fnref
|
7
|
+
@footnotes.each { |fn| div.parent << fn }
|
14
8
|
end
|
15
|
-
end
|
16
9
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
out.span **attrs do |a|
|
10
|
+
def make_table_footnote_link(out, fnid, fnref)
|
11
|
+
attrs = { href: "##{fnid}", class: "TableFootnoteRef" }
|
12
|
+
out.a **attrs do |a|
|
21
13
|
a << fnref
|
22
14
|
end
|
23
|
-
insert_tab(s, 1)
|
24
15
|
end
|
25
|
-
end
|
26
16
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
17
|
+
def make_table_footnote_target(out, fnid, fnref)
|
18
|
+
attrs = { id: fnid, class: "TableFootnoteRef" }
|
19
|
+
out.span do |s|
|
20
|
+
out.span **attrs do |a|
|
21
|
+
a << fnref
|
22
|
+
end
|
23
|
+
insert_tab(s, 1)
|
33
24
|
end
|
34
|
-
end
|
35
|
-
end
|
25
|
+
end
|
36
26
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
27
|
+
def make_table_footnote_text(node, fnid, fnref)
|
28
|
+
attrs = { id: "fn:#{fnid}" }
|
29
|
+
noko do |xml|
|
30
|
+
xml.div **attr_code(attrs) do |div|
|
31
|
+
make_table_footnote_target(div, fnid, fnref)
|
32
|
+
node.children.each { |n| parse(n, div) }
|
33
|
+
end
|
34
|
+
end.join("\n")
|
35
|
+
end
|
44
36
|
|
45
|
-
|
46
|
-
|
47
|
-
|
37
|
+
def make_generic_footnote_text(node, fnid)
|
38
|
+
noko do |xml|
|
39
|
+
xml.aside **{ id: "fn:#{fnid}", class: "footnote" } do |div|
|
40
|
+
node.children.each { |n| parse(n, div) }
|
41
|
+
end
|
42
|
+
end.join("\n")
|
43
|
+
end
|
48
44
|
|
49
|
-
|
50
|
-
|
45
|
+
def get_table_ancestor_id(node)
|
46
|
+
table = node.ancestors("table") || node.ancestors("figure")
|
47
|
+
return UUIDTools::UUID.random_create.to_s if table.empty?
|
51
48
|
|
52
|
-
|
53
|
-
|
49
|
+
table.last["id"]
|
50
|
+
end
|
54
51
|
|
55
|
-
|
56
|
-
|
57
|
-
tid = get_table_ancestor_id(node)
|
58
|
-
make_table_footnote_link(out, tid + fn, fn)
|
59
|
-
return if @seen_footnote.include?(tid + fn)
|
52
|
+
# @seen_footnote:
|
53
|
+
# do not output footnote text if we have already seen it for this table
|
60
54
|
|
61
|
-
|
62
|
-
|
63
|
-
|
55
|
+
def table_footnote_parse(node, out)
|
56
|
+
fn = node["reference"] || UUIDTools::UUID.random_create.to_s
|
57
|
+
tid = get_table_ancestor_id(node)
|
58
|
+
make_table_footnote_link(out, tid + fn, fn)
|
59
|
+
return if @seen_footnote.include?(tid + fn)
|
60
|
+
|
61
|
+
@in_footnote = true
|
62
|
+
out.aside **{ class: "footnote" } do |a|
|
63
|
+
a << make_table_footnote_text(node, tid + fn, fn)
|
64
|
+
end
|
65
|
+
@in_footnote = false
|
66
|
+
@seen_footnote << (tid + fn)
|
64
67
|
end
|
65
|
-
@in_footnote = false
|
66
|
-
@seen_footnote << (tid + fn)
|
67
|
-
end
|
68
68
|
|
69
|
-
|
70
|
-
|
71
|
-
|
69
|
+
def footnote_parse(node, out)
|
70
|
+
return table_footnote_parse(node, out) if (@in_table || @in_figure) &&
|
71
|
+
!node.ancestors.map(&:name).include?("name")
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
73
|
+
fn = node["reference"] || UUIDTools::UUID.random_create.to_s
|
74
|
+
attrs = { class: "FootnoteRef", href: "#fn:#{fn}" }
|
75
|
+
out.a **attrs do |a|
|
76
|
+
a.sup { |sup| sup << fn }
|
77
|
+
end
|
78
|
+
make_footnote(node, fn)
|
77
79
|
end
|
78
|
-
make_footnote(node, fn)
|
79
|
-
end
|
80
80
|
|
81
|
-
|
82
|
-
|
81
|
+
def make_footnote(node, fnote)
|
82
|
+
return if @seen_footnote.include?(fnote)
|
83
83
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
84
|
+
@in_footnote = true
|
85
|
+
@footnotes << make_generic_footnote_text(node, fnote)
|
86
|
+
@in_footnote = false
|
87
|
+
@seen_footnote << fnote
|
88
|
+
end
|
88
89
|
end
|
89
90
|
end
|
90
91
|
end
|