isodoc 2.4.0 → 2.4.2

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.
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)