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
@@ -1,16 +1,22 @@
|
|
1
|
+
require "metanorma-utils"
|
2
|
+
require_relative "./concept"
|
3
|
+
|
1
4
|
module IsoDoc
|
2
5
|
class PresentationXMLConvert < ::IsoDoc::Convert
|
3
6
|
def prefix_container(container, linkend, _target)
|
4
7
|
l10n("#{@xrefs.anchor(container, :xref)}, #{linkend}")
|
5
8
|
end
|
6
9
|
|
10
|
+
def anchor_value(id)
|
11
|
+
@xrefs.anchor(id, :value) || @xrefs.anchor(id, :label) ||
|
12
|
+
@xrefs.anchor(id, :xref)
|
13
|
+
end
|
14
|
+
|
7
15
|
def anchor_linkend(node, linkend)
|
8
16
|
if node["citeas"].nil? && node["bibitemid"]
|
9
17
|
return @xrefs.anchor(node["bibitemid"], :xref) || "???"
|
10
18
|
elsif node["target"] && node["droploc"]
|
11
|
-
return
|
12
|
-
@xrefs.anchor(node["target"], :label) ||
|
13
|
-
@xrefs.anchor(node["target"], :xref) || "???"
|
19
|
+
return anchor_value(node["target"]) || "???"
|
14
20
|
elsif node["target"] && !/.#./.match(node["target"])
|
15
21
|
linkend = anchor_linkend1(node)
|
16
22
|
end
|
@@ -24,14 +30,15 @@ module IsoDoc
|
|
24
30
|
(container && get_note_container_id(node) != container &&
|
25
31
|
@xrefs.get[node["target"]]) and
|
26
32
|
linkend = prefix_container(container, linkend, node["target"])
|
27
|
-
capitalise_xref(node, linkend)
|
33
|
+
capitalise_xref(node, linkend, anchor_value(node["target"]))
|
28
34
|
end
|
29
35
|
|
30
|
-
def capitalise_xref(node, linkend)
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
36
|
+
def capitalise_xref(node, linkend, label)
|
37
|
+
linktext = linkend.gsub(/<[^>]+>/, "")
|
38
|
+
(label && !label.empty? && /^#{Regexp.escape(label)}/.match?(linktext) ||
|
39
|
+
linktext[0, 1].match?(/\p{Upper}/)) and return linkend
|
40
|
+
node["case"] and
|
41
|
+
return Common::case_with_markup(linkend, node["case"], @script)
|
35
42
|
|
36
43
|
capitalise_xref1(node, linkend)
|
37
44
|
end
|
@@ -40,7 +47,7 @@ module IsoDoc
|
|
40
47
|
prec = nearest_block_parent(node).xpath("./descendant-or-self::text()") &
|
41
48
|
node.xpath("./preceding::text()")
|
42
49
|
if prec.empty? || /(?!<[^.].)\.\s+$/.match(prec.map(&:text).join)
|
43
|
-
linkend
|
50
|
+
Common::case_with_markup(linkend, "capital", @script)
|
44
51
|
else linkend
|
45
52
|
end
|
46
53
|
end
|
@@ -67,7 +74,7 @@ module IsoDoc
|
|
67
74
|
link += eref_localities(node.xpath(ns("./locality | ./localityStack")),
|
68
75
|
link, node)
|
69
76
|
non_locality_elems(node).each(&:remove)
|
70
|
-
node.add_child(link)
|
77
|
+
node.add_child(cleanup_entities(link))
|
71
78
|
end
|
72
79
|
# so not <origin bibitemid="ISO7301" citeas="ISO 7301">
|
73
80
|
# <locality type="section"><reference>3.1</reference></locality></origin>
|
@@ -88,8 +95,7 @@ module IsoDoc
|
|
88
95
|
ret += eref_localities0(rr, j, target, delim, node)
|
89
96
|
delim = ","
|
90
97
|
end
|
91
|
-
else
|
92
|
-
ret += eref_localities0(ref, idx, target, delim, node)
|
98
|
+
else ret += eref_localities0(ref, idx, target, delim, node)
|
93
99
|
end
|
94
100
|
ret
|
95
101
|
end
|
@@ -130,7 +136,7 @@ module IsoDoc
|
|
130
136
|
loc = @i18n.locality[type] || type.sub(/^locality:/, "")
|
131
137
|
loc = case node["case"]
|
132
138
|
when "lowercase" then loc.downcase
|
133
|
-
else loc
|
139
|
+
else Metanorma::Utils.strict_capitalize_first(loc)
|
134
140
|
end
|
135
141
|
" #{loc}"
|
136
142
|
end
|
@@ -155,41 +161,6 @@ module IsoDoc
|
|
155
161
|
get_linkend(node)
|
156
162
|
end
|
157
163
|
|
158
|
-
def concept(docxml)
|
159
|
-
docxml.xpath(ns("//concept")).each { |f| concept1(f) }
|
160
|
-
end
|
161
|
-
|
162
|
-
def concept1(node)
|
163
|
-
xref = node&.at(ns("./xref/@target"))&.text or
|
164
|
-
return concept_render(node, node["ital"] || "true",
|
165
|
-
node["ref"] || "true")
|
166
|
-
if node.at(ns("//definitions//dt[@id = '#{xref}']"))
|
167
|
-
concept_render(node, node["ital"] || "false", node["ref"] || "false")
|
168
|
-
else concept_render(node, node["ital"] || "true", node["ref"] || "true")
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
def concept_render(node, ital, ref)
|
173
|
-
node&.at(ns("./refterm"))&.remove
|
174
|
-
r = node.at(ns("./renderterm"))
|
175
|
-
r&.next = " " if node.at(ns("./xref | ./eref | ./termref")) && ref != "false"
|
176
|
-
if ital == "true" then r&.name = "em"
|
177
|
-
else r&.replace(r&.children)
|
178
|
-
end
|
179
|
-
concept1_ref(node, ref)
|
180
|
-
node.replace(node.children)
|
181
|
-
end
|
182
|
-
|
183
|
-
def concept1_ref(node, ref)
|
184
|
-
r = node.at(ns("./xref | ./eref | ./termref")) or return
|
185
|
-
return r.remove if ref == "false"
|
186
|
-
|
187
|
-
if non_locality_elems(r).select { |c| !c.text? || /\S/.match(c) }.empty?
|
188
|
-
r.replace(@i18n.term_defined_in.sub(/%/, r.to_xml))
|
189
|
-
else r.replace("[#{r.to_xml}]")
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
164
|
def variant(docxml)
|
194
165
|
docxml.xpath(ns("//variant")).each { |f| variant1(f) }
|
195
166
|
docxml.xpath(ns("//variant[@remove = 'true']")).each(&:remove)
|
data/lib/isodoc/version.rb
CHANGED
@@ -1,231 +1,233 @@
|
|
1
1
|
require_relative "./table"
|
2
2
|
require_relative "./inline"
|
3
3
|
|
4
|
-
module IsoDoc
|
5
|
-
module
|
6
|
-
|
7
|
-
head
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
def body_attr
|
17
|
-
{ lang: "EN-US", link: "blue", vlink: "#954F72" }
|
18
|
-
end
|
4
|
+
module IsoDoc
|
5
|
+
module WordFunction
|
6
|
+
module Body
|
7
|
+
def define_head(head, filename, _dir)
|
8
|
+
head.style do |style|
|
9
|
+
loc = File.join(File.dirname(__FILE__), "..", "base_style",
|
10
|
+
"metanorma_word.scss")
|
11
|
+
stylesheet = File.read(loc, encoding: "utf-8")
|
12
|
+
style.comment "\n#{stylesheet}\n"
|
13
|
+
end
|
14
|
+
super
|
15
|
+
end
|
19
16
|
|
20
|
-
|
21
|
-
|
22
|
-
div1.p { |p| p << " " } # placeholder
|
17
|
+
def body_attr
|
18
|
+
{ lang: "EN-US", link: "blue", vlink: "#954F72" }
|
23
19
|
end
|
24
|
-
section_break(body)
|
25
|
-
end
|
26
20
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
21
|
+
def make_body1(body, _docxml)
|
22
|
+
body.div **{ class: "WordSection1" } do |div1|
|
23
|
+
div1.p { |p| p << " " } # placeholder
|
24
|
+
end
|
25
|
+
section_break(body)
|
26
|
+
end
|
27
|
+
|
28
|
+
def make_body2(body, docxml)
|
29
|
+
body.div **{ class: "WordSection2" } do |div2|
|
30
|
+
boilerplate docxml, div2
|
31
|
+
preface_block docxml, div2
|
32
|
+
abstract docxml, div2
|
33
|
+
foreword docxml, div2
|
34
|
+
introduction docxml, div2
|
35
|
+
preface docxml, div2
|
36
|
+
acknowledgements docxml, div2
|
37
|
+
div2.p { |p| p << " " } # placeholder
|
38
|
+
end
|
39
|
+
section_break(body)
|
40
|
+
end
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
def make_body3(body, docxml)
|
43
|
+
body.div **{ class: "WordSection3" } do |div3|
|
44
|
+
middle docxml, div3
|
45
|
+
footnotes div3
|
46
|
+
comments div3
|
47
|
+
end
|
46
48
|
end
|
47
|
-
end
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
50
|
+
def insert_tab(out, count)
|
51
|
+
out.span **attr_code(style: "mso-tab-count:#{count}") do |span|
|
52
|
+
[1..count].each { span << "  " }
|
53
|
+
end
|
52
54
|
end
|
53
|
-
end
|
54
55
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
56
|
+
def para_class(_node)
|
57
|
+
classtype = nil
|
58
|
+
classtype = "Note" if @note
|
59
|
+
classtype = "MsoCommentText" if in_comment
|
60
|
+
classtype = "Sourcecode" if @annotation
|
61
|
+
classtype
|
62
|
+
end
|
62
63
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
64
|
+
def para_parse(node, out)
|
65
|
+
out.p **attr_code(para_attrs(node)) do |p|
|
66
|
+
unless @termdomain.empty?
|
67
|
+
p << "<#{@termdomain}> "
|
68
|
+
@termdomain = ""
|
69
|
+
end
|
70
|
+
node.children.each { |n| parse(n, p) unless n.name == "note" }
|
68
71
|
end
|
69
|
-
node.
|
72
|
+
node.xpath(ns("./note")).each { |n| parse(n, out) }
|
70
73
|
end
|
71
|
-
node.xpath(ns("./note")).each { |n| parse(n, out) }
|
72
|
-
end
|
73
74
|
|
74
|
-
|
75
|
-
|
75
|
+
WORD_DT_ATTRS = { class: @note ? "Note" : nil, align: "left",
|
76
|
+
style: "margin-left:0pt;text-align:left;" }.freeze
|
76
77
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
78
|
+
def dt_parse(dterm, term)
|
79
|
+
term.p **attr_code(WORD_DT_ATTRS) do |p|
|
80
|
+
if dterm.elements.empty?
|
81
|
+
p << dterm.text
|
82
|
+
else
|
83
|
+
dterm.children.each { |n| parse(n, p) }
|
84
|
+
end
|
83
85
|
end
|
84
86
|
end
|
85
|
-
end
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
88
|
+
def dl_parse(node, out)
|
89
|
+
out.table **{ class: "dl" } do |v|
|
90
|
+
node.elements.select { |n| dt_dd? n }.each_slice(2) do |dt, dd|
|
91
|
+
v.tr do |tr|
|
92
|
+
tr.td **{ valign: "top", align: "left" } do |term|
|
93
|
+
dt_parse(dt, term)
|
94
|
+
end
|
95
|
+
tr.td **{ valign: "top" } do |listitem|
|
96
|
+
dd.children.each { |n| parse(n, listitem) }
|
97
|
+
end
|
96
98
|
end
|
97
99
|
end
|
100
|
+
dl_parse_notes(node, v)
|
98
101
|
end
|
99
|
-
dl_parse_notes(node, v)
|
100
102
|
end
|
101
|
-
end
|
102
103
|
|
103
|
-
|
104
|
-
|
104
|
+
def dl_parse_notes(node, out)
|
105
|
+
return if node.elements.reject { |n| dt_dd? n }.empty?
|
105
106
|
|
106
|
-
|
107
|
-
|
108
|
-
|
107
|
+
out.tr do |tr|
|
108
|
+
tr.td **{ colspan: 2 } do |td|
|
109
|
+
node.elements.reject { |n| dt_dd? n }.each { |n| parse(n, td) }
|
110
|
+
end
|
109
111
|
end
|
110
112
|
end
|
111
|
-
end
|
112
113
|
|
113
|
-
|
114
|
-
dl = node.at(".//table[@class = 'dl']")
|
115
|
-
if dl.nil?
|
116
|
-
node.add_child("<p><b>#{@i18n.key}</b></p><table class='dl'></table>")
|
114
|
+
def figure_get_or_make_dl(node)
|
117
115
|
dl = node.at(".//table[@class = 'dl']")
|
116
|
+
if dl.nil?
|
117
|
+
node.add_child("<p><b>#{@i18n.key}</b></p><table class='dl'></table>")
|
118
|
+
dl = node.at(".//table[@class = 'dl']")
|
119
|
+
end
|
120
|
+
dl
|
121
|
+
end
|
122
|
+
|
123
|
+
def figure_aside_process(fig, aside, key)
|
124
|
+
# get rid of footnote link, it is in diagram
|
125
|
+
fig&.at("./a[@class='TableFootnoteRef']")&.remove
|
126
|
+
fnref = fig.at(".//span[@class='TableFootnoteRef']/..")
|
127
|
+
tr = key.add_child("<tr></tr>").first
|
128
|
+
dt = tr.add_child("<td valign='top' align='left'></td>").first
|
129
|
+
dd = tr.add_child("<td valign='top'></td>").first
|
130
|
+
fnref.parent = dt
|
131
|
+
aside.xpath(".//p").each do |a|
|
132
|
+
a.delete("class")
|
133
|
+
a.parent = dd
|
134
|
+
end
|
118
135
|
end
|
119
|
-
dl
|
120
|
-
end
|
121
|
-
|
122
|
-
def figure_aside_process(fig, aside, key)
|
123
|
-
# get rid of footnote link, it is in diagram
|
124
|
-
fig&.at("./a[@class='TableFootnoteRef']")&.remove
|
125
|
-
fnref = fig.at(".//span[@class='TableFootnoteRef']/..")
|
126
|
-
tr = key.add_child("<tr></tr>").first
|
127
|
-
dt = tr.add_child("<td valign='top' align='left'></td>").first
|
128
|
-
dd = tr.add_child("<td valign='top'></td>").first
|
129
|
-
fnref.parent = dt
|
130
|
-
aside.xpath(".//p").each do |a|
|
131
|
-
a.delete("class")
|
132
|
-
a.parent = dd
|
133
|
-
end
|
134
|
-
end
|
135
136
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
137
|
+
def note_p_parse(node, div)
|
138
|
+
name = node&.at(ns("./name"))&.remove
|
139
|
+
div.p **{ class: "Note" } do |p|
|
140
|
+
p.span **{ class: "note_label" } do |s|
|
141
|
+
name&.children&.each { |n| parse(n, s) }
|
142
|
+
end
|
143
|
+
insert_tab(p, 1)
|
144
|
+
node.first_element_child.children.each { |n| parse(n, p) }
|
141
145
|
end
|
142
|
-
|
143
|
-
node.first_element_child.children.each { |n| parse(n, p) }
|
146
|
+
node.element_children[1..-1].each { |n| parse(n, div) }
|
144
147
|
end
|
145
|
-
node.element_children[1..-1].each { |n| parse(n, div) }
|
146
|
-
end
|
147
148
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
149
|
+
def note_parse1(node, div)
|
150
|
+
name = node&.at(ns("./name"))&.remove
|
151
|
+
div.p **{ class: "Note" } do |p|
|
152
|
+
p.span **{ class: "note_label" } do |s|
|
153
|
+
name&.children&.each { |n| parse(n, s) }
|
154
|
+
end
|
155
|
+
insert_tab(p, 1)
|
153
156
|
end
|
154
|
-
|
157
|
+
node.children.each { |n| parse(n, div) }
|
155
158
|
end
|
156
|
-
node.children.each { |n| parse(n, div) }
|
157
|
-
end
|
158
159
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
160
|
+
def termnote_parse(node, out)
|
161
|
+
name = node&.at(ns("./name"))&.remove
|
162
|
+
out.div **note_attrs(node) do |div|
|
163
|
+
div.p **{ class: "Note" } do |p|
|
164
|
+
if name
|
165
|
+
name.children.each { |n| parse(n, p) }
|
166
|
+
p << l10n(": ")
|
167
|
+
end
|
168
|
+
para_then_remainder(node.first_element_child, node, p, div)
|
166
169
|
end
|
167
|
-
para_then_remainder(node.first_element_child, node, p, div)
|
168
170
|
end
|
169
171
|
end
|
170
|
-
end
|
171
172
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
173
|
+
def para_attrs(node)
|
174
|
+
attrs = { class: para_class(node), id: node["id"], style: "" }
|
175
|
+
unless node["align"].nil?
|
176
|
+
attrs[:align] = node["align"] unless node["align"] == "justify"
|
177
|
+
attrs[:style] += "text-align:#{node['align']};"
|
178
|
+
end
|
179
|
+
attrs[:style] += keep_style(node).to_s
|
180
|
+
attrs[:style] = nil if attrs[:style].empty?
|
181
|
+
attrs
|
177
182
|
end
|
178
|
-
attrs[:style] += keep_style(node).to_s
|
179
|
-
attrs[:style] = nil if attrs[:style].empty?
|
180
|
-
attrs
|
181
|
-
end
|
182
183
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
184
|
+
def example_table_attr(node)
|
185
|
+
super.merge(
|
186
|
+
style: "mso-table-lspace:15.0cm;margin-left:423.0pt;"\
|
187
|
+
"mso-table-rspace:15.0cm;margin-right:423.0pt;"\
|
188
|
+
"mso-table-anchor-horizontal:column;"\
|
189
|
+
"mso-table-overlap:never;border-collapse:collapse;"\
|
190
|
+
"#{keep_style(node)}",
|
191
|
+
)
|
192
|
+
end
|
192
193
|
|
193
|
-
|
194
|
-
|
194
|
+
def formula_where(deflist, out)
|
195
|
+
return unless deflist
|
195
196
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
197
|
+
out.p { |p| p << @i18n.where }
|
198
|
+
parse(deflist, out)
|
199
|
+
out.parent.at("./table")["class"] = "formula_dl"
|
200
|
+
end
|
200
201
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
202
|
+
def formula_parse1(node, out)
|
203
|
+
out.div **attr_code(class: "formula") do |div|
|
204
|
+
div.p do |_p|
|
205
|
+
parse(node.at(ns("./stem")), div)
|
206
|
+
insert_tab(div, 1)
|
207
|
+
if lbl = node&.at(ns("./name"))&.text
|
208
|
+
div << "(#{lbl})"
|
209
|
+
end
|
208
210
|
end
|
209
211
|
end
|
210
212
|
end
|
211
|
-
end
|
212
213
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
214
|
+
def li_parse(node, out)
|
215
|
+
out.li **attr_code(id: node["id"]) do |li|
|
216
|
+
if node["uncheckedcheckbox"] == "true"
|
217
|
+
li << '<span class="zzMoveToFollowing">☐ </span>'
|
218
|
+
elsif node["checkedcheckbox"] == "true"
|
219
|
+
li << '<span class="zzMoveToFollowing">☑ </span>'
|
220
|
+
end
|
221
|
+
node.children.each { |n| parse(n, li) }
|
219
222
|
end
|
220
|
-
node.children.each { |n| parse(n, li) }
|
221
223
|
end
|
222
|
-
end
|
223
224
|
|
224
|
-
|
225
|
-
|
226
|
-
|
225
|
+
def suffix_url(url)
|
226
|
+
return url if %r{^https?://}.match?(url)
|
227
|
+
return url unless File.extname(url).empty?
|
227
228
|
|
228
|
-
|
229
|
+
url.sub(/#{File.extname(url)}$/, ".doc")
|
230
|
+
end
|
229
231
|
end
|
230
232
|
end
|
231
233
|
end
|