isodoc 2.4.1 → 2.4.3

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 (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