isodoc 2.4.1 → 2.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/lib/isodoc/base_style/all.css +29 -0
  3. data/lib/isodoc/base_style/metanorma_word.css +9 -0
  4. data/lib/isodoc/base_style/metanorma_word.scss +11 -0
  5. data/lib/isodoc/base_style/reset.css +29 -0
  6. data/lib/isodoc/base_style/reset.scss +34 -0
  7. data/lib/isodoc/base_style/rouge.css +39 -0
  8. data/lib/isodoc/base_style/typography.scss +1 -1
  9. data/lib/isodoc/convert.rb +10 -3
  10. data/lib/isodoc/function/blocks.rb +29 -16
  11. data/lib/isodoc/function/inline.rb +13 -13
  12. data/lib/isodoc/function/inline_simple.rb +1 -1
  13. data/lib/isodoc/function/references.rb +17 -38
  14. data/lib/isodoc/function/table.rb +1 -1
  15. data/lib/isodoc/function/to_word_html.rb +0 -4
  16. data/lib/isodoc/function/utils.rb +6 -2
  17. data/lib/isodoc/html_function/html.rb +13 -13
  18. data/lib/isodoc/html_function/postprocess.rb +14 -1
  19. data/lib/isodoc/metadata.rb +1 -1
  20. data/lib/isodoc/presentation_function/bibdata.rb +3 -3
  21. data/lib/isodoc/presentation_function/block.rb +1 -98
  22. data/lib/isodoc/presentation_function/math.rb +15 -4
  23. data/lib/isodoc/presentation_function/sourcecode.rb +122 -0
  24. data/lib/isodoc/presentation_function/terms.rb +14 -27
  25. data/lib/isodoc/presentation_xml_convert.rb +38 -0
  26. data/lib/isodoc/version.rb +1 -1
  27. data/lib/isodoc/word_function/body.rb +19 -19
  28. data/lib/isodoc/word_function/comments.rb +23 -18
  29. data/lib/isodoc/word_function/footnotes.rb +8 -8
  30. data/lib/isodoc/word_function/postprocess.rb +25 -118
  31. data/lib/isodoc/word_function/postprocess_cover.rb +29 -157
  32. data/lib/isodoc/word_function/postprocess_table.rb +85 -0
  33. data/lib/isodoc/word_function/postprocess_toc.rb +165 -0
  34. data/lib/isodoc/word_function/table.rb +34 -15
  35. data/lib/isodoc/xref/xref_gen.rb +2 -4
  36. metadata +6 -2
@@ -4,7 +4,7 @@ module IsoDoc
4
4
  def comments(div)
5
5
  return if @comments.empty?
6
6
 
7
- div.div **{ style: "mso-element:comment-list" } do |div1|
7
+ div.div style: "mso-element:comment-list" do |div1|
8
8
  @comments.each { |fn| div1.parent << fn }
9
9
  end
10
10
  end
@@ -26,28 +26,27 @@ module IsoDoc
26
26
  # add in from and to links to move the comment into place
27
27
  def make_comment_link(out, fnote, node)
28
28
  out.span(**comment_link_attrs(fnote, node)) do |s1|
29
- s1.span **{ lang: "EN-GB", style: "font-size:9.0pt" } do |s2|
30
- s2.a **{ style: "mso-comment-reference:SMC_#{fnote};"\
29
+ s1.span lang: "EN-GB", style: "font-size:9.0pt" do |s2|
30
+ s2.a style: "mso-comment-reference:SMC_#{fnote};" \
31
31
  "mso-comment-date:#{node['date'].gsub(/[:-]+/,
32
- '')}" }
33
- s2.span **{ style: "mso-special-character:comment",
34
- target: fnote } # do |s|
32
+ '')}"
33
+ s2.span style: "mso-special-character:comment", target: fnote # do |s|
35
34
  end
36
35
  end
37
36
  end
38
37
 
39
38
  def make_comment_target(out)
40
- out.span **{ style: "MsoCommentReference" } do |s1|
41
- s1.span **{ lang: "EN-GB", style: "font-size:9.0pt" } do |s2|
42
- s2.span **{ style: "mso-special-character:comment" }
39
+ out.span style: "MsoCommentReference" do |s1|
40
+ s1.span lang: "EN-GB", style: "font-size:9.0pt" do |s2|
41
+ s2.span style: "mso-special-character:comment"
43
42
  end
44
43
  end
45
44
  end
46
45
 
47
46
  def make_comment_text(node, fnote)
48
47
  noko do |xml|
49
- xml.div **{ style: "mso-element:comment", id: fnote } do |div|
50
- div.span **{ style: %{mso-comment-author:"#{node['reviewer']}"} }
48
+ xml.div style: "mso-element:comment", id: fnote do |div|
49
+ div.span style: %{mso-comment-author:"#{node['reviewer']}"}
51
50
  make_comment_target(div)
52
51
  node.children.each { |n| parse(n, div) }
53
52
  end
@@ -61,7 +60,7 @@ module IsoDoc
61
60
  end
62
61
 
63
62
  COMMENT_IN_COMMENT_LIST1 =
64
- '//div[@style="mso-element:comment-list"]//'\
63
+ '//div[@style="mso-element:comment-list"]//' \
65
64
  'span[@style="MsoCommentReference"]'.freeze
66
65
 
67
66
  def embed_comment_in_comment_list(docxml)
@@ -80,18 +79,24 @@ module IsoDoc
80
79
  link.children = fromlink
81
80
  end
82
81
 
83
- def comment_attributes(docxml, x)
84
- fromlink = docxml.at("//*[@id='#{x['from']}']")
82
+ def comment_attributes(docxml, span)
83
+ fromlink = docxml.at("//*[@id='#{span['from']}']")
85
84
  return(nil) if fromlink.nil?
86
85
 
87
- tolink = docxml.at("//*[@id='#{x['to']}']") || fromlink
88
- target = docxml.at("//*[@id='#{x['target']}']")
86
+ tolink = docxml.at("//*[@id='#{span['to']}']") || fromlink
87
+ target = docxml.at("//*[@id='#{span['target']}']")
89
88
  { from: fromlink, to: tolink, target: target }
90
89
  end
91
90
 
92
91
  def wrap_comment_cont(from, target)
93
- s = from.replace("<span style='mso-comment-continuation:#{target}'>")
94
- s.first.children = from
92
+ if %w(ol ul li div p).include?(from.name)
93
+ from.children.each do |c|
94
+ wrap_comment_cont(c, target)
95
+ end
96
+ else
97
+ s = from.replace("<span style='mso-comment-continuation:#{target}'>")
98
+ s.first.children = from
99
+ end
95
100
  end
96
101
 
97
102
  def skip_comment_wrap(from)
@@ -45,7 +45,7 @@ module IsoDoc
45
45
 
46
46
  def make_generic_footnote_text(node, fnid)
47
47
  noko do |xml|
48
- xml.aside **{ id: "ftn#{fnid}" } do |div|
48
+ xml.aside id: "ftn#{fnid}" do |div|
49
49
  node.children.each { |n| parse(n, div) }
50
50
  end
51
51
  end.join("\n")
@@ -72,13 +72,13 @@ module IsoDoc
72
72
  end
73
73
 
74
74
  def seen_footnote_parse(_node, out, footnote)
75
- out.span **{ style: "mso-element:field-begin" }
75
+ out.span style: "mso-element:field-begin"
76
76
  out << " NOTEREF _Ref#{@fn_bookmarks[footnote]} \\f \\h"
77
- out.span **{ style: "mso-element:field-separator" }
78
- out.span **{ class: "MsoFootnoteReference" } do |s|
77
+ out.span style: "mso-element:field-separator"
78
+ out.span class: "MsoFootnoteReference" do |s|
79
79
  s << footnote
80
80
  end
81
- out.span **{ style: "mso-element:field-end" }
81
+ out.span style: "mso-element:field-end"
82
82
  end
83
83
 
84
84
  def footnote_parse(node, out)
@@ -89,9 +89,9 @@ module IsoDoc
89
89
  return seen_footnote_parse(node, out, fn) if @seen_footnote.include?(fn)
90
90
 
91
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|
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
95
  a.sup { |sup| sup << fn }
96
96
  end
97
97
  end
@@ -1,34 +1,11 @@
1
1
  require "fileutils"
2
2
  require_relative "./postprocess_cover"
3
+ require_relative "./postprocess_toc"
4
+ require_relative "./postprocess_table"
3
5
 
4
6
  module IsoDoc
5
7
  module WordFunction
6
8
  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
- def table_note_cleanup(docxml)
24
- super
25
- # preempt html2doc putting MsoNormal there
26
- docxml.xpath("//p[not(self::*[@class])][ancestor::*[@class = 'Note']]")
27
- .each do |p|
28
- p["class"] = "Note"
29
- end
30
- end
31
-
32
9
  def postprocess(result, filename, dir)
33
10
  filename = filename.sub(/\.doc$/, "")
34
11
  header = generate_header(filename, dir)
@@ -56,23 +33,6 @@ module IsoDoc
56
33
  "Sourcecode"
57
34
  end
58
35
 
59
- def wordstylesheet_update
60
- return if @wordstylesheet.nil?
61
-
62
- f = File.open(@wordstylesheet.path, "a")
63
- @landscapestyle.empty? or f.write(@landscapestyle)
64
- s = @meta.get[:code_css] and
65
- f.write(s.gsub(/sourcecode/, "p.#{sourcecode_style}"))
66
- if @wordstylesheet_override && @wordstylesheet
67
- f.write(@wordstylesheet_override.read)
68
- @wordstylesheet_override.close
69
- elsif @wordstylesheet_override && !@wordstylesheet
70
- @wordstylesheet = @wordstylesheet_override
71
- end
72
- f.close
73
- @wordstylesheet
74
- end
75
-
76
36
  def word_admonition_images(docxml)
77
37
  docxml.xpath("//div[@class = 'Admonition']//img").each do |i|
78
38
  i["width"], i["height"] =
@@ -84,10 +44,12 @@ module IsoDoc
84
44
  def word_cleanup(docxml)
85
45
  word_annex_cleanup(docxml)
86
46
  word_preface(docxml)
47
+ word_sourcecode_annotations(docxml)
87
48
  word_sourcecode_table(docxml)
88
49
  word_nested_tables(docxml)
89
50
  word_colgroup(docxml)
90
51
  word_table_align(docxml)
52
+ word_table_pagebreak(docxml)
91
53
  word_table_separator(docxml)
92
54
  word_admonition_images(docxml)
93
55
  word_list_continuations(docxml)
@@ -101,18 +63,29 @@ module IsoDoc
101
63
  docxml
102
64
  end
103
65
 
104
- def word_sourcecode_table(docxml)
105
- docxml.xpath("//p[@class='Sourcecode']/div[@class='table_container']")
106
- .each do |d|
107
- pre = d.at(".//p[@class='Sourcecode']")
108
- to_sourcecode_para(pre)
109
- d["id"] = d.parent["id"]
110
- d.parent.replace(d)
66
+ def word_sourcecode_annotations(html)
67
+ ann = ".//div[@class = 'annotation']"
68
+ html.xpath("//p[@class = '#{sourcecode_style}'][#{ann}]")
69
+ .each do |p|
70
+ ins = p.after("<p class='#{sourcecode_style}'/>").next_element
71
+ p.xpath(ann).each do |d|
72
+ ins << d.remove.children
111
73
  end
74
+ end
75
+ end
76
+
77
+ def word_sourcecode_table(docxml)
78
+ s = "p[@class='#{sourcecode_style}']"
79
+ docxml.xpath("//#{s}/div[@class='table_container']").each do |d|
80
+ pre = d.at(".//#{s}")
81
+ to_sourcecode_para(pre)
82
+ d["id"] = d.parent["id"]
83
+ d.parent.replace(d)
84
+ end
112
85
  end
113
86
 
114
87
  def to_sourcecode_para(pre)
115
- @sourcecode = true
88
+ @sourcecode = "pre"
116
89
  pre.traverse do |x|
117
90
  x.text? or next
118
91
  ret = []
@@ -130,63 +103,14 @@ module IsoDoc
130
103
  end
131
104
  end
132
105
 
133
- def word_colgroup(docxml)
134
- cells2d = {}
135
- docxml.xpath("//table[colgroup]").each do |t|
136
- w = colgroup_widths(t)
137
- t.xpath(".//tr").each_with_index { |_tr, r| cells2d[r] = {} }
138
- t.xpath(".//tr").each_with_index do |tr, r|
139
- tr.xpath("./td | ./th").each_with_index do |td, _i|
140
- x = 0
141
- rs = td.attr("rowspan")&.to_i || 1
142
- cs = td.attr("colspan")&.to_i || 1
143
- while cells2d[r][x]
144
- x += 1
145
- end
146
- (r..(r + rs - 1)).each do |y2|
147
- cells2d[y2].nil? and next
148
- (x..(x + cs - 1)).each { |x2| cells2d[y2][x2] = 1 }
149
- end
150
- width = (x..(x + cs - 1)).each_with_object({ width: 0 }) do |z, m|
151
- m[:width] += w[z]
152
- end
153
- td["width"] = "#{width[:width]}%"
154
- x += cs
155
- end
156
- end
157
- end
158
- end
159
-
160
- # assume percentages
161
- def colgroup_widths(table)
162
- table.xpath("./colgroup/col").each_with_object([]) do |c, m|
163
- m << c["width"].sub(/%$/, "").to_f
164
- end
165
- end
166
-
167
- def word_nested_tables(docxml)
168
- docxml.xpath("//table").each do |t|
169
- t.xpath(".//table").reverse.each do |tt|
170
- t.next = tt.remove
171
- end
172
- end
173
- end
174
-
175
- def style_update(node, css)
176
- return unless node
177
-
178
- node["style"] =
179
- node["style"] ? node["style"].sub(/;?$/, ";#{css}") : css
180
- end
181
-
182
106
  def word_image_caption(docxml)
183
107
  docxml.xpath("//p[@class = 'FigureTitle' or @class = 'SourceTitle']")
184
108
  .each do |t|
185
- if t&.previous_element&.name == "img"
109
+ if t.previous_element&.name == "img"
186
110
  img = t.previous_element
187
111
  t.previous_element.swap("<p class='figure'>#{img.to_xml}</p>")
188
112
  end
189
- style_update(t&.previous_element, "page-break-after:avoid;")
113
+ style_update(t.previous_element, "page-break-after:avoid;")
190
114
  end
191
115
  end
192
116
 
@@ -211,23 +135,6 @@ module IsoDoc
211
135
  end
212
136
  end
213
137
 
214
- def word_table_align(docxml)
215
- docxml.xpath("//td[@align]/p | //th[@align]/p").each do |p|
216
- next if p["align"]
217
-
218
- style_update(p, "text-align: #{p.parent['align']}")
219
- end
220
- end
221
-
222
- def word_table_separator(docxml)
223
- docxml.xpath("//p[@class = 'TableTitle']").each do |t|
224
- next unless t.children.empty?
225
-
226
- t["style"] = t["style"].sub(/;?$/, ";font-size:0pt;")
227
- t.children = "&#xa0;"
228
- end
229
- end
230
-
231
138
  def word_annex_cleanup(docxml); end
232
139
 
233
140
  def word_example_cleanup(docxml)
@@ -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)
@@ -0,0 +1,85 @@
1
+ module IsoDoc
2
+ module WordFunction
3
+ module Postprocess
4
+ def table_note_cleanup(docxml)
5
+ super
6
+ # preempt html2doc putting MsoNormal there
7
+ docxml.xpath("//p[not(self::*[@class])][ancestor::*[@class = 'Note']]")
8
+ .each { |p| p["class"] = "Note" }
9
+ end
10
+
11
+ def word_colgroup(docxml)
12
+ cells2d = {}
13
+ docxml.xpath("//table[colgroup]").each do |t|
14
+ w = colgroup_widths(t)
15
+ t.xpath(".//tr").each_with_index { |_tr, r| cells2d[r] = {} }
16
+ t.xpath(".//tr").each_with_index do |tr, r|
17
+ tr.xpath("./td | ./th").each_with_index do |td, _i|
18
+ x = 0
19
+ rs = td.attr("rowspan")&.to_i || 1
20
+ cs = td.attr("colspan")&.to_i || 1
21
+ while cells2d[r][x]
22
+ x += 1
23
+ end
24
+ (r..(r + rs - 1)).each do |y2|
25
+ cells2d[y2].nil? and next
26
+ (x..(x + cs - 1)).each { |x2| cells2d[y2][x2] = 1 }
27
+ end
28
+ width = (x..(x + cs - 1)).each_with_object({ width: 0 }) do |z, m|
29
+ m[:width] += w[z]
30
+ end
31
+ td["width"] = "#{width[:width]}%"
32
+ x += cs
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ # assume percentages
39
+ def colgroup_widths(table)
40
+ table.xpath("./colgroup/col").each_with_object([]) do |c, m|
41
+ m << c["width"].sub(/%$/, "").to_f
42
+ end
43
+ end
44
+
45
+ def word_nested_tables(docxml)
46
+ docxml.xpath("//table").each do |t|
47
+ t.xpath(".//table").reverse.each do |tt|
48
+ t.next = tt.remove
49
+ end
50
+ end
51
+ end
52
+
53
+ def style_update(node, css)
54
+ node or return
55
+ node["style"] =
56
+ node["style"] ? node["style"].sub(/;?$/, ";#{css}") : css
57
+ end
58
+
59
+ def word_table_align(docxml)
60
+ docxml.xpath("//td[@align]/p | //th[@align]/p").each do |p|
61
+ p["align"] and next
62
+ style_update(p, "text-align: #{p.parent['align']}")
63
+ end
64
+ end
65
+
66
+ def word_table_separator(docxml)
67
+ docxml.xpath("//p[@class = 'TableTitle']").each do |t|
68
+ t.children.empty? or next
69
+ t["style"] = t["style"].sub(/;?$/, ";font-size:0pt;")
70
+ t.children = "&#xa0;"
71
+ end
72
+ end
73
+
74
+ def word_table_pagebreak(docxml)
75
+ docxml.xpath("//td[@style] | //th[@style]").each do |t|
76
+ s = /(page-break-after:[^;]+)/.match(t["style"])
77
+ (s && s[1]) or next
78
+ t.xpath(".//div | .//p | .//pre").each do |p|
79
+ style_update(p, s[1])
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end