isodoc 1.7.4 → 1.7.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -1,145 +1,150 @@
|
|
1
|
-
module IsoDoc
|
2
|
-
module
|
1
|
+
module IsoDoc
|
2
|
+
module WordFunction
|
3
|
+
module Comments
|
4
|
+
def in_comment
|
5
|
+
@in_comment
|
6
|
+
end
|
3
7
|
|
4
|
-
|
5
|
-
|
6
|
-
end
|
8
|
+
def comments(div)
|
9
|
+
return if @comments.empty?
|
7
10
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
@comments.each { |fn| div1.parent << fn }
|
11
|
+
div.div **{ style: "mso-element:comment-list" } do |div1|
|
12
|
+
@comments.each { |fn| div1.parent << fn }
|
13
|
+
end
|
12
14
|
end
|
13
|
-
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
def review_note_parse(node, out)
|
17
|
+
fn = @comments.length + 1
|
18
|
+
make_comment_link(out, fn, node)
|
19
|
+
@in_comment = true
|
20
|
+
@comments << make_comment_text(node, fn)
|
21
|
+
@in_comment = false
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
def comment_link_attrs(fnote, node)
|
25
|
+
{ style: "MsoCommentReference", target: fnote,
|
26
|
+
class: "commentLink", from: node["from"],
|
27
|
+
to: node["to"] }
|
28
|
+
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
30
|
+
# add in from and to links to move the comment into place
|
31
|
+
def make_comment_link(out, fnote, node)
|
32
|
+
out.span(**comment_link_attrs(fnote, node)) do |s1|
|
33
|
+
s1.span **{ lang: "EN-GB", style: "font-size:9.0pt" } do |s2|
|
34
|
+
s2.a **{ style: "mso-comment-reference:SMC_#{fnote};"\
|
35
|
+
"mso-comment-date:#{node['date'].gsub(/[:-]+/,
|
36
|
+
'')}" }
|
37
|
+
s2.span **{ style: "mso-special-character:comment",
|
38
|
+
target: fnote } # do |s|
|
39
|
+
end
|
37
40
|
end
|
38
41
|
end
|
39
|
-
end
|
40
42
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
def make_comment_target(out)
|
44
|
+
out.span **{ style: "MsoCommentReference" } do |s1|
|
45
|
+
s1.span **{ lang: "EN-GB", style: "font-size:9.0pt" } do |s2|
|
46
|
+
s2.span **{ style: "mso-special-character:comment" }
|
47
|
+
end
|
45
48
|
end
|
46
49
|
end
|
47
|
-
end
|
48
50
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
51
|
+
def make_comment_text(node, fnote)
|
52
|
+
noko do |xml|
|
53
|
+
xml.div **{ style: "mso-element:comment", id: fnote } do |div|
|
54
|
+
div.span **{ style: %{mso-comment-author:"#{node['reviewer']}"} }
|
55
|
+
make_comment_target(div)
|
56
|
+
node.children.each { |n| parse(n, div) }
|
57
|
+
end
|
58
|
+
end.join("\n")
|
59
|
+
end
|
58
60
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
61
|
+
def comment_cleanup(docxml)
|
62
|
+
move_comment_link_to_from(docxml)
|
63
|
+
reorder_comments_by_comment_link(docxml)
|
64
|
+
embed_comment_in_comment_list(docxml)
|
65
|
+
end
|
64
66
|
|
65
|
-
|
66
|
-
|
67
|
-
|
67
|
+
COMMENT_IN_COMMENT_LIST1 =
|
68
|
+
'//div[@style="mso-element:comment-list"]//'\
|
69
|
+
'span[@style="MsoCommentReference"]'.freeze
|
68
70
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
71
|
+
def embed_comment_in_comment_list(docxml)
|
72
|
+
# docxml.xpath(COMMENT_IN_COMMENT_LIST).each do |x|
|
73
|
+
docxml.xpath(COMMENT_IN_COMMENT_LIST1).each do |x|
|
74
|
+
n = x.next_element
|
75
|
+
n&.children&.first&.add_previous_sibling(x.remove)
|
76
|
+
end
|
77
|
+
docxml
|
74
78
|
end
|
75
|
-
docxml
|
76
|
-
end
|
77
79
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
80
|
+
def move_comment_link_to_from1(tolink, fromlink)
|
81
|
+
tolink.remove
|
82
|
+
link = tolink.at(".//a")
|
83
|
+
fromlink.replace(tolink)
|
84
|
+
link.children = fromlink
|
85
|
+
end
|
84
86
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
tolink = docxml.at("//*[@id='#{x['to']}']") || fromlink
|
89
|
-
target = docxml.at("//*[@id='#{x['target']}']")
|
90
|
-
{ from: fromlink, to: tolink, target: target }
|
91
|
-
end
|
87
|
+
def comment_attributes(docxml, x)
|
88
|
+
fromlink = docxml.at("//*[@id='#{x['from']}']")
|
89
|
+
return(nil) if fromlink.nil?
|
92
90
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
91
|
+
tolink = docxml.at("//*[@id='#{x['to']}']") || fromlink
|
92
|
+
target = docxml.at("//*[@id='#{x['target']}']")
|
93
|
+
{ from: fromlink, to: tolink, target: target }
|
94
|
+
end
|
97
95
|
|
98
|
-
|
99
|
-
|
100
|
-
|
96
|
+
def wrap_comment_cont(from, target)
|
97
|
+
s = from.replace("<span style='mso-comment-continuation:#{target}'>")
|
98
|
+
s.first.children = from
|
99
|
+
end
|
100
|
+
|
101
|
+
def skip_comment_wrap(from)
|
102
|
+
from["style"] != "mso-special-character:comment"
|
103
|
+
end
|
101
104
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
105
|
+
def insert_comment_cont(from, upto, target)
|
106
|
+
# includes_to = from.at(".//*[@id='#{upto}']")
|
107
|
+
while !from.nil? && from["id"] != upto
|
108
|
+
following = from.xpath("./following::*")
|
109
|
+
(from = following.shift) && incl_to = from.at(".//*[@id='#{upto}']")
|
110
|
+
while !incl_to.nil? && !from.nil? && skip_comment_wrap(from)
|
111
|
+
(from = following.shift) && incl_to = from.at(".//*[@id='#{upto}']")
|
112
|
+
end
|
113
|
+
wrap_comment_cont(from, target) if !from.nil?
|
109
114
|
end
|
110
|
-
wrap_comment_cont(from, target) if !from.nil?
|
111
115
|
end
|
112
|
-
end
|
113
116
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
117
|
+
def move_comment_link_to_from(docxml)
|
118
|
+
docxml.xpath('//span[@style="MsoCommentReference"][@from]').each do |x|
|
119
|
+
attrs = comment_attributes(docxml, x) || next
|
120
|
+
move_comment_link_to_from1(x, attrs[:from])
|
121
|
+
insert_comment_cont(attrs[:from], x["to"], x["target"])
|
122
|
+
end
|
119
123
|
end
|
120
|
-
end
|
121
124
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
125
|
+
def get_comments_from_text(docxml, link_order)
|
126
|
+
comments = []
|
127
|
+
docxml.xpath("//div[@style='mso-element:comment']").each do |c|
|
128
|
+
next unless c["id"] && !link_order[c["id"]].nil?
|
129
|
+
|
130
|
+
comments << { text: c.remove.to_s, id: c["id"] }
|
131
|
+
end
|
132
|
+
comments.sort! { |a, b| link_order[a[:id]] <=> link_order[b[:id]] }
|
133
|
+
# comments
|
127
134
|
end
|
128
|
-
comments.sort! { |a, b| link_order[a[:id]] <=> link_order[b[:id]] }
|
129
|
-
# comments
|
130
|
-
end
|
131
135
|
|
132
|
-
|
133
|
-
|
136
|
+
COMMENT_TARGET_XREFS1 =
|
137
|
+
"//span[@style='mso-special-character:comment']/@target".freeze
|
134
138
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
+
def reorder_comments_by_comment_link(docxml)
|
140
|
+
link_order = {}
|
141
|
+
docxml.xpath(COMMENT_TARGET_XREFS1).each_with_index do |target, i|
|
142
|
+
link_order[target.value] = i
|
143
|
+
end
|
144
|
+
comments = get_comments_from_text(docxml, link_order)
|
145
|
+
list = docxml.at("//*[@style='mso-element:comment-list']") || return
|
146
|
+
list.children = comments.map { |c| c[:text] }.join("\n")
|
139
147
|
end
|
140
|
-
comments = get_comments_from_text(docxml, link_order)
|
141
|
-
list = docxml.at("//*[@style='mso-element:comment-list']") || return
|
142
|
-
list.children = comments.map { |c| c[:text] }.join("\n")
|
143
148
|
end
|
144
149
|
end
|
145
150
|
end
|
@@ -1,112 +1,114 @@
|
|
1
|
-
module IsoDoc
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
ret
|
1
|
+
module IsoDoc
|
2
|
+
module WordFunction
|
3
|
+
module Footnotes
|
4
|
+
def bookmarkid
|
5
|
+
ret = "X"
|
6
|
+
until !@bookmarks_allocated[ret]
|
7
|
+
ret = Random.rand(1000000000)
|
8
|
+
end
|
9
|
+
@bookmarks_allocated[ret] = true
|
10
|
+
sprintf "%09d", ret
|
7
11
|
end
|
8
|
-
@bookmarks_allocated[ret] = true
|
9
|
-
sprintf "%09d", ret
|
10
|
-
end
|
11
|
-
|
12
|
-
def footnotes(div)
|
13
|
-
return if @footnotes.empty?
|
14
12
|
|
15
|
-
|
16
|
-
|
13
|
+
def footnotes(div)
|
14
|
+
return if @footnotes.empty?
|
17
15
|
|
18
|
-
|
19
|
-
attrs = { href: "##{fnid}", class: "TableFootnoteRef" }
|
20
|
-
out.a **attrs do |a|
|
21
|
-
a << fnref
|
16
|
+
@footnotes.each { |fn| div.parent << fn }
|
22
17
|
end
|
23
|
-
end
|
24
18
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
out.span **attrs do |a|
|
19
|
+
def make_table_footnote_link(out, fnid, fnref)
|
20
|
+
attrs = { href: "##{fnid}", class: "TableFootnoteRef" }
|
21
|
+
out.a **attrs do |a|
|
29
22
|
a << fnref
|
30
23
|
end
|
31
|
-
insert_tab(s, 1)
|
32
24
|
end
|
33
|
-
end
|
34
25
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
26
|
+
def make_table_footnote_target(out, fnid, fnref)
|
27
|
+
attrs = { id: fnid, class: "TableFootnoteRef" }
|
28
|
+
out.span do |s|
|
29
|
+
out.span **attrs do |a|
|
30
|
+
a << fnref
|
31
|
+
end
|
32
|
+
insert_tab(s, 1)
|
41
33
|
end
|
42
|
-
end
|
43
|
-
end
|
34
|
+
end
|
44
35
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
36
|
+
def make_table_footnote_text(node, fnid, fnref)
|
37
|
+
attrs = { id: "ftn#{fnid}" }
|
38
|
+
noko do |xml|
|
39
|
+
xml.div **attr_code(attrs) do |div|
|
40
|
+
make_table_footnote_target(div, fnid, fnref)
|
41
|
+
node.children.each { |n| parse(n, div) }
|
42
|
+
end
|
43
|
+
end.join("\n")
|
44
|
+
end
|
52
45
|
|
53
|
-
|
54
|
-
|
55
|
-
|
46
|
+
def make_generic_footnote_text(node, fnid)
|
47
|
+
noko do |xml|
|
48
|
+
xml.aside **{ id: "ftn#{fnid}" } do |div|
|
49
|
+
node.children.each { |n| parse(n, div) }
|
50
|
+
end
|
51
|
+
end.join("\n")
|
52
|
+
end
|
56
53
|
|
57
|
-
|
58
|
-
|
54
|
+
def get_table_ancestor_id(node)
|
55
|
+
table = node.ancestors("table") || node.ancestors("figure")
|
56
|
+
return UUIDTools::UUID.random_create.to_s if table.empty?
|
59
57
|
|
60
|
-
|
61
|
-
|
62
|
-
tid = get_table_ancestor_id(node)
|
63
|
-
make_table_footnote_link(out, tid + fn, fn)
|
64
|
-
# do not output footnote text if we have already seen it for this table
|
65
|
-
return if @seen_footnote.include?(tid + fn)
|
66
|
-
|
67
|
-
@in_footnote = true
|
68
|
-
out.aside { |a| a << make_table_footnote_text(node, tid + fn, fn) }
|
69
|
-
@in_footnote = false
|
70
|
-
@seen_footnote << (tid + fn)
|
71
|
-
end
|
58
|
+
table.last["id"]
|
59
|
+
end
|
72
60
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
61
|
+
def table_footnote_parse(node, out)
|
62
|
+
fn = node["reference"] || UUIDTools::UUID.random_create.to_s
|
63
|
+
tid = get_table_ancestor_id(node)
|
64
|
+
make_table_footnote_link(out, tid + fn, fn)
|
65
|
+
# do not output footnote text if we have already seen it for this table
|
66
|
+
return if @seen_footnote.include?(tid + fn)
|
67
|
+
|
68
|
+
@in_footnote = true
|
69
|
+
out.aside { |a| a << make_table_footnote_text(node, tid + fn, fn) }
|
70
|
+
@in_footnote = false
|
71
|
+
@seen_footnote << (tid + fn)
|
79
72
|
end
|
80
|
-
out.span **{ style: "mso-element:field-end" }
|
81
|
-
end
|
82
73
|
|
83
|
-
|
84
|
-
|
85
|
-
|
74
|
+
def seen_footnote_parse(_node, out, footnote)
|
75
|
+
out.span **{ style: "mso-element:field-begin" }
|
76
|
+
out << " NOTEREF _Ref#{@fn_bookmarks[footnote]} \\f \\h"
|
77
|
+
out.span **{ style: "mso-element:field-separator" }
|
78
|
+
out.span **{ class: "MsoFootnoteReference" } do |s|
|
79
|
+
s << footnote
|
80
|
+
end
|
81
|
+
out.span **{ style: "mso-element:field-end" }
|
82
|
+
end
|
83
|
+
|
84
|
+
def footnote_parse(node, out)
|
85
|
+
return table_footnote_parse(node, out) if (@in_table || @in_figure) &&
|
86
|
+
!node.ancestors.map(&:name).include?("name")
|
86
87
|
|
87
|
-
|
88
|
-
|
88
|
+
fn = node["reference"] || UUIDTools::UUID.random_create.to_s
|
89
|
+
return seen_footnote_parse(node, out, fn) if @seen_footnote.include?(fn)
|
89
90
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
91
|
+
@fn_bookmarks[fn] = bookmarkid
|
92
|
+
out.span **{ style: "mso-bookmark:_Ref#{@fn_bookmarks[fn]}" } do |s|
|
93
|
+
s.a **{ class: "FootnoteRef", "epub:type": "footnote",
|
94
|
+
href: "#ftn#{fn}" } do |a|
|
95
|
+
a.sup { |sup| sup << fn }
|
96
|
+
end
|
95
97
|
end
|
98
|
+
@in_footnote = true
|
99
|
+
@footnotes << make_generic_footnote_text(node, fn)
|
100
|
+
@in_footnote = false
|
101
|
+
@seen_footnote << fn
|
96
102
|
end
|
97
|
-
@in_footnote = true
|
98
|
-
@footnotes << make_generic_footnote_text(node, fn)
|
99
|
-
@in_footnote = false
|
100
|
-
@seen_footnote << fn
|
101
|
-
end
|
102
103
|
|
103
|
-
|
104
|
-
|
104
|
+
def make_footnote(node, footnote)
|
105
|
+
return if @seen_footnote.include?(footnote)
|
105
106
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
107
|
+
@in_footnote = true
|
108
|
+
@footnotes << make_generic_footnote_text(node, footnote)
|
109
|
+
@in_footnote = false
|
110
|
+
@seen_footnote << footnote
|
111
|
+
end
|
110
112
|
end
|
111
113
|
end
|
112
114
|
end
|
@@ -1,83 +1,58 @@
|
|
1
|
-
module IsoDoc
|
2
|
-
module
|
3
|
-
|
4
|
-
body
|
5
|
-
p
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
def page_break(out)
|
10
|
-
out.p do |p|
|
11
|
-
p.br **{ clear: "all",
|
12
|
-
style: "mso-special-character:line-break;"\
|
13
|
-
"page-break-before:always" }
|
1
|
+
module IsoDoc
|
2
|
+
module WordFunction
|
3
|
+
module Body
|
4
|
+
def section_break(body)
|
5
|
+
body.p do |p|
|
6
|
+
p.br **{ clear: "all", class: "section" }
|
7
|
+
end
|
14
8
|
end
|
15
|
-
end
|
16
9
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
10
|
+
def page_break(out)
|
11
|
+
out.p do |p|
|
12
|
+
p.br **{ clear: "all",
|
13
|
+
style: "mso-special-character:line-break;"\
|
14
|
+
"page-break-before:always" }
|
15
|
+
end
|
22
16
|
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def svg_parse(node, out)
|
26
|
-
svg = Base64.strict_encode64(node.to_xml)
|
27
|
-
r = node.replace("<img src='data:image/svg+xml;base64,#{svg}' mimetype='image/svg+xml'/>").first
|
28
|
-
image_parse(r, out, nil)
|
29
|
-
end
|
30
17
|
|
31
|
-
|
32
|
-
|
33
|
-
return node["src"] unless %r{^data:}.match node["src"]
|
34
|
-
save_dataimage(node["src"])
|
35
|
-
end
|
18
|
+
def pagebreak_parse(node, out)
|
19
|
+
return page_break(out) if node["orientation"].nil?
|
36
20
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
width: node["width"] }
|
43
|
-
out.img **attr_code(attrs)
|
44
|
-
image_title_parse(out, caption)
|
45
|
-
end
|
21
|
+
out.p do |p|
|
22
|
+
p.br **{ clear: "all", class: "section",
|
23
|
+
orientation: node["orientation"] }
|
24
|
+
end
|
25
|
+
end
|
46
26
|
|
47
|
-
|
48
|
-
|
49
|
-
end
|
27
|
+
def imgsrc(node)
|
28
|
+
return node["src"] unless %r{^data:}.match? node["src"]
|
50
29
|
|
51
|
-
|
52
|
-
|
53
|
-
uri = node["src"]
|
54
|
-
%r{^data:}.match(uri) and uri = save_dataimage(uri)
|
55
|
-
ret = svg_to_emf_filename(uri)
|
56
|
-
File.exists?(ret) and return ret
|
57
|
-
exe = inkscape_installed? or return nil
|
58
|
-
system %(#{exe} --export-type="emf" #{uri}) and
|
59
|
-
return ret
|
60
|
-
nil
|
61
|
-
end
|
30
|
+
save_dataimage(node["src"])
|
31
|
+
end
|
62
32
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
exe = File.join(path, "#{cmd}#{ext}")
|
69
|
-
return exe if File.executable?(exe) && !File.directory?(exe)
|
33
|
+
def image_parse(node, out, caption)
|
34
|
+
if emf = node.at(ns("./emf"))
|
35
|
+
node["src"] = emf["src"]
|
36
|
+
node["mimetype"] = "image/x-emf"
|
37
|
+
node.children.remove
|
70
38
|
end
|
39
|
+
attrs = { src: imgsrc(node),
|
40
|
+
height: node["height"], alt: node["alt"],
|
41
|
+
title: node["title"], width: node["width"] }
|
42
|
+
out.img **attr_code(attrs)
|
43
|
+
image_title_parse(out, caption)
|
71
44
|
end
|
72
|
-
nil
|
73
|
-
end
|
74
45
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
46
|
+
def xref_parse(node, out)
|
47
|
+
target = if /#/.match?(node["target"])
|
48
|
+
node["target"].sub(/#/, ".doc#")
|
49
|
+
else
|
50
|
+
"##{node['target']}"
|
51
|
+
end
|
52
|
+
out.a(**{ href: target }) do |l|
|
79
53
|
node.children.each { |n| parse(n, l) }
|
80
54
|
end
|
55
|
+
end
|
81
56
|
end
|
82
57
|
end
|
83
58
|
end
|