isodoc 1.2.7 → 1.4.1

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +14 -9
  3. data/README.adoc +1 -3
  4. data/isodoc.gemspec +1 -1
  5. data/lib/isodoc-yaml/i18n-en.yaml +56 -0
  6. data/lib/isodoc-yaml/i18n-fr.yaml +64 -7
  7. data/lib/isodoc-yaml/i18n-zh-Hans.yaml +1 -0
  8. data/lib/isodoc/base_style/blocks.scss +2 -2
  9. data/lib/isodoc/base_style/typography.scss +1 -1
  10. data/lib/isodoc/convert.rb +13 -85
  11. data/lib/isodoc/css.rb +95 -0
  12. data/lib/isodoc/function/inline.rb +0 -33
  13. data/lib/isodoc/function/inline_simple.rb +10 -1
  14. data/lib/isodoc/function/lists.rb +2 -1
  15. data/lib/isodoc/function/references.rb +8 -13
  16. data/lib/isodoc/function/section.rb +1 -1
  17. data/lib/isodoc/function/table.rb +10 -0
  18. data/lib/isodoc/function/to_word_html.rb +2 -2
  19. data/lib/isodoc/gem_tasks.rb +4 -0
  20. data/lib/isodoc/html_function/html.rb +7 -0
  21. data/lib/isodoc/html_function/mathvariant_to_plain.rb +82 -0
  22. data/lib/isodoc/html_function/postprocess.rb +41 -20
  23. data/lib/isodoc/i18n.rb +15 -2
  24. data/lib/isodoc/metadata_contributor.rb +4 -3
  25. data/lib/isodoc/presentation_function/bibdata.rb +3 -3
  26. data/lib/isodoc/presentation_function/block.rb +14 -9
  27. data/lib/isodoc/presentation_function/inline.rb +126 -22
  28. data/lib/isodoc/presentation_function/section.rb +9 -0
  29. data/lib/isodoc/presentation_xml_convert.rb +5 -0
  30. data/lib/isodoc/version.rb +1 -1
  31. data/lib/isodoc/word_convert.rb +0 -20
  32. data/lib/isodoc/word_function/body.rb +12 -0
  33. data/lib/isodoc/word_function/postprocess.rb +38 -80
  34. data/lib/isodoc/word_function/postprocess_cover.rb +55 -0
  35. data/lib/isodoc/word_function/table.rb +10 -0
  36. data/lib/isodoc/xref.rb +1 -0
  37. data/lib/isodoc/xref/xref_counter.rb +20 -9
  38. data/lib/isodoc/xref/xref_gen.rb +20 -2
  39. data/lib/isodoc/xref/xref_sect_gen.rb +1 -1
  40. data/spec/assets/html.scss +14 -0
  41. data/spec/assets/i18n.yaml +7 -6
  42. data/spec/isodoc/blocks_spec.rb +2 -1
  43. data/spec/isodoc/cleanup_spec.rb +0 -1
  44. data/spec/isodoc/footnotes_spec.rb +4 -5
  45. data/spec/isodoc/i18n_spec.rb +23 -2
  46. data/spec/isodoc/inline_spec.rb +182 -202
  47. data/spec/isodoc/lists_spec.rb +1 -1
  48. data/spec/isodoc/metadata_spec.rb +3 -1
  49. data/spec/isodoc/postproc_spec.rb +472 -11
  50. data/spec/isodoc/presentation_xml_spec.rb +584 -1
  51. data/spec/isodoc/ref_spec.rb +325 -7
  52. data/spec/isodoc/table_spec.rb +28 -0
  53. data/spec/isodoc/xref_spec.rb +162 -17
  54. metadata +18 -16
@@ -4,8 +4,21 @@ module IsoDoc
4
4
  class I18n
5
5
  def load_yaml(lang, script, i18nyaml = nil)
6
6
  ret = load_yaml1(lang, script)
7
- return ret.merge(YAML.load_file(i18nyaml)) if i18nyaml
8
- ret
7
+ return normalise_hash(ret.merge(YAML.load_file(i18nyaml))) if i18nyaml
8
+ normalise_hash(ret)
9
+ end
10
+
11
+ def normalise_hash(ret)
12
+ if ret.is_a? Hash
13
+ ret.each do |k, v|
14
+ ret[k] = normalise_hash(v)
15
+ end
16
+ ret
17
+ elsif ret.is_a? Array then ret.map { |n| normalise_hash(n) }
18
+ elsif ret.is_a? String then ret.unicode_normalize(:nfc)
19
+ else
20
+ ret
21
+ end
9
22
  end
10
23
 
11
24
  def load_yaml1(lang, script)
@@ -17,9 +17,10 @@ module IsoDoc
17
17
  def extract_person_affiliations(authors)
18
18
  authors.reduce([]) do |m, a|
19
19
  name = a&.at(ns('./affiliation/organization/name'))&.text
20
- location = a&.at(ns('./affiliation/organization/address/'\
21
- 'formattedAddress'))&.text
22
- m << (!name.nil? && !location.nil? ? "#{name}, #{location}" :
20
+ subdivs = a&.xpath(ns('./affiliation/organization/subdivision'))&.map(&:text)&.join(", ")
21
+ name and subdivs and !subdivs.empty? and name = l10n("#{name}, #{subdivs}", @lang, @script)
22
+ location = a&.at(ns('./affiliation/organization/address/formattedAddress'))&.text
23
+ m << (!name.nil? && !location.nil? ? l10n("#{name}, #{location}", @lang, @script) :
23
24
  (name || location || ''))
24
25
  m
25
26
  end
@@ -25,13 +25,13 @@ module IsoDoc
25
25
  hash_translate(b, @i18n.get["substage_dict"], "./status/substage")
26
26
  end
27
27
 
28
- def hash_translate(bibdata, hash, xpath)
28
+ def hash_translate(bibdata, hash, xpath, lang = @lang)
29
29
  x = bibdata.at(ns(xpath)) or return
30
30
  x["language"] = ""
31
31
  hash.is_a? Hash or return
32
32
  hash[x.text] or return
33
33
  x.next = x.dup
34
- x.next["language"] = @lang
34
+ x.next["language"] = lang
35
35
  x.next.children = hash[x.text]
36
36
  end
37
37
 
@@ -40,7 +40,7 @@ module IsoDoc
40
40
  end
41
41
 
42
42
  def i18n_safe(k)
43
- k.gsub(/\s|\./, "_")
43
+ k.to_s.gsub(/\s|\./, "_")
44
44
  end
45
45
 
46
46
  def i8n_name(h, pref)
@@ -1,5 +1,10 @@
1
1
  module IsoDoc
2
2
  class PresentationXMLConvert < ::IsoDoc::Convert
3
+ def lower2cap(s)
4
+ return s if /^[[:upper:]][[:upper:]]/.match(s)
5
+ s.capitalize
6
+ end
7
+
3
8
  def figure(docxml)
4
9
  docxml.xpath(ns("//figure")).each do |f|
5
10
  figure1(f)
@@ -12,7 +17,7 @@ module IsoDoc
12
17
  return if labelled_ancestor(f) && f.ancestors("figure").empty?
13
18
  return if f.at(ns("./figure")) and !f.at(ns("./name"))
14
19
  lbl = @xrefs.anchor(f['id'], :label, false) or return
15
- prefix_name(f, "&nbsp;&mdash; ", l10n("#{@i18n.figure} #{lbl}"), "name")
20
+ prefix_name(f, "&nbsp;&mdash; ", l10n("#{lower2cap @i18n.figure} #{lbl}"), "name")
16
21
  end
17
22
 
18
23
  def prefix_name(f, delim, number, elem)
@@ -36,7 +41,7 @@ module IsoDoc
36
41
  return if labelled_ancestor(f)
37
42
  return unless f.ancestors("example").empty?
38
43
  lbl = @xrefs.anchor(f['id'], :label, false) or return
39
- prefix_name(f, "&nbsp;&mdash; ", l10n("#{@i18n.figure} #{lbl}"), "name")
44
+ prefix_name(f, "&nbsp;&mdash; ", l10n("#{lower2cap @i18n.figure} #{lbl}"), "name")
40
45
  end
41
46
 
42
47
  def formula(docxml)
@@ -65,7 +70,7 @@ module IsoDoc
65
70
 
66
71
  def example1(f)
67
72
  n = @xrefs.get[f["id"]]
68
- lbl = (n.nil? || n[:label].nil? || n[:label].empty?) ? @i18n.example :
73
+ lbl = (n.nil? || n[:label].nil? || n[:label].empty?) ? @i18n.example:
69
74
  l10n("#{@i18n.example} #{n[:label]}")
70
75
  prefix_name(f, "&nbsp;&mdash; ", lbl, "name")
71
76
  end
@@ -81,7 +86,7 @@ module IsoDoc
81
86
  return if f.parent.name == "bibitem"
82
87
  n = @xrefs.get[f["id"]]
83
88
  lbl = (@i18n.note if n.nil? || n[:label].nil? || n[:label].empty?) ?
84
- @i18n.note : l10n("#{@i18n.note} #{n[:label]}")
89
+ @i18n.note: l10n("#{@i18n.note} #{n[:label]}")
85
90
  prefix_name(f, "", lbl, "name")
86
91
  end
87
92
 
@@ -94,24 +99,24 @@ module IsoDoc
94
99
  # introduce name element
95
100
  def termnote1(f)
96
101
  lbl = l10n(@xrefs.anchor(f['id'], :label) || '???')
97
- prefix_name(f, "", lbl, "name")
102
+ prefix_name(f, "", lower2cap(lbl), "name")
98
103
  end
99
104
 
100
105
  def recommendation(docxml)
101
106
  docxml.xpath(ns("//recommendation")).each do |f|
102
- recommendation1(f, @i18n.recommendation)
107
+ recommendation1(f, lower2cap(@i18n.recommendation))
103
108
  end
104
109
  end
105
110
 
106
111
  def requirement(docxml)
107
112
  docxml.xpath(ns("//requirement")).each do |f|
108
- recommendation1(f, @i18n.requirement)
113
+ recommendation1(f, lower2cap(@i18n.requirement))
109
114
  end
110
115
  end
111
116
 
112
117
  def permission(docxml)
113
118
  docxml.xpath(ns("//permission")).each do |f|
114
- recommendation1(f, @i18n.permission)
119
+ recommendation1(f, lower2cap(@i18n.permission))
115
120
  end
116
121
  end
117
122
 
@@ -132,7 +137,7 @@ module IsoDoc
132
137
  return if labelled_ancestor(f)
133
138
  return if f["unnumbered"] && !f.at(ns("./name"))
134
139
  n = @xrefs.anchor(f['id'], :label, false)
135
- prefix_name(f, "&nbsp;&mdash; ", l10n("#{@i18n.table} #{n}"), "name")
140
+ prefix_name(f, "&nbsp;&mdash; ", l10n("#{lower2cap @i18n.table} #{n}"), "name")
136
141
  end
137
142
 
138
143
  # we use this to eliminate the semantic amend blocks from rendering
@@ -1,3 +1,5 @@
1
+ require "twitter_cldr"
2
+
1
3
  module IsoDoc
2
4
  class PresentationXMLConvert < ::IsoDoc::Convert
3
5
  def prefix_container(container, linkend, _target)
@@ -8,8 +10,8 @@ module IsoDoc
8
10
  if node["citeas"].nil? && node["bibitemid"]
9
11
  return @xrefs.anchor(node["bibitemid"] ,:xref) || "???"
10
12
  elsif node["target"] && node["droploc"]
11
- return @xrefs.anchor(node["target"], :value) ||
12
- @xrefs.anchor(node["target"], :label) ||
13
+ return @xrefs.anchor(node["target"], :value) ||
14
+ @xrefs.anchor(node["target"], :label) ||
13
15
  @xrefs.anchor(node["target"], :xref) || "???"
14
16
  elsif node["target"] && !/.#./.match(node["target"])
15
17
  linkend = anchor_linkend1(node)
@@ -38,7 +40,7 @@ module IsoDoc
38
40
  end
39
41
 
40
42
  def nearest_block_parent(node)
41
- until %w(p title td th name formula
43
+ until %w(p title td th name formula
42
44
  li dt dd sourcecode pre).include?(node.name)
43
45
  node = node.parent
44
46
  end
@@ -51,13 +53,13 @@ module IsoDoc
51
53
  end
52
54
  end
53
55
 
54
- def get_linkend(node)
55
- contents = non_locality_elems(node).select { |c| !c.text? || /\S/.match(c) }
56
+ def get_linkend(n)
57
+ contents = non_locality_elems(n).select { |c| !c.text? || /\S/.match(c) }
56
58
  return unless contents.empty?
57
- link = anchor_linkend(node, docid_l10n(node["target"] || node["citeas"]))
58
- link += eref_localities(node.xpath(ns("./locality | ./localityStack")), link)
59
- non_locality_elems(node).each { |n| n.remove }
60
- node.add_child(link)
59
+ link = anchor_linkend(n, docid_l10n(n["target"] || n["citeas"]))
60
+ link += eref_localities(n.xpath(ns("./locality | ./localityStack")), link)
61
+ non_locality_elems(n).each { |n| n.remove }
62
+ n.add_child(link)
61
63
  end
62
64
  # so not <origin bibitemid="ISO7301" citeas="ISO 7301">
63
65
  # <locality type="section"><reference>3.1</reference></locality></origin>
@@ -104,7 +106,8 @@ module IsoDoc
104
106
  # TODO: move to localization file
105
107
  def eref_localities1(target, type, from, to, delim, lang = "en")
106
108
  return "" if type == "anchor"
107
- return l10n(eref_localities1_zh(target, type, from, to, delim)) if lang == "zh"
109
+ lang == "zh" and
110
+ return l10n(eref_localities1_zh(target, type, from, to, delim))
108
111
  ret = delim
109
112
  loc = @i18n.locality[type] || type.sub(/^locality:/, "").capitalize
110
113
  ret += " #{loc}"
@@ -114,31 +117,132 @@ module IsoDoc
114
117
  end
115
118
 
116
119
  def xref(docxml)
117
- docxml.xpath(ns("//xref")).each do |f|
118
- xref1(f)
119
- end
120
+ docxml.xpath(ns("//xref")).each { |f| xref1(f) }
120
121
  end
121
122
 
122
123
  def eref(docxml)
123
- docxml.xpath(ns("//eref")).each do |f|
124
- xref1(f)
125
- end
124
+ docxml.xpath(ns("//eref")).each { |f| xref1(f) }
126
125
  end
127
126
 
128
127
  def origin(docxml)
129
- docxml.xpath(ns("//origin[not(termref)]")).each do |f|
130
- xref1(f)
131
- end
128
+ docxml.xpath(ns("//origin[not(termref)]")).each { |f| xref1(f) }
132
129
  end
133
130
 
134
131
  def quotesource(docxml)
135
- docxml.xpath(ns("//quote/source")).each do |f|
136
- xref1(f)
137
- end
132
+ docxml.xpath(ns("//quote/source")).each { |f| xref1(f) }
138
133
  end
139
134
 
140
135
  def xref1(f)
141
136
  get_linkend(f)
142
137
  end
138
+
139
+ def concept(docxml)
140
+ docxml.xpath(ns("//concept")).each { |f| concept1(f) }
141
+ end
142
+
143
+ def concept1(node)
144
+ content = node.first_element_child.children.select do |c|
145
+ !%w{locality localityStack}.include? c.name
146
+ end.select { |c| !c.text? || /\S/.match(c) }
147
+ node.replace content.empty? ?
148
+ @i18n.term_defined_in.sub(/%/, node.first_element_child.to_xml) :
149
+ "<em>#{node.children.to_xml}</em>"
150
+ end
151
+
152
+
153
+ MATHML = { "m" => "http://www.w3.org/1998/Math/MathML" }.freeze
154
+
155
+ def mathml(docxml)
156
+ locale = twitter_cldr_localiser()
157
+ docxml.xpath("//m:math", MATHML).each do |f|
158
+ mathml1(f, locale)
159
+ end
160
+ end
161
+
162
+ # symbols is merged into
163
+ # TwitterCldr::DataReaders::NumberDataReader.new(locale).symbols
164
+ def localize_maths(f, locale)
165
+ f.xpath(".//m:mn", MATHML).each do |x|
166
+ num = /\./.match(x.text) ? x.text.to_f : x.text.to_i
167
+ precision = /\./.match(x.text) ? x.text.sub(/^.*\./, "").size : 0
168
+ x.children = localized_number(num, locale, precision)
169
+ end
170
+ end
171
+
172
+ # By itself twiiter cldr does not support fraction part digits grouping
173
+ # and custom delimeter, will decorate fraction part manually
174
+ def localized_number(num, locale, precision)
175
+ localized = precision == 0 ? num.localize(locale).to_s :
176
+ num.localize(locale).to_decimal.to_s(:precision => precision)
177
+ twitter_cldr_reader_symbols = twitter_cldr_reader(locale)
178
+ return localized unless twitter_cldr_reader_symbols[:decimal]
179
+ integer, fraction = localized.split(twitter_cldr_reader_symbols[:decimal])
180
+ return localized if fraction.nil? || fraction.length.zero?
181
+ [integer, decorate_fraction_part(fraction, locale)].
182
+ join(twitter_cldr_reader_symbols[:decimal])
183
+ end
184
+
185
+ def decorate_fraction_part(fract, locale)
186
+ result = []
187
+ twitter_cldr_reader_symbols = twitter_cldr_reader(locale)
188
+ fract = fract.slice(0..(twitter_cldr_reader_symbols[:precision] || -1))
189
+ fr_group_digits = twitter_cldr_reader_symbols[:fraction_group_digits] || 1
190
+ until fract.empty?
191
+ result.push(fract.slice!(0, fr_group_digits))
192
+ end
193
+ result.join(twitter_cldr_reader_symbols[:fraction_group].to_s)
194
+ end
195
+
196
+ def twitter_cldr_localiser_symbols
197
+ {}
198
+ end
199
+
200
+ def twitter_cldr_reader(locale)
201
+ num = TwitterCldr::DataReaders::NumberDataReader.new(locale)
202
+ num.symbols.merge!(twitter_cldr_localiser_symbols)
203
+ end
204
+
205
+ def twitter_cldr_localiser()
206
+ locale = TwitterCldr.supported_locale?(@lang.to_sym) ? @lang.to_sym : :en
207
+ twitter_cldr_reader(locale)
208
+ locale
209
+ end
210
+
211
+ def mathml1(f, locale)
212
+ localize_maths(f, locale)
213
+ return unless f.elements.size == 1 && f.elements.first.name == "mn"
214
+ f.replace(f.at("./m:mn", MATHML).children)
215
+ end
216
+
217
+ def variant(docxml)
218
+ docxml.xpath(ns("//variant")).each { |f| variant1(f) }
219
+ docxml.xpath(ns("//variant[@remove = 'true']")).each { |f| f.remove }
220
+ docxml.xpath(ns("//variant")).each do |v|
221
+ next unless v&.next&.name == "variant"
222
+ v.next = "/"
223
+ end
224
+ docxml.xpath(ns("//variant")).each { |f| f.replace(f.children) }
225
+ end
226
+
227
+ def variant1(node)
228
+ if (!node["lang"] || node["lang"] == @lang) &&
229
+ (!node["script"] || node["script"] == @script)
230
+ elsif found_matching_variant_sibling(node)
231
+ node["remove"] = "true"
232
+ else
233
+ #return unless !node.at("./preceding-sibling::xmlns:variant")
234
+ end
235
+ end
236
+
237
+ def found_matching_variant_sibling(node)
238
+ prev = node.xpath("./preceding-sibling::xmlns:variant")
239
+ foll = node.xpath("./following-sibling::xmlns:variant")
240
+ found = false
241
+ (prev + foll).each do |n|
242
+ found = true if n["lang"] == @lang &&
243
+ (!n["script"] || n["script"] == @script)
244
+ end
245
+ found
246
+ end
143
247
  end
144
248
  end
@@ -42,5 +42,14 @@ module IsoDoc
42
42
  lbl = @xrefs.get[f["id"]][:label] or return
43
43
  prefix_name(f, "", "#{lbl}#{clausedelim}", "name")
44
44
  end
45
+
46
+ def references(docxml)
47
+ end
48
+
49
+ def index(docxml)
50
+ docxml.xpath(ns("//index | //index-xref")).each do |f|
51
+ f.remove
52
+ end
53
+ end
45
54
  end
46
55
  end
@@ -30,6 +30,8 @@ module IsoDoc
30
30
  clause docxml
31
31
  annex docxml
32
32
  term docxml
33
+ references docxml
34
+ index docxml
33
35
  end
34
36
 
35
37
  def block(docxml)
@@ -51,7 +53,10 @@ module IsoDoc
51
53
  xref docxml
52
54
  eref docxml
53
55
  origin docxml
56
+ concept docxml
54
57
  quotesource docxml
58
+ mathml docxml
59
+ variant docxml
55
60
  end
56
61
 
57
62
  def postprocess(result, filename, dir)
@@ -1,3 +1,3 @@
1
1
  module IsoDoc
2
- VERSION = "1.2.7".freeze
2
+ VERSION = "1.4.1".freeze
3
3
  end
@@ -4,26 +4,6 @@ require_relative "word_function/body.rb"
4
4
  require_relative "word_function/postprocess.rb"
5
5
 
6
6
  module IsoDoc
7
-
8
- =begin
9
- module WordConvertModule
10
- # http://tech.tulentsev.com/2012/02/ruby-how-to-override-class-method-with-a-module/
11
- # https://www.ruby-forum.com/topic/148303
12
- #
13
- # The following is ugly indeed, but the only way I can split module override methods
14
- # across files
15
- def self.included base
16
- base.class_eval do
17
-
18
- eval File.open(File.join(File.dirname(__FILE__),"wordconvertmodule.rb")).read
19
- eval File.open(File.join(File.dirname(__FILE__),"comments.rb")).read
20
- eval File.open(File.join(File.dirname(__FILE__),"footnotes.rb")).read
21
- eval File.open(File.join(File.dirname(__FILE__),"postprocess.rb")).read
22
- end
23
- end
24
- end
25
- =end
26
-
27
7
  class WordConvert < ::IsoDoc::Convert
28
8
  include WordFunction::Comments
29
9
  include WordFunction::Footnotes
@@ -196,6 +196,18 @@ module IsoDoc::WordFunction
196
196
  out.parent.at("./table")["class"] = "formula_dl"
197
197
  end
198
198
 
199
+ def formula_parse1(node, out)
200
+ out.div **attr_code(class: "formula") do |div|
201
+ div.p do |p|
202
+ parse(node.at(ns("./stem")), div)
203
+ insert_tab(div, 1)
204
+ if lbl = node&.at(ns("./name"))&.text
205
+ div << "(#{lbl})"
206
+ end
207
+ end
208
+ end
209
+ end
210
+
199
211
  def li_parse(node, out)
200
212
  out.li **attr_code(id: node["id"]) do |li|
201
213
  if node["uncheckedcheckbox"] == "true"
@@ -5,11 +5,9 @@ module IsoDoc::WordFunction
5
5
  module Postprocess
6
6
  # add namespaces for Word fragments
7
7
  WORD_NOKOHEAD = <<~HERE.freeze
8
- <!DOCTYPE html SYSTEM
9
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
8
+ <!DOCTYPE html SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
10
9
  <html xmlns="http://www.w3.org/1999/xhtml"
11
- xmlns:v="urn:schemas-microsoft-com:vml"
12
- xmlns:o="urn:schemas-microsoft-com:office:office"
10
+ xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"
13
11
  xmlns:w="urn:schemas-microsoft-com:office:word"
14
12
  xmlns:m="http://schemas.microsoft.com/office/2004/12/omml">
15
13
  <head> <title></title> <meta charset="UTF-8" /> </head>
@@ -18,15 +16,13 @@ xmlns:m="http://schemas.microsoft.com/office/2004/12/omml">
18
16
 
19
17
  def to_word_xhtml_fragment(xml)
20
18
  doc = ::Nokogiri::XML.parse(WORD_NOKOHEAD)
21
- fragment = ::Nokogiri::XML::DocumentFragment.new(doc, xml, doc.root)
22
- fragment
19
+ ::Nokogiri::XML::DocumentFragment.new(doc, xml, doc.root)
23
20
  end
24
21
 
25
22
  def table_note_cleanup(docxml)
26
23
  super
27
24
  # preempt html2doc putting MsoNormal there
28
- docxml.xpath("//p[not(self::*[@class])]"\
29
- "[ancestor::*[@class = 'Note']]").each do |p|
25
+ docxml.xpath("//p[not(self::*[@class])][ancestor::*[@class = 'Note']]").each do |p|
30
26
  p["class"] = "Note"
31
27
  end
32
28
  end
@@ -56,8 +52,7 @@ xmlns:m="http://schemas.microsoft.com/office/2004/12/omml">
56
52
 
57
53
  def word_admonition_images(docxml)
58
54
  docxml.xpath("//div[@class = 'Admonition']//img").each do |i|
59
- i["width"], i["height"] =
60
- Html2Doc.image_resize(i, image_localfile(i), @maxheight, 300)
55
+ i["width"], i["height"] = Html2Doc.image_resize(i, image_localfile(i), @maxheight, 300)
61
56
  end
62
57
  end
63
58
 
@@ -65,6 +60,7 @@ xmlns:m="http://schemas.microsoft.com/office/2004/12/omml">
65
60
  word_annex_cleanup(docxml)
66
61
  word_preface(docxml)
67
62
  word_nested_tables(docxml)
63
+ word_colgroup(docxml)
68
64
  word_table_align(docxml)
69
65
  word_table_separator(docxml)
70
66
  word_admonition_images(docxml)
@@ -78,28 +74,44 @@ xmlns:m="http://schemas.microsoft.com/office/2004/12/omml">
78
74
  docxml
79
75
  end
80
76
 
81
- def word_nested_tables(docxml)
82
- docxml.xpath("//table").each do |t|
83
- t.xpath(".//table").reverse.each do |tt|
84
- t.next = tt.remove
77
+ def word_colgroup(docxml)
78
+ cells2d = {}
79
+ docxml.xpath("//table[colgroup]").each do |t|
80
+ w = colgroup_widths(t)
81
+ t.xpath(".//tr").each_with_index { |tr, r| cells2d[r] = {} }
82
+ t.xpath(".//tr").each_with_index do |tr, r|
83
+ tr.xpath("./td | ./th").each_with_index do |td, i|
84
+ x = 0
85
+ rs = td&.attr("rowspan")&.to_i || 1
86
+ cs = td&.attr("colspan")&.to_i || 1
87
+ while cells2d[r][x] do
88
+ x += 1
89
+ end
90
+ for y2 in r..(r + rs - 1)
91
+ for x2 in x..(x + cs - 1)
92
+ cells2d[y2][x2] = 1
93
+ end
94
+ end
95
+ width = (x..(x+cs-1)).each_with_object({width: 0}) { |z, m| m[:width] += w[z] }
96
+ td["width"] = "#{width[:width]}%"
97
+ x += cs
98
+ end
85
99
  end
86
100
  end
87
101
  end
88
102
 
89
- def authority_cleanup1(docxml, klass)
90
- dest = docxml.at("//div[@id = 'boilerplate-#{klass}-destination']")
91
- auth = docxml.at("//div[@id = 'boilerplate-#{klass}' or @class = 'boilerplate-#{klass}']")
92
- auth&.xpath(".//h1[not(text())] | .//h2[not(text())]")&.each { |h| h.remove }
93
- auth&.xpath(".//h1 | .//h2")&.each do |h|
94
- h.name = "p"
95
- h["class"] = "TitlePageSubhead"
103
+ # assume percentages
104
+ def colgroup_widths(t)
105
+ t.xpath("./colgroup/col").each_with_object([]) do |c, m|
106
+ m << c["width"].sub(/%$/, "").to_f
96
107
  end
97
- dest and auth and dest.replace(auth.remove)
98
108
  end
99
109
 
100
- def authority_cleanup(docxml)
101
- %w(copyright license legal feedback).each do |t|
102
- authority_cleanup1(docxml, t)
110
+ def word_nested_tables(docxml)
111
+ docxml.xpath("//table").each do |t|
112
+ t.xpath(".//table").reverse.each do |tt|
113
+ t.next = tt.remove
114
+ end
103
115
  end
104
116
  end
105
117
 
@@ -144,19 +156,6 @@ xmlns:m="http://schemas.microsoft.com/office/2004/12/omml">
144
156
  end
145
157
  end
146
158
 
147
- =begin
148
- EMPTY_PARA = "<p style='margin-top:0cm;margin-right:0cm;"\
149
- "margin-bottom:0cm;margin-left:0.0pt;margin-bottom:.0001pt;"\
150
- "line-height:1.0pt;mso-line-height-rule:exactly'>"\
151
- "<span lang=EN-GB style='display:none;mso-hide:all'>&nbsp;</span></p>"
152
-
153
- def table_after_table(docxml)
154
- docxml.xpath("//table[following-sibling::*[1]/self::table]").each do |t|
155
- t.add_next_sibling(EMPTY_PARA)
156
- end
157
- end
158
- =end
159
-
160
159
  def word_table_separator(docxml)
161
160
  docxml.xpath("//p[@class = 'TableTitle']").each do |t|
162
161
  next unless t.children.empty?
@@ -180,46 +179,6 @@ xmlns:m="http://schemas.microsoft.com/office/2004/12/omml">
180
179
  end
181
180
  end
182
181
 
183
- def generate_header(filename, _dir)
184
- return nil unless @header
185
- template = IsoDoc::Common.liquid(File.read(@header, encoding: "UTF-8"))
186
- meta = @meta.get.merge(@labels || {}).merge(@meta.labels || {})
187
- meta[:filename] = filename
188
- params = meta.map { |k, v| [k.to_s, v] }.to_h
189
- Tempfile.open(%w(header html), :encoding => "utf-8") do |f|
190
- f.write(template.render(params))
191
- f
192
- end
193
- end
194
-
195
- def word_section_breaks(docxml)
196
- @landscapestyle = ""
197
- word_section_breaks1(docxml, "WordSection2")
198
- word_section_breaks1(docxml, "WordSection3")
199
- word_remove_pb_before_annex(docxml)
200
- docxml.xpath("//br[@orientation]").each { |br| br.delete("orientation") }
201
- end
202
-
203
- def word_section_breaks1(docxml, sect)
204
- docxml.xpath("//div[@class = '#{sect}']//br[@orientation]").reverse.
205
- each_with_index do |br, i|
206
- @landscapestyle += "\ndiv.#{sect}_#{i} {page:#{sect}"\
207
- "#{br["orientation"] == "landscape" ? "L" : "P"};}\n"
208
- split_at_section_break(docxml, sect, br, i)
209
- end
210
- end
211
-
212
- def split_at_section_break(docxml, sect, br, i)
213
- move = br.parent.xpath("following::node()") &
214
- br.document.xpath("//div[@class = '#{sect}']//*")
215
- ins = docxml.at("//div[@class = '#{sect}']").
216
- after("<div class='#{sect}_#{i}'/>").next_element
217
- move.each do |m|
218
- next if m.at("./ancestor::div[@class = '#{sect}_#{i}']")
219
- ins << m.remove
220
- end
221
- end
222
-
223
182
  # applies for <div class="WordSectionN_M"><p><pagebreak/></p>...
224
183
  def word_remove_pb_before_annex(docxml)
225
184
  docxml.xpath("//div[p/br]").each do |d|
@@ -237,8 +196,7 @@ xmlns:m="http://schemas.microsoft.com/office/2004/12/omml">
237
196
  docxml.xpath("//a[@epub:type = 'footnote']").each do |x|
238
197
  footnote_reference_format(x)
239
198
  end
240
- docxml.xpath("//a[@class = 'TableFootnoteRef'] | "\
241
- "//span[@class = 'TableFootnoteRef']").each do |x|
199
+ docxml.xpath("//a[@class = 'TableFootnoteRef'] | //span[@class = 'TableFootnoteRef']").each do |x|
242
200
  table_footnote_reference_format(x)
243
201
  end
244
202
  docxml