isodoc 2.4.0 → 2.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/isodoc.gemspec +1 -0
- data/lib/isodoc/base_style/all.css +29 -0
- data/lib/isodoc/base_style/metanorma_word.css +9 -0
- data/lib/isodoc/base_style/metanorma_word.scss +11 -0
- data/lib/isodoc/base_style/reset.css +29 -0
- data/lib/isodoc/base_style/reset.scss +34 -0
- data/lib/isodoc/base_style/rouge.css +39 -0
- data/lib/isodoc/base_style/typography.scss +6 -3
- data/lib/isodoc/convert.rb +7 -4
- data/lib/isodoc/function/blocks.rb +26 -16
- data/lib/isodoc/function/inline.rb +17 -17
- data/lib/isodoc/function/references.rb +38 -52
- data/lib/isodoc/function/table.rb +22 -13
- data/lib/isodoc/function/to_word_html.rb +1 -4
- data/lib/isodoc/function/utils.rb +5 -1
- data/lib/isodoc/html_function/html.rb +13 -34
- data/lib/isodoc/html_function/postprocess.rb +14 -1
- data/lib/isodoc/html_function/postprocess_cover.rb +6 -9
- data/lib/isodoc/metadata.rb +5 -0
- data/lib/isodoc/presentation_function/block.rb +15 -46
- data/lib/isodoc/presentation_function/refs.rb +75 -3
- data/lib/isodoc/presentation_function/sourcecode.rb +114 -0
- data/lib/isodoc/presentation_function/terms.rb +29 -37
- data/lib/isodoc/presentation_function/xrefs.rb +9 -6
- data/lib/isodoc/version.rb +1 -1
- data/lib/isodoc/word_function/body.rb +16 -16
- data/lib/isodoc/word_function/postprocess.rb +47 -43
- data/lib/isodoc/word_function/postprocess_cover.rb +29 -157
- data/lib/isodoc/word_function/postprocess_toc.rb +165 -0
- data/lib/isodoc/word_function/table.rb +25 -13
- data/lib/isodoc/xref/xref_gen.rb +2 -4
- metadata +19 -2
@@ -1,17 +1,19 @@
|
|
1
1
|
module IsoDoc
|
2
2
|
class PresentationXMLConvert < ::IsoDoc::Convert
|
3
3
|
def concept(docxml)
|
4
|
+
@definition_ids = docxml.xpath(ns("//definitions//dt"))
|
5
|
+
.each_with_object({}) { |x, m| m[x["id"]] = true }
|
4
6
|
docxml.xpath(ns("//concept")).each { |f| concept1(f) }
|
5
7
|
end
|
6
8
|
|
7
9
|
def concept1(node)
|
8
10
|
xref = node&.at(ns("./xref/@target"))&.text or
|
9
|
-
return concept_render(node, ital: "true", ref: "true",
|
11
|
+
return concept_render(node, ital: "true", ref: "true", bold: "false",
|
10
12
|
linkref: "true", linkmention: "false")
|
11
|
-
if
|
12
|
-
concept_render(node, ital: "false", ref: "false",
|
13
|
+
if @definition_ids[xref]
|
14
|
+
concept_render(node, ital: "false", ref: "false", bold: "false",
|
13
15
|
linkref: "true", linkmention: "false")
|
14
|
-
else concept_render(node, ital: "true", ref: "true",
|
16
|
+
else concept_render(node, ital: "true", ref: "true", bold: "false",
|
15
17
|
linkref: "true", linkmention: "false")
|
16
18
|
end
|
17
19
|
end
|
@@ -20,21 +22,23 @@ module IsoDoc
|
|
20
22
|
opts, render, ref = concept_render_init(node, defaults)
|
21
23
|
node&.at(ns("./refterm"))&.remove
|
22
24
|
ref && opts[:ref] != "false" and render&.next = " "
|
23
|
-
opts[:ital] == "true" and render&.name = "em"
|
24
25
|
concept1_linkmention(ref, render, opts)
|
25
26
|
concept1_ref(node, ref, opts)
|
26
|
-
|
27
|
+
concept1_style(node, opts)
|
27
28
|
node.replace(node.children)
|
28
29
|
end
|
29
30
|
|
30
|
-
def
|
31
|
-
|
32
|
-
r =
|
33
|
-
|
31
|
+
def concept1_style(node, opts)
|
32
|
+
r = node.at(ns(".//renderterm")) or return
|
33
|
+
opts[:ital] == "true" and r.children = "<em>#{to_xml(r.children)}</em>"
|
34
|
+
opts[:bold] == "true" and
|
35
|
+
r.children = "<strong>#{to_xml(r.children)}</strong>"
|
36
|
+
r.replace(r.children)
|
34
37
|
end
|
35
38
|
|
36
39
|
def concept_render_init(node, defaults)
|
37
|
-
opts = %i(ital ref linkref linkmention)
|
40
|
+
opts = %i(bold ital ref linkref linkmention)
|
41
|
+
.each_with_object({}) do |x, m|
|
38
42
|
m[x] = node[x.to_s] || defaults[x]
|
39
43
|
end
|
40
44
|
[opts, node.at(ns("./renderterm")),
|
@@ -42,8 +46,8 @@ module IsoDoc
|
|
42
46
|
end
|
43
47
|
|
44
48
|
def concept1_linkmention(ref, renderterm, opts)
|
45
|
-
|
46
|
-
|
49
|
+
(opts[:linkmention] == "true" &&
|
50
|
+
!renderterm.nil? && !ref.nil?) or return
|
47
51
|
ref2 = ref.clone
|
48
52
|
r2 = renderterm.clone
|
49
53
|
renderterm.replace(ref2).children = r2
|
@@ -51,16 +55,14 @@ module IsoDoc
|
|
51
55
|
|
52
56
|
def concept1_ref(_node, ref, opts)
|
53
57
|
ref.nil? and return
|
54
|
-
|
55
|
-
|
58
|
+
opts[:ref] == "false" and return ref.remove
|
56
59
|
r = concept1_ref_content(ref)
|
57
60
|
ref = r.at("./descendant-or-self::xmlns:xref | " \
|
58
61
|
"./descendant-or-self::xmlns:eref | " \
|
59
62
|
"./descendant-or-self::xmlns:termref")
|
60
63
|
%w(xref eref).include? ref&.name and get_linkend(ref)
|
61
|
-
|
64
|
+
opts[:linkref] == "false" && %w(xref eref).include?(ref&.name) and
|
62
65
|
ref.replace(ref.children)
|
63
|
-
end
|
64
66
|
end
|
65
67
|
|
66
68
|
def concept1_ref_content(ref)
|
@@ -92,9 +94,8 @@ module IsoDoc
|
|
92
94
|
|
93
95
|
def designation(docxml)
|
94
96
|
docxml.xpath(ns("//term")).each { |t| merge_second_preferred(t) }
|
95
|
-
docxml.xpath(ns("//preferred | //admitted | //deprecates"))
|
96
|
-
designation1(p)
|
97
|
-
end
|
97
|
+
docxml.xpath(ns("//preferred | //admitted | //deprecates"))
|
98
|
+
.each { |p| designation1(p) }
|
98
99
|
end
|
99
100
|
|
100
101
|
def merge_second_preferred(term)
|
@@ -107,11 +108,10 @@ module IsoDoc
|
|
107
108
|
end
|
108
109
|
|
109
110
|
def merge_second_preferred1(pref, second)
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
end
|
111
|
+
merge_preferred_eligible?(pref, second) or return
|
112
|
+
n1 = pref.at(ns("./expression/name"))
|
113
|
+
n2 = second.remove.at(ns("./expression/name"))
|
114
|
+
n1.children = l10n("#{to_xml(n1.children)}; #{Common::to_xml(n2.children)}")
|
115
115
|
end
|
116
116
|
|
117
117
|
def merge_preferred_eligible?(first, second)
|
@@ -127,7 +127,6 @@ module IsoDoc
|
|
127
127
|
s = desgn.at(ns("./termsource"))
|
128
128
|
name = desgn.at(ns("./expression/name | ./letter-symbol/name | " \
|
129
129
|
"./graphical-symbol")) or return
|
130
|
-
|
131
130
|
designation_annotate(desgn, name)
|
132
131
|
s and desgn.next = s
|
133
132
|
end
|
@@ -151,8 +150,7 @@ module IsoDoc
|
|
151
150
|
def designation_field(desgn, name)
|
152
151
|
f = desgn.xpath(ns("./field-of-application | ./usage-info"))
|
153
152
|
&.map { |u| to_xml(u.children) }&.join(", ")
|
154
|
-
|
155
|
-
|
153
|
+
f&.empty? and return nil
|
156
154
|
name << ", <#{f}>"
|
157
155
|
end
|
158
156
|
|
@@ -173,27 +171,21 @@ module IsoDoc
|
|
173
171
|
loc = [desgn&.at(ns("./expression/@language"))&.text,
|
174
172
|
desgn&.at(ns("./expression/@script"))&.text,
|
175
173
|
desgn&.at(ns("./@geographic-area"))&.text].compact
|
176
|
-
|
177
|
-
|
174
|
+
loc.empty? and return
|
178
175
|
name << ", #{loc.join(' ')}"
|
179
176
|
end
|
180
177
|
|
181
178
|
def designation_pronunciation(desgn, name)
|
182
179
|
f = desgn.at(ns("./expression/pronunciation")) or return
|
183
|
-
|
184
180
|
name << ", /#{to_xml(f.children)}/"
|
185
181
|
end
|
186
182
|
|
187
183
|
def termexample(docxml)
|
188
|
-
docxml.xpath(ns("//termexample")).each
|
189
|
-
example1(f)
|
190
|
-
end
|
184
|
+
docxml.xpath(ns("//termexample")).each { |f| example1(f) }
|
191
185
|
end
|
192
186
|
|
193
187
|
def termnote(docxml)
|
194
|
-
docxml.xpath(ns("//termnote")).each
|
195
|
-
termnote1(f)
|
196
|
-
end
|
188
|
+
docxml.xpath(ns("//termnote")).each { |f| termnote1(f) }
|
197
189
|
end
|
198
190
|
|
199
191
|
def termnote1(elem)
|
@@ -38,15 +38,18 @@ module IsoDoc
|
|
38
38
|
def anchor_xref(node, target)
|
39
39
|
x = @xrefs.anchor(target, :xref)
|
40
40
|
t = @xrefs.anchor(target, :title)
|
41
|
-
case node["style"]
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
41
|
+
ret = case node["style"]
|
42
|
+
when "basic" then t
|
43
|
+
when "full" then anchor_xref_full(x, t)
|
44
|
+
when "short", nil then x
|
45
|
+
else @xrefs.anchor(target, node[:style].to_sym)
|
46
|
+
end
|
47
|
+
ret || x
|
47
48
|
end
|
48
49
|
|
49
50
|
def anchor_xref_full(num, title)
|
51
|
+
(!title.nil? && !title.empty?) or return nil
|
52
|
+
|
50
53
|
l10n("#{num}, #{title}")
|
51
54
|
end
|
52
55
|
|
data/lib/isodoc/version.rb
CHANGED
@@ -19,14 +19,14 @@ module IsoDoc
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def make_body1(body, _docxml)
|
22
|
-
body.div
|
22
|
+
body.div class: "WordSection1" do |div1|
|
23
23
|
div1.p { |p| p << " " } # placeholder
|
24
24
|
end
|
25
25
|
section_break(body)
|
26
26
|
end
|
27
27
|
|
28
28
|
def make_body2(body, docxml)
|
29
|
-
body.div
|
29
|
+
body.div class: "WordSection2" do |div2|
|
30
30
|
boilerplate docxml, div2
|
31
31
|
preface_block docxml, div2
|
32
32
|
abstract docxml, div2
|
@@ -40,7 +40,7 @@ module IsoDoc
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def make_body3(body, docxml)
|
43
|
-
body.div
|
43
|
+
body.div class: "WordSection3" do |div3|
|
44
44
|
middle docxml, div3
|
45
45
|
footnotes div3
|
46
46
|
comments div3
|
@@ -93,7 +93,7 @@ module IsoDoc
|
|
93
93
|
|
94
94
|
def dl_parse_table(node, out)
|
95
95
|
list_title_parse(node, out)
|
96
|
-
out.table
|
96
|
+
out.table class: "dl" do |v|
|
97
97
|
node.elements.select { |n| dt_dd?(n) }
|
98
98
|
.each_slice(2) do |dt, dd|
|
99
99
|
dl_parse_table1(v, dt, dd)
|
@@ -104,10 +104,10 @@ module IsoDoc
|
|
104
104
|
|
105
105
|
def dl_parse_table1(table, dterm, ddefn)
|
106
106
|
table.tr do |tr|
|
107
|
-
tr.td
|
107
|
+
tr.td valign: "top", align: "left" do |term|
|
108
108
|
dt_parse(dterm, term)
|
109
109
|
end
|
110
|
-
tr.td
|
110
|
+
tr.td valign: "top" do |listitem|
|
111
111
|
ddefn.children.each { |n| parse(n, listitem) }
|
112
112
|
end
|
113
113
|
end
|
@@ -118,7 +118,7 @@ module IsoDoc
|
|
118
118
|
return if remainder.empty?
|
119
119
|
|
120
120
|
out.tr do |tr|
|
121
|
-
tr.td
|
121
|
+
tr.td colspan: 2 do |td|
|
122
122
|
remainder.each { |n| parse(n, td) }
|
123
123
|
end
|
124
124
|
end
|
@@ -149,8 +149,8 @@ module IsoDoc
|
|
149
149
|
|
150
150
|
def note_p_parse(node, div)
|
151
151
|
name = node&.at(ns("./name"))&.remove
|
152
|
-
div.p
|
153
|
-
p.span
|
152
|
+
div.p class: "Note" do |p|
|
153
|
+
p.span class: "note_label" do |s|
|
154
154
|
name&.children&.each { |n| parse(n, s) }
|
155
155
|
end
|
156
156
|
insert_tab(p, 1)
|
@@ -161,8 +161,8 @@ module IsoDoc
|
|
161
161
|
|
162
162
|
def note_parse1(node, div)
|
163
163
|
name = node&.at(ns("./name"))&.remove
|
164
|
-
div.p
|
165
|
-
p.span
|
164
|
+
div.p class: "Note" do |p|
|
165
|
+
p.span class: "note_label" do |s|
|
166
166
|
name&.children&.each { |n| parse(n, s) }
|
167
167
|
end
|
168
168
|
insert_tab(p, 1)
|
@@ -173,7 +173,7 @@ module IsoDoc
|
|
173
173
|
def termnote_parse(node, out)
|
174
174
|
name = node&.at(ns("./name"))&.remove
|
175
175
|
out.div **note_attrs(node) do |div|
|
176
|
-
div.p
|
176
|
+
div.p class: "Note" do |p|
|
177
177
|
if name
|
178
178
|
name.children.each { |n| parse(n, p) }
|
179
179
|
p << termnote_delim
|
@@ -196,10 +196,10 @@ module IsoDoc
|
|
196
196
|
|
197
197
|
def example_table_attr(node)
|
198
198
|
super.merge(
|
199
|
-
style: "mso-table-lspace:15.0cm;margin-left:423.0pt;"\
|
200
|
-
"mso-table-rspace:15.0cm;margin-right:423.0pt;"\
|
201
|
-
"mso-table-anchor-horizontal:column;"\
|
202
|
-
"mso-table-overlap:never;border-collapse:collapse;"\
|
199
|
+
style: "mso-table-lspace:15.0cm;margin-left:423.0pt;" \
|
200
|
+
"mso-table-rspace:15.0cm;margin-right:423.0pt;" \
|
201
|
+
"mso-table-anchor-horizontal:column;" \
|
202
|
+
"mso-table-overlap:never;border-collapse:collapse;" \
|
203
203
|
"#{keep_style(node)}",
|
204
204
|
)
|
205
205
|
end
|
@@ -1,32 +1,15 @@
|
|
1
1
|
require "fileutils"
|
2
2
|
require_relative "./postprocess_cover"
|
3
|
+
require_relative "./postprocess_toc"
|
3
4
|
|
4
5
|
module IsoDoc
|
5
6
|
module WordFunction
|
6
7
|
module Postprocess
|
7
|
-
# add namespaces for Word fragments
|
8
|
-
WORD_NOKOHEAD = <<~HERE.freeze
|
9
|
-
<!DOCTYPE html SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
10
|
-
<html xmlns="http://www.w3.org/1999/xhtml"
|
11
|
-
xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"
|
12
|
-
xmlns:w="urn:schemas-microsoft-com:office:word"
|
13
|
-
xmlns:m="http://schemas.microsoft.com/office/2004/12/omml">
|
14
|
-
<head> <title></title> <meta charset="UTF-8" /> </head>
|
15
|
-
<body> </body> </html>
|
16
|
-
HERE
|
17
|
-
|
18
|
-
def to_word_xhtml_fragment(xml)
|
19
|
-
doc = ::Nokogiri::XML.parse(WORD_NOKOHEAD)
|
20
|
-
::Nokogiri::XML::DocumentFragment.new(doc, xml, doc.root)
|
21
|
-
end
|
22
|
-
|
23
8
|
def table_note_cleanup(docxml)
|
24
9
|
super
|
25
10
|
# preempt html2doc putting MsoNormal there
|
26
11
|
docxml.xpath("//p[not(self::*[@class])][ancestor::*[@class = 'Note']]")
|
27
|
-
.each
|
28
|
-
p["class"] = "Note"
|
29
|
-
end
|
12
|
+
.each { |p| p["class"] = "Note" }
|
30
13
|
end
|
31
14
|
|
32
15
|
def postprocess(result, filename, dir)
|
@@ -52,31 +35,23 @@ module IsoDoc
|
|
52
35
|
@wordstylesheet.unlink if @wordstylesheet.is_a?(Tempfile)
|
53
36
|
end
|
54
37
|
|
55
|
-
def
|
56
|
-
|
57
|
-
|
58
|
-
f = File.open(@wordstylesheet.path, "a")
|
59
|
-
@landscapestyle.empty? or f.write(@landscapestyle)
|
60
|
-
if @wordstylesheet_override && @wordstylesheet
|
61
|
-
f.write(@wordstylesheet_override.read)
|
62
|
-
@wordstylesheet_override.close
|
63
|
-
elsif @wordstylesheet_override && !@wordstylesheet
|
64
|
-
@wordstylesheet = @wordstylesheet_override
|
65
|
-
end
|
66
|
-
f.close
|
67
|
-
@wordstylesheet
|
38
|
+
def sourcecode_style
|
39
|
+
"Sourcecode"
|
68
40
|
end
|
69
41
|
|
70
42
|
def word_admonition_images(docxml)
|
71
43
|
docxml.xpath("//div[@class = 'Admonition']//img").each do |i|
|
72
44
|
i["width"], i["height"] =
|
73
|
-
Html2Doc.new({}).image_resize(i, image_localfile(i), @maxheight,
|
45
|
+
Html2Doc.new({}).image_resize(i, image_localfile(i), @maxheight,
|
46
|
+
300)
|
74
47
|
end
|
75
48
|
end
|
76
49
|
|
77
50
|
def word_cleanup(docxml)
|
78
51
|
word_annex_cleanup(docxml)
|
79
52
|
word_preface(docxml)
|
53
|
+
word_sourcecode_annotations(docxml)
|
54
|
+
word_sourcecode_table(docxml)
|
80
55
|
word_nested_tables(docxml)
|
81
56
|
word_colgroup(docxml)
|
82
57
|
word_table_align(docxml)
|
@@ -93,6 +68,38 @@ module IsoDoc
|
|
93
68
|
docxml
|
94
69
|
end
|
95
70
|
|
71
|
+
def word_sourcecode_annotations(html)
|
72
|
+
ann = ".//div[@class = 'annotation']"
|
73
|
+
html.xpath("//p[@class = '#{sourcecode_style}'][#{ann}]")
|
74
|
+
.each do |p|
|
75
|
+
ins = p.after("<p class='#{sourcecode_style}'/>").next_element
|
76
|
+
p.xpath(ann).each do |d|
|
77
|
+
ins << d.remove.children
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def word_sourcecode_table(docxml)
|
83
|
+
s = "p[@class='#{sourcecode_style}']"
|
84
|
+
docxml.xpath("//#{s}/div[@class='table_container']").each do |d|
|
85
|
+
pre = d.at(".//#{s}")
|
86
|
+
to_sourcecode_para(pre)
|
87
|
+
d["id"] = d.parent["id"]
|
88
|
+
d.parent.replace(d)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_sourcecode_para(pre)
|
93
|
+
@sourcecode = "pre"
|
94
|
+
pre.traverse do |x|
|
95
|
+
x.text? or next
|
96
|
+
ret = []
|
97
|
+
text_parse(x, ret)
|
98
|
+
x.replace(ret.join)
|
99
|
+
end
|
100
|
+
@sourcecode = false
|
101
|
+
end
|
102
|
+
|
96
103
|
def word_tab_clean(docxml)
|
97
104
|
docxml.xpath("//p[@class='Biblio']//span[@style='mso-tab-count:1']")
|
98
105
|
.each do |s|
|
@@ -144,8 +151,7 @@ module IsoDoc
|
|
144
151
|
end
|
145
152
|
|
146
153
|
def style_update(node, css)
|
147
|
-
|
148
|
-
|
154
|
+
node or return
|
149
155
|
node["style"] =
|
150
156
|
node["style"] ? node["style"].sub(/;?$/, ";#{css}") : css
|
151
157
|
end
|
@@ -153,11 +159,11 @@ module IsoDoc
|
|
153
159
|
def word_image_caption(docxml)
|
154
160
|
docxml.xpath("//p[@class = 'FigureTitle' or @class = 'SourceTitle']")
|
155
161
|
.each do |t|
|
156
|
-
if t
|
162
|
+
if t.previous_element&.name == "img"
|
157
163
|
img = t.previous_element
|
158
|
-
t.previous_element.swap("<p class
|
164
|
+
t.previous_element.swap("<p class='figure'>#{img.to_xml}</p>")
|
159
165
|
end
|
160
|
-
style_update(t
|
166
|
+
style_update(t.previous_element, "page-break-after:avoid;")
|
161
167
|
end
|
162
168
|
end
|
163
169
|
|
@@ -184,16 +190,14 @@ module IsoDoc
|
|
184
190
|
|
185
191
|
def word_table_align(docxml)
|
186
192
|
docxml.xpath("//td[@align]/p | //th[@align]/p").each do |p|
|
187
|
-
|
188
|
-
|
193
|
+
p["align"] and next
|
189
194
|
style_update(p, "text-align: #{p.parent['align']}")
|
190
195
|
end
|
191
196
|
end
|
192
197
|
|
193
198
|
def word_table_separator(docxml)
|
194
199
|
docxml.xpath("//p[@class = 'TableTitle']").each do |t|
|
195
|
-
|
196
|
-
|
200
|
+
t.children.empty? or next
|
197
201
|
t["style"] = t["style"].sub(/;?$/, ";font-size:0pt;")
|
198
202
|
t.children = " "
|
199
203
|
end
|
@@ -231,7 +235,7 @@ module IsoDoc
|
|
231
235
|
docxml.xpath("//a[@epub:type = 'footnote']").each do |x|
|
232
236
|
footnote_reference_format(x)
|
233
237
|
end
|
234
|
-
docxml.xpath("//a[@class = 'TableFootnoteRef'] | "\
|
238
|
+
docxml.xpath("//a[@class = 'TableFootnoteRef'] | " \
|
235
239
|
"//span[@class = 'TableFootnoteRef']").each do |x|
|
236
240
|
table_footnote_reference_format(x)
|
237
241
|
end
|
@@ -23,164 +23,36 @@ module IsoDoc
|
|
23
23
|
introxml.to_xml(encoding: "US-ASCII")
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
<<~TOC
|
54
|
-
<span lang="EN-GB"><span style='mso-element:field-begin'></span><span
|
55
|
-
style='mso-spacerun:yes'> </span>TOC \\o "1-#{level}" \\h \\z \\u <span
|
56
|
-
style='mso-element:field-separator'></span></span>
|
57
|
-
TOC
|
58
|
-
end
|
59
|
-
|
60
|
-
WORD_TOC_SUFFIX1 = <<~TOC.freeze
|
61
|
-
<p class="MsoToc1"><span lang="EN-GB"><span
|
62
|
-
style='mso-element:field-end'></span></span><span
|
63
|
-
lang="EN-GB"><o:p> </o:p></span></p>
|
64
|
-
TOC
|
65
|
-
|
66
|
-
def make_WordToC(docxml, level)
|
67
|
-
toc = ""
|
68
|
-
# docxml.xpath("//h1 | //h2[not(ancestor::*[@class = 'Section3'])]").
|
69
|
-
xpath = (1..level).each.map { |i| "//h#{i}" }.join (" | ")
|
70
|
-
docxml.xpath(xpath).each do |h|
|
71
|
-
toc += word_toc_entry(h.name[1].to_i, header_strip(h))
|
72
|
-
end
|
73
|
-
toc.sub(/(<p class="MsoToc1">)/,
|
74
|
-
%{\\1#{word_toc_preface(level)}}) + WORD_TOC_SUFFIX1
|
75
|
-
end
|
76
|
-
|
77
|
-
# inheriting gems need to add native Word name of style, if different
|
78
|
-
# including both CSS style name and human readable style name.
|
79
|
-
# Any human readable style name needs to come first for the Word template
|
80
|
-
# to work in regenerating the ToC
|
81
|
-
def table_toc_class
|
82
|
-
%w(TableTitle tabletitle)
|
83
|
-
end
|
84
|
-
|
85
|
-
def figure_toc_class
|
86
|
-
%w(FigureTitle figuretitle)
|
87
|
-
end
|
88
|
-
|
89
|
-
def reqt_toc_class
|
90
|
-
%w(RecommendationTitle RecommendationTestTitle
|
91
|
-
recommendationtitle recommendationtesttitle)
|
92
|
-
end
|
93
|
-
|
94
|
-
def toc_word_class_list(classes)
|
95
|
-
classes.map do |x|
|
96
|
-
/ /.match?(x) ? %("#{x}") : x
|
97
|
-
end.join(",")
|
98
|
-
end
|
99
|
-
|
100
|
-
def word_toc_reqt_preface1
|
101
|
-
<<~TOC
|
102
|
-
<span lang="EN-GB"><span style='mso-element:field-begin'></span><span
|
103
|
-
style='mso-spacerun:yes'> </span>TOC \\h \\z \\t #{toc_word_class_list reqt_toc_class}
|
104
|
-
<span style='mso-element:field-separator'></span></span>
|
105
|
-
TOC
|
106
|
-
end
|
107
|
-
|
108
|
-
def word_toc_table_preface1
|
109
|
-
<<~TOC
|
110
|
-
<span lang="EN-GB"><span style='mso-element:field-begin'></span><span style='mso-spacerun:yes'> </span>TOC
|
111
|
-
\\h \\z \\t #{toc_word_class_list table_toc_class} <span style='mso-element:field-separator'></span></span>
|
112
|
-
TOC
|
113
|
-
end
|
114
|
-
|
115
|
-
def word_toc_figure_preface1
|
116
|
-
<<~TOC
|
117
|
-
<span lang="EN-GB"><span style='mso-element:field-begin'></span><span style='mso-spacerun:yes'> </span>TOC
|
118
|
-
\\h \\z \\t #{toc_word_class_list figure_toc_class} <span style='mso-element:field-separator'></span></span>
|
119
|
-
TOC
|
120
|
-
end
|
121
|
-
|
122
|
-
def table_toc_xpath
|
123
|
-
attr = table_toc_class.map { |x| "@class = '#{x}'" }
|
124
|
-
"//p[#{attr.join(' or ')}]"
|
125
|
-
end
|
126
|
-
|
127
|
-
def make_table_word_toc(docxml)
|
128
|
-
(docxml.at(table_toc_xpath) && @toctablestitle) or return ""
|
129
|
-
toc = %{<p class="TOCTitle">#{@toctablestitle}</p>}
|
130
|
-
docxml.xpath(table_toc_xpath).each do |h|
|
131
|
-
toc += word_toc_entry(1, header_strip(h))
|
132
|
-
end
|
133
|
-
toc.sub(/(<p class="MsoToc1">)/,
|
134
|
-
%{\\1#{word_toc_table_preface1}}) + WORD_TOC_SUFFIX1
|
135
|
-
end
|
136
|
-
|
137
|
-
def figure_toc_xpath
|
138
|
-
attr = figure_toc_class.map { |x| "@class = '#{x}'" }
|
139
|
-
"//p[#{attr.join(' or ')}]"
|
140
|
-
end
|
141
|
-
|
142
|
-
def make_figure_word_toc(docxml)
|
143
|
-
(docxml.at(figure_toc_xpath) && @tocfigurestitle) or return ""
|
144
|
-
toc = %{<p class="TOCTitle">#{@tocfigurestitle}</p>}
|
145
|
-
docxml.xpath(figure_toc_xpath).each do |h|
|
146
|
-
toc += word_toc_entry(1, header_strip(h))
|
147
|
-
end
|
148
|
-
toc.sub(/(<p class="MsoToc1">)/,
|
149
|
-
%{\\1#{word_toc_figure_preface1}}) + WORD_TOC_SUFFIX1
|
150
|
-
end
|
151
|
-
|
152
|
-
def reqt_toc_xpath
|
153
|
-
attr = reqt_toc_class.map { |x| "@class = '#{x}'" }
|
154
|
-
"//p[#{attr.join(' or ')}]"
|
155
|
-
end
|
156
|
-
|
157
|
-
def make_recommendation_word_toc(docxml)
|
158
|
-
(docxml.at(reqt_toc_xpath) && @tocrecommendationstitle) or return ""
|
159
|
-
toc = %{<p class="TOCTitle">#{@tocrecommendationstitle}</p>}
|
160
|
-
docxml.xpath(reqt_toc_xpath).sort_by do |h|
|
161
|
-
recommmendation_sort_key(h.text)
|
162
|
-
end.each do |h|
|
163
|
-
toc += word_toc_entry(1, header_strip(h))
|
164
|
-
end
|
165
|
-
toc.sub(/(<p class="MsoToc1">)/,
|
166
|
-
%{\\1#{word_toc_reqt_preface1}}) + WORD_TOC_SUFFIX1
|
167
|
-
end
|
168
|
-
|
169
|
-
def recommmendation_sort_key(header)
|
170
|
-
m = /^([^0-9]+) (\d+)/.match(header) || /^([^:]+)/.match(header)
|
171
|
-
m ||= [header, nil]
|
172
|
-
ret = "#{recommmendation_sort_key1(m[1])}::"
|
173
|
-
m[2] and ret += ("%04d" % m[2].to_i).to_s
|
174
|
-
ret
|
175
|
-
end
|
176
|
-
|
177
|
-
def recommmendation_sort_key1(type)
|
178
|
-
case type&.downcase
|
179
|
-
when "requirement" then "04"
|
180
|
-
when "recommendation" then "05"
|
181
|
-
when "permission" then "06"
|
182
|
-
else type
|
26
|
+
# add namespaces for Word fragments
|
27
|
+
WORD_NOKOHEAD = <<~HERE.freeze
|
28
|
+
<!DOCTYPE html SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
29
|
+
<html xmlns="http://www.w3.org/1999/xhtml"
|
30
|
+
xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"
|
31
|
+
xmlns:w="urn:schemas-microsoft-com:office:word"
|
32
|
+
xmlns:m="http://schemas.microsoft.com/office/2004/12/omml">
|
33
|
+
<head> <title></title> <meta charset="UTF-8" /> </head>
|
34
|
+
<body> </body> </html>
|
35
|
+
HERE
|
36
|
+
|
37
|
+
def to_word_xhtml_fragment(xml)
|
38
|
+
doc = ::Nokogiri::XML.parse(WORD_NOKOHEAD)
|
39
|
+
::Nokogiri::XML::DocumentFragment.new(doc, xml, doc.root)
|
40
|
+
end
|
41
|
+
|
42
|
+
def wordstylesheet_update
|
43
|
+
@wordstylesheet.nil? and return
|
44
|
+
f = File.open(@wordstylesheet.path, "a")
|
45
|
+
@landscapestyle.empty? or f.write(@landscapestyle)
|
46
|
+
s = @meta.get[:code_css] and
|
47
|
+
f.write(s.gsub(/sourcecode/, "p.#{sourcecode_style}"))
|
48
|
+
if @wordstylesheet_override && @wordstylesheet
|
49
|
+
f.write(@wordstylesheet_override.read)
|
50
|
+
@wordstylesheet_override.close
|
51
|
+
elsif @wordstylesheet_override && !@wordstylesheet
|
52
|
+
@wordstylesheet = @wordstylesheet_override
|
183
53
|
end
|
54
|
+
f.close
|
55
|
+
@wordstylesheet
|
184
56
|
end
|
185
57
|
|
186
58
|
def authority_cleanup1(docxml, klass)
|