isodoc 2.4.0 → 2.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/isodoc.gemspec +1 -0
  3. data/lib/isodoc/base_style/all.css +29 -0
  4. data/lib/isodoc/base_style/metanorma_word.css +9 -0
  5. data/lib/isodoc/base_style/metanorma_word.scss +11 -0
  6. data/lib/isodoc/base_style/reset.css +29 -0
  7. data/lib/isodoc/base_style/reset.scss +34 -0
  8. data/lib/isodoc/base_style/rouge.css +39 -0
  9. data/lib/isodoc/base_style/typography.scss +6 -3
  10. data/lib/isodoc/convert.rb +7 -4
  11. data/lib/isodoc/function/blocks.rb +26 -16
  12. data/lib/isodoc/function/inline.rb +17 -17
  13. data/lib/isodoc/function/references.rb +38 -52
  14. data/lib/isodoc/function/table.rb +22 -13
  15. data/lib/isodoc/function/to_word_html.rb +1 -4
  16. data/lib/isodoc/function/utils.rb +5 -1
  17. data/lib/isodoc/html_function/html.rb +13 -34
  18. data/lib/isodoc/html_function/postprocess.rb +14 -1
  19. data/lib/isodoc/html_function/postprocess_cover.rb +6 -9
  20. data/lib/isodoc/metadata.rb +5 -0
  21. data/lib/isodoc/presentation_function/block.rb +15 -46
  22. data/lib/isodoc/presentation_function/refs.rb +75 -3
  23. data/lib/isodoc/presentation_function/sourcecode.rb +114 -0
  24. data/lib/isodoc/presentation_function/terms.rb +29 -37
  25. data/lib/isodoc/presentation_function/xrefs.rb +9 -6
  26. data/lib/isodoc/version.rb +1 -1
  27. data/lib/isodoc/word_function/body.rb +16 -16
  28. data/lib/isodoc/word_function/postprocess.rb +47 -43
  29. data/lib/isodoc/word_function/postprocess_cover.rb +29 -157
  30. data/lib/isodoc/word_function/postprocess_toc.rb +165 -0
  31. data/lib/isodoc/word_function/table.rb +25 -13
  32. data/lib/isodoc/xref/xref_gen.rb +2 -4
  33. 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 node.at(ns("//definitions//dt[@id = '#{xref}']"))
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
- concept1_nonital(node, opts)
27
+ concept1_style(node, opts)
27
28
  node.replace(node.children)
28
29
  end
29
30
 
30
- def concept1_nonital(node, opts)
31
- opts[:ital] == "false" or return
32
- r = node.at(ns(".//renderterm"))
33
- r&.replace(r&.children)
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).each_with_object({}) do |x, m|
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
- return unless opts[:linkmention] == "true" && !renderterm.nil? && !ref.nil?
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
- return ref.remove if opts[:ref] == "false"
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
- if opts[:linkref] == "false" && %w(xref eref).include?(ref&.name)
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")).each do |p|
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
- if merge_preferred_eligible?(pref, second)
111
- n1 = pref.at(ns("./expression/name"))
112
- n2 = second.remove.at(ns("./expression/name"))
113
- n1.children = l10n("#{to_xml(n1.children)}; #{Common::to_xml(n2.children)}")
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
- return nil if f&.empty?
155
-
153
+ f&.empty? and return nil
156
154
  name << ", &#x3c;#{f}&#x3e;"
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
- return if loc.empty?
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 do |f|
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 do |f|
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
- when "basic" then t || x
43
- when "full" then t ? anchor_xref_full(x, t) : x
44
- when "short", nil then x
45
- else @xrefs.anchor(target, node[:style].to_sym)
46
- end
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
 
@@ -1,3 +1,3 @@
1
1
  module IsoDoc
2
- VERSION = "2.4.0".freeze
2
+ VERSION = "2.4.2".freeze
3
3
  end
@@ -19,14 +19,14 @@ module IsoDoc
19
19
  end
20
20
 
21
21
  def make_body1(body, _docxml)
22
- body.div **{ class: "WordSection1" } do |div1|
22
+ body.div class: "WordSection1" do |div1|
23
23
  div1.p { |p| p << "&#xa0;" } # placeholder
24
24
  end
25
25
  section_break(body)
26
26
  end
27
27
 
28
28
  def make_body2(body, docxml)
29
- body.div **{ class: "WordSection2" } do |div2|
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 **{ class: "WordSection3" } do |div3|
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 **{ class: "dl" } do |v|
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 **{ valign: "top", align: "left" } do |term|
107
+ tr.td valign: "top", align: "left" do |term|
108
108
  dt_parse(dterm, term)
109
109
  end
110
- tr.td **{ valign: "top" } do |listitem|
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 **{ colspan: 2 } do |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 **{ class: "Note" } do |p|
153
- p.span **{ class: "note_label" } do |s|
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 **{ class: "Note" } do |p|
165
- p.span **{ class: "note_label" } do |s|
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 **{ class: "Note" } do |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 do |p|
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 wordstylesheet_update
56
- return if @wordstylesheet.nil?
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, 300)
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
- return unless node
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&.previous_element&.name == "img"
162
+ if t.previous_element&.name == "img"
157
163
  img = t.previous_element
158
- t.previous_element.swap("<p class=\'figure\'>#{img.to_xml}</p>")
164
+ t.previous_element.swap("<p class='figure'>#{img.to_xml}</p>")
159
165
  end
160
- style_update(t&.previous_element, "page-break-after:avoid;")
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
- next if p["align"]
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
- next unless t.children.empty?
196
-
200
+ t.children.empty? or next
197
201
  t["style"] = t["style"].sub(/;?$/, ";font-size:0pt;")
198
202
  t.children = "&#xa0;"
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
- def insert_toc(intro, docxml, level)
27
- toc = ""
28
- toc += make_WordToC(docxml, level)
29
- toc += make_table_word_toc(docxml)
30
- toc += make_figure_word_toc(docxml)
31
- toc += make_recommendation_word_toc(docxml)
32
- intro.sub(/WORDTOC/, toc)
33
- end
34
-
35
- def word_toc_entry(toclevel, heading)
36
- bookmark = bookmarkid # Random.rand(1000000000)
37
- <<~TOC
38
- <p class="MsoToc#{toclevel}"><span class="MsoHyperlink"><span lang="EN-GB" style='mso-no-proof:yes'>
39
- <a href="#_Toc#{bookmark}">#{heading}<span lang="EN-GB" class="MsoTocTextSpan">
40
- <span style='mso-tab-count:1 dotted'>. </span>
41
- </span><span lang="EN-GB" class="MsoTocTextSpan">
42
- <span style='mso-element:field-begin'></span></span>
43
- <span lang="EN-GB" class="MsoTocTextSpan"> PAGEREF _Toc#{bookmark} \\h </span>
44
- <span lang="EN-GB" class="MsoTocTextSpan"><span style='mso-element:field-separator'></span></span><span
45
- lang="EN-GB" class="MsoTocTextSpan">1</span>
46
- <span lang="EN-GB" class="MsoTocTextSpan"></span><span
47
- lang="EN-GB" class="MsoTocTextSpan"><span style='mso-element:field-end'></span></span></a></span></span></p>
48
-
49
- TOC
50
- end
51
-
52
- def word_toc_preface(level)
53
- <<~TOC
54
- <span lang="EN-GB"><span style='mso-element:field-begin'></span><span
55
- style='mso-spacerun:yes'>&#xA0;</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>&#xA0;</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) ? %(&quot;#{x}&quot;) : 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'>&#xA0;</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'>&#xA0;</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'>&#xA0;</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)