isodoc 2.4.2 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f122ad0105340afb41607b8639eb00b7205328f9bddad0a5a3726e9644c912e
4
- data.tar.gz: 04b386a592680a3315ed3d55e7c6716bc177fd628a8d67f520e224b1a4d4de5f
3
+ metadata.gz: a0720c3026536785125b4c6c495e4f2573dfa7b2186094c0f36efa9c20a1fbd3
4
+ data.tar.gz: 9ea3325d067e417956b865edd0baf70dff9a5cb80008e6dfe5fbfbdaaaf16ff4
5
5
  SHA512:
6
- metadata.gz: 6fef982e2095471e35cc7235a3bc5712066845fd4302131e9760e8d10da548ec73b40f344816077b915b63d93d32cb5b459507ad2133ac52da257a6230e99353
7
- data.tar.gz: cbbaa050b52517cf272d7d0da4d875075e094b3dcda074a89c55945ceedb6c357914f9e9be0cd09e45ac9d6ace9f61f71b8f9d2ccb5c8d3ebb5ba4fd9251e632
6
+ metadata.gz: 2e97827c7adacaa26ef823222897672413056219fba5a3e0a6dee92079ac680cd50a9f1dde9cb7c40fddf23ef000fcb0478709a95916a4e6b222bf3d4e94ca54
7
+ data.tar.gz: 888734821add95629f8709aac1e5ac8b95b372b6a33d43e366e78e0c4ec6a3957dc9264a86015501458ca2752b881f44053e1f7a3997c5d0fb1b43ec816abc74
@@ -50,6 +50,8 @@ module IsoDoc
50
50
  # fontlicenseagreement: fontist font license agreement
51
51
  # modspecidentifierbase: base prefix for any Modspec identifiers
52
52
  # sourcehighlighter: whether to apply sourcecode highlighting
53
+ # semantic_xml_insert: whether to insert into presentation XML
54
+ # a copy of semantic XML
53
55
  def initialize(options) # rubocop:disable Lint/MissingSuper
54
56
  @options = options_preprocess(options)
55
57
  init_stylesheets(@options)
@@ -60,6 +62,7 @@ module IsoDoc
60
62
  init_locations(@options)
61
63
  init_i18n(@options)
62
64
  init_rendering(@options)
65
+ init_arrangement(@options)
63
66
  end
64
67
 
65
68
  def options_preprocess(options)
@@ -77,14 +80,18 @@ module IsoDoc
77
80
  @datauriimage = options[:datauriimage]
78
81
  @suppressheadingnumbers = options[:suppressheadingnumbers]
79
82
  @break_up_urls_in_tables = options[:breakupurlsintables]
80
- @sectionsplit = options[:sectionsplit] == "true"
81
83
  @suppressasciimathdup = options[:suppressasciimathdup]
82
- @bare = options[:bare]
83
84
  @aligncrosselements = options[:aligncrosselements]
84
85
  @modspecidentifierbase = options[:modspecidentifierbase]
85
86
  @sourcehighlighter = options[:sourcehighlighter]
86
87
  end
87
88
 
89
+ def init_arrangement(options)
90
+ @sectionsplit = options[:sectionsplit] == "true"
91
+ @bare = options[:bare]
92
+ @semantic_xml_insert = options[:semanticxmlinsert] != "false"
93
+ end
94
+
88
95
  def init_i18n(options)
89
96
  @i18nyaml = options[:i18nyaml]
90
97
  @lang = options[:language] || "en"
@@ -187,7 +194,7 @@ module IsoDoc
187
194
  @xrefs.parse docxml
188
195
  bibitem_lookup(docxml)
189
196
  noko do |xml|
190
- xml.html **{ lang: @lang.to_s } do |html|
197
+ xml.html lang: @lang.to_s do |html|
191
198
  html.parent.add_namespace("epub", "http://www.idpf.org/2007/ops")
192
199
  info docxml, nil
193
200
  populate_css
@@ -82,8 +82,11 @@ module IsoDoc
82
82
 
83
83
  def sourcecode_parse1(node, div)
84
84
  @sourcecode = "pre"
85
- node.at(ns(".//table")) || !node.ancestors("table").empty? and
85
+ node.at(ns(".//table[@class = 'rouge-line-table']")) ||
86
+ node.at("./ancestor::xmlns:table[@class = 'rouge-line-table']") and
86
87
  @sourcecode = "table"
88
+ # !node.ancestors("table").empty? and
89
+ # @sourcecode = "table"
87
90
  node.children.each { |n| parse(n, div) unless n.name == "name" }
88
91
  @sourcecode = false
89
92
  end
@@ -96,7 +99,7 @@ module IsoDoc
96
99
  @sourcecode = false
97
100
  @annotation = true
98
101
  out.div class: "annotation" do |div|
99
- #node.at("./preceding-sibling::*[local-name() = 'annotation']") or
102
+ # node.at("./preceding-sibling::*[local-name() = 'annotation']") or
100
103
  # div << "<br/>"
101
104
  callout = node.at(ns("//callout[@target='#{node['id']}']"))
102
105
  div << "<span class='c'>&lt;#{callout.text}&gt;</span> "
@@ -30,7 +30,7 @@ module IsoDoc
30
30
  end
31
31
 
32
32
  def keyword_parse(node, out)
33
- out.span **{ class: "keyword" } do |s|
33
+ out.span class: "keyword" do |s|
34
34
  node.children.each { |n| parse(n, s) }
35
35
  end
36
36
  end
@@ -4,55 +4,35 @@ module IsoDoc
4
4
  # This is highly specific to ISO, but it's not a bad precedent for
5
5
  # references anyway; keeping here instead of in IsoDoc::Iso for now
6
6
  def docid_l10n(text)
7
- return text if text.nil?
8
-
9
- text.gsub(/All Parts/i, @i18n.all_parts.downcase) if @i18n.all_parts
7
+ text.nil? and return text
8
+ @i18n.all_parts and text.gsub!(/All Parts/i, @i18n.all_parts.downcase)
9
+ text.size < 20 and text.gsub!(/ /, "&#xa0;")
10
10
  text
11
11
  end
12
12
 
13
- def nonstd_bibitem(list, bib, _ordinal, biblio) # %%%
13
+ def nonstd_bibitem(list, bib, _ordinal, biblio)
14
14
  list.p **attr_code(iso_bibitem_entry_attrs(bib, biblio)) do |ref|
15
- # ids = bibitem_ref_code(bib)
16
- # idents = render_identifier(ids)
17
- # if biblio then ref_entry_code(ref, ordinal, idents, ids)
18
- # else
19
- # ref << (idents[:ordinal] || idents[:metanorma] || idents[:sdo]).to_s
20
- # ref << ", #{idents[sdo]}" if idents[:ordinal] && idents[:sdo]
21
- # end
22
- # ref << "," if idents[:sdo]
23
15
  tag = bib.at(ns("./biblio-tag"))
24
16
  tag&.children&.each { |n| parse(n, ref) }
25
17
  reference_format(bib, ref)
26
18
  end
27
19
  end
28
20
 
29
- def std_bibitem_entry(list, bib, _ordinal, biblio) # %%%
21
+ def std_bibitem_entry(list, bib, _ordinal, biblio)
30
22
  list.p **attr_code(iso_bibitem_entry_attrs(bib, biblio)) do |ref|
31
- # idents = render_identifier(bibitem_ref_code(bib))
32
- # if biblio then ref_entry_code(ref, ordinal, idents, nil)
33
- # else
34
- # ref << (idents[:ordinal] || idents[:metanorma] || idents[:sdo]).to_s
35
- # ref << ", #{idents[:sdo]}" if (idents[:ordinal] ||
36
- # idents[:metanorma]) && idents[:sdo]
37
- # end
38
- # date_note_process(bib, ref)
39
- # ref << "," if idents[:sdo]
40
23
  tag = bib.at(ns("./biblio-tag"))
41
24
  tag&.children&.each { |n| parse(n, ref) }
42
25
  reference_format(bib, ref)
43
26
  end
44
27
  end
45
28
 
46
- # # if ids is just a number, only use that ([1] Non-Standard)
47
- # # else, use both ordinal, as prefix, and ids
48
- # def ref_entry_code(ref, ordinal, ids, _id) #%%%
49
- # prefix_bracketed_ref(ref, ids[:ordinal] || ids[:metanorma] ||
50
- # "[#{ordinal}]")
51
- # ids[:sdo] and ref << (ids[:sdo]).to_s
52
- # end
29
+ SKIP_DOCID = <<~XPATH.strip.freeze
30
+ @type = 'DOI' or @type = 'doi' or @type = 'ISSN' or @type = 'issn' or @type = 'ISBN' or @type = 'isbn' or starts-with(@type, 'ISSN.') or starts-with(@type, 'ISBN.') or starts-with(@type, 'issn.') or starts-with(@type, 'isbn.')
31
+ XPATH
53
32
 
54
- SKIP_DOCID = "@type = 'DOI' or @type = 'metanorma' or @type = 'ISSN' or " \
55
- "@type = 'metanorma-ordinal' or @type = 'ISBN'".freeze
33
+ SKIP_DOC1 = <<~XPATH.strip.freeze
34
+ #{SKIP_DOCID} or @type = 'metanorma-ordinal' or @type = 'metanorma'
35
+ XPATH
56
36
 
57
37
  def pref_ref_code(bib)
58
38
  bib["suppress_identifier"] == "true" and return nil
@@ -61,8 +41,8 @@ module IsoDoc
61
41
  ret.empty? and
62
42
  ret = bib.xpath(ns("./docidentifier[@primary = 'true']"))
63
43
  ret.empty? and
64
- ret = bib.at(ns("./docidentifier[not(#{SKIP_DOCID})]#{lang}")) ||
65
- bib.at(ns("./docidentifier[not(#{SKIP_DOCID})]"))
44
+ ret = bib.at(ns("./docidentifier[not(#{SKIP_DOC1})]#{lang}")) ||
45
+ bib.at(ns("./docidentifier[not(#{SKIP_DOC1})]"))
66
46
  ret
67
47
  end
68
48
 
@@ -70,8 +50,7 @@ module IsoDoc
70
50
  def bibitem_ref_code(bib)
71
51
  id = bib.at(ns("./docidentifier[@type = 'metanorma']"))
72
52
  id1 = pref_ref_code(bib)
73
- id2 = bib.at(ns("./docidentifier[@type = 'DOI' or @type = 'ISSN' or " \
74
- "@type = 'ISBN']"))
53
+ id2 = bib.at(ns("./docidentifier[#{SKIP_DOCID}]"))
75
54
  id3 = bib.at(ns("./docidentifier[@type = 'metanorma-ordinal']"))
76
55
  return [id, id1, id2, id3] if id || id1 || id2 || id3
77
56
  return [nil, nil, nil, nil] if bib["suppress_identifier"] == "true"
@@ -139,9 +118,9 @@ module IsoDoc
139
118
 
140
119
  def standard?(bib)
141
120
  ret = false
142
- drop = %w(metanorma DOI ISSN ISBN)
143
121
  bib.xpath(ns("./docidentifier")).each do |id|
144
- next if id["type"].nil? || drop.include?(id["type"])
122
+ next if id["type"].nil? ||
123
+ id.at(".//self::*[#{SKIP_DOCID} or @type = 'metanorma']")
145
124
 
146
125
  ret = true
147
126
  end
@@ -194,7 +173,7 @@ module IsoDoc
194
173
  return
195
174
  page_break(out)
196
175
  out.div do |div|
197
- div.h1 **{ class: "Section3" } do |h1|
176
+ div.h1 class: "Section3" do |h1|
198
177
  f.at(ns("./title"))&.children&.each { |c2| parse(c2, h1) }
199
178
  end
200
179
  biblio_list(f, div, true)
@@ -69,7 +69,7 @@ module IsoDoc
69
69
  end
70
70
 
71
71
  def from_xhtml(xml)
72
- numeric_escapes(xml.to_xml
72
+ numeric_escapes(to_xml(xml)
73
73
  .sub(%r{ xmlns="http://www.w3.org/1999/xhtml"}, ""))
74
74
  end
75
75
 
@@ -170,7 +170,7 @@ module IsoDoc
170
170
  end
171
171
 
172
172
  def code_css(isoxml, _out)
173
- c = isoxml.at(ns("//misc-container/source-highlighter-css")) or return
173
+ c = isoxml.at(ns("//metanorma-extension/source-highlighter-css")) or return
174
174
  set(:code_css, c.text)
175
175
  end
176
176
  end
@@ -17,8 +17,8 @@ module IsoDoc
17
17
  def toc_metadata(docxml)
18
18
  return unless @tocfigures || @toctables || @tocrecommendations
19
19
 
20
- ins = docxml.at(ns("//misc-container")) ||
21
- docxml.at(ns("//bibdata")).after("<misc-container/>").next_element
20
+ ins = docxml.at(ns("//metanorma-extension")) ||
21
+ docxml.at(ns("//bibdata")).after("<metanorma-extension/>").next_element
22
22
  @tocfigures and
23
23
  ins << "<toc type='figure'><title>#{@i18n.toc_figures}</title></toc>"
24
24
  @toctables and
@@ -41,7 +41,7 @@ module IsoDoc
41
41
  return unless @fontist_fonts
42
42
 
43
43
  ins = xmldoc.at(ns("//presentation-metadata")) ||
44
- xmldoc.at(ns("//misc-container")) || xmldoc.at(ns("//bibdata"))
44
+ xmldoc.at(ns("//metanorma-extension")) || xmldoc.at(ns("//bibdata"))
45
45
  CSV.parse_line(@fontist_fonts, col_sep: ";").map(&:strip).each do |f|
46
46
  ins.next = presmeta("fonts", f)
47
47
  end
@@ -32,7 +32,7 @@ module IsoDoc
32
32
  return localized unless twitter_cldr_reader_symbols[:decimal]
33
33
 
34
34
  integer, fraction = localized.split(twitter_cldr_reader_symbols[:decimal])
35
- return localized if fraction.nil? || fraction.length.zero?
35
+ return localized if fraction.nil? || fraction.empty?
36
36
 
37
37
  [integer, decorate_fraction_part(fraction, locale)]
38
38
  .join(twitter_cldr_reader_symbols[:decimal])
@@ -97,14 +97,25 @@ module IsoDoc
97
97
  end
98
98
 
99
99
  def mathml1(node, locale)
100
+ mathml_style_inherit(node)
100
101
  asciimath_dup(node)
101
102
  localize_maths(node, locale)
102
- return unless node.elements.size == 1 && node.elements.first.name == "mn"
103
+ mathml_number_to_number(node)
104
+ end
105
+
106
+ def mathml_style_inherit(node)
107
+ node.at("./ancestor::xmlns:strong") or return
108
+ node.children =
109
+ "<mstyle fontweight='bold'>#{node.children.to_xml}</mstyle>"
110
+ end
103
111
 
112
+ def mathml_number_to_number(node)
113
+ (node.elements.size == 1 && node.elements.first.name == "mn") or return
114
+ repl = node.at("./m:mn", MATHML).children
104
115
  if node.parent.name == "stem"
105
- node.parent.replace(node.at("./m:mn", MATHML).children)
116
+ node.parent.replace(repl)
106
117
  else
107
- node.replace(node.at("./m:mn", MATHML).children)
118
+ node.replace(repl)
108
119
  end
109
120
  end
110
121
  end
@@ -2,8 +2,8 @@ module IsoDoc
2
2
  class PresentationXMLConvert < ::IsoDoc::Convert
3
3
  def sourcehighlighter_css(docxml)
4
4
  @sourcehighlighter or return
5
- ins = docxml.at(ns("//misc-container")) ||
6
- docxml.at(ns("//bibdata")).after("<misc-container/>").next_element
5
+ ins = docxml.at(ns("//metanorma-extension")) ||
6
+ docxml.at(ns("//bibdata")).after("<metanorma-extension/>").next_element
7
7
  ins << "<source-highlighter-css>#{sourcehighlighter_css_file}" \
8
8
  "</source-highlighter-css>"
9
9
  end
@@ -15,10 +15,11 @@ module IsoDoc
15
15
 
16
16
  def sourcehighlighter
17
17
  @sourcehighlighter or return
18
+ Rouge::Formatter.enable_escape!
18
19
  f = Rouge::Formatters::HTML.new
19
20
  opts = { gutter_class: "rouge-gutter", code_class: "rouge-code" }
20
- { formatter: f,
21
- formatter_line: Rouge::Formatters::HTMLLineTable.new(f, opts) }
21
+ f1 = Rouge::Formatters::HTMLLineTable.new(f, opts)
22
+ { formatter: f, formatter_line: f1 }
22
23
  end
23
24
 
24
25
  def sourcecode(docxml)
@@ -50,6 +51,11 @@ module IsoDoc
50
51
  def source_remove_markup(elem)
51
52
  ret = {}
52
53
  name = elem.at(ns("./name")) and ret[:name] = name.remove.to_xml
54
+ source_remove_annotations(ret, elem)
55
+ ret
56
+ end
57
+
58
+ def source_remove_annotations(ret, elem)
53
59
  ret[:ann] = elem.xpath(ns("./annotation")).each(&:remove)
54
60
  ret[:call] = elem.xpath(ns("./callout")).each_with_object([]) do |c, m|
55
61
  m << { xml: c.remove.to_xml, line: c.line - elem.line }
@@ -99,9 +105,11 @@ module IsoDoc
99
105
  end
100
106
 
101
107
  def source_lex(elem)
102
- l = (Rouge::Lexer.find(elem["lang"] || "plaintext") ||
108
+ lexer = (Rouge::Lexer.find(elem["lang"] || "plaintext") ||
103
109
  Rouge::Lexer.find("plaintext"))
104
- l.lex(@c.decode(elem.children.to_xml))
110
+ l = Rouge::Lexers::Escape.new(start: "{^^{", end: "}^^}", lang: lexer)
111
+ source = to_xml(elem.children).gsub(/</, "{^^{<").gsub(/>/, ">}^^}")
112
+ l.lex(@c.decode(source))
105
113
  end
106
114
 
107
115
  def source_label(elem)
@@ -24,6 +24,7 @@ module IsoDoc
24
24
  end
25
25
 
26
26
  def conversions(docxml)
27
+ semantic_xml_insert(docxml)
27
28
  bibdata docxml
28
29
  @xrefs.parse docxml
29
30
  section docxml
@@ -84,6 +85,43 @@ module IsoDoc
84
85
  related docxml
85
86
  end
86
87
 
88
+ def semantic_xml_insert(xml)
89
+ @semantic_xml_insert or return
90
+ embed = to_xml(embedable_semantic_xml(xml))
91
+ ins = metanorma_extension_insert_pt(xml)
92
+ ins = ins.at(ns("./metanorma")) || ins.add_child("<metanorma/>").first
93
+ ins << "<source>#{embed}</source>"
94
+ end
95
+
96
+ def metanorma_extension_insert_pt(xml)
97
+ xml.at(ns("//metanorma-extension")) ||
98
+ xml.at(ns("//bibdata"))&.after("<metanorma-extension/>")
99
+ &.next_element ||
100
+ xml.root.elements.first.before("<metanorma-extension/>")
101
+ .previous_element
102
+ end
103
+
104
+ def embedable_semantic_xml(xml)
105
+ xml = embedable_semantic_xml_tags(xml)
106
+ embedable_semantic_xml_attributes(xml)
107
+ end
108
+
109
+ def embedable_semantic_xml_tags(xml)
110
+ Nokogiri::XML(to_xml(xml).gsub(%r{(</?)([[:alpha:]])},
111
+ "\\1semantic__\\2")).root
112
+ end
113
+
114
+ def embedable_semantic_xml_attributes(xml)
115
+ Metanorma::Utils::anchor_attributes.each do |(tag_name, attr_name)|
116
+ tag_name == "*" or tag_name = "semantic__#{tag_name}"
117
+ xml.xpath(ns("//#{tag_name}[@#{attr_name}]")).each do |elem|
118
+ elem.attributes[attr_name].value =
119
+ "semantic__#{elem.attributes[attr_name].value}"
120
+ end
121
+ end
122
+ xml
123
+ end
124
+
87
125
  def postprocess(result, filename, _dir)
88
126
  to_xml_file(result, filename)
89
127
  @files_to_delete.each { |f| FileUtils.rm_rf f }
@@ -1,3 +1,3 @@
1
1
  module IsoDoc
2
- VERSION = "2.4.2".freeze
2
+ VERSION = "2.4.3".freeze
3
3
  end
@@ -244,11 +244,11 @@ module IsoDoc
244
244
 
245
245
  def info(isoxml, out)
246
246
  @tocfigurestitle =
247
- isoxml&.at(ns("//misc-container/toc[@type = 'figure']/title"))&.text
247
+ isoxml&.at(ns("//metanorma-extension/toc[@type = 'figure']/title"))&.text
248
248
  @toctablestitle =
249
- isoxml&.at(ns("//misc-container/toc[@type = 'table']/title"))&.text
249
+ isoxml&.at(ns("//metanorma-extension/toc[@type = 'table']/title"))&.text
250
250
  @tocrecommendationstitle = isoxml
251
- &.at(ns("//misc-container/toc[@type = 'recommendation']/title"))&.text
251
+ &.at(ns("//metanorma-extension/toc[@type = 'recommendation']/title"))&.text
252
252
  super
253
253
  end
254
254
  end
@@ -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,17 +1,11 @@
1
1
  require "fileutils"
2
2
  require_relative "./postprocess_cover"
3
3
  require_relative "./postprocess_toc"
4
+ require_relative "./postprocess_table"
4
5
 
5
6
  module IsoDoc
6
7
  module WordFunction
7
8
  module Postprocess
8
- def table_note_cleanup(docxml)
9
- super
10
- # preempt html2doc putting MsoNormal there
11
- docxml.xpath("//p[not(self::*[@class])][ancestor::*[@class = 'Note']]")
12
- .each { |p| p["class"] = "Note" }
13
- end
14
-
15
9
  def postprocess(result, filename, dir)
16
10
  filename = filename.sub(/\.doc$/, "")
17
11
  header = generate_header(filename, dir)
@@ -55,6 +49,7 @@ module IsoDoc
55
49
  word_nested_tables(docxml)
56
50
  word_colgroup(docxml)
57
51
  word_table_align(docxml)
52
+ word_table_pagebreak(docxml)
58
53
  word_table_separator(docxml)
59
54
  word_admonition_images(docxml)
60
55
  word_list_continuations(docxml)
@@ -108,54 +103,6 @@ module IsoDoc
108
103
  end
109
104
  end
110
105
 
111
- def word_colgroup(docxml)
112
- cells2d = {}
113
- docxml.xpath("//table[colgroup]").each do |t|
114
- w = colgroup_widths(t)
115
- t.xpath(".//tr").each_with_index { |_tr, r| cells2d[r] = {} }
116
- t.xpath(".//tr").each_with_index do |tr, r|
117
- tr.xpath("./td | ./th").each_with_index do |td, _i|
118
- x = 0
119
- rs = td.attr("rowspan")&.to_i || 1
120
- cs = td.attr("colspan")&.to_i || 1
121
- while cells2d[r][x]
122
- x += 1
123
- end
124
- (r..(r + rs - 1)).each do |y2|
125
- cells2d[y2].nil? and next
126
- (x..(x + cs - 1)).each { |x2| cells2d[y2][x2] = 1 }
127
- end
128
- width = (x..(x + cs - 1)).each_with_object({ width: 0 }) do |z, m|
129
- m[:width] += w[z]
130
- end
131
- td["width"] = "#{width[:width]}%"
132
- x += cs
133
- end
134
- end
135
- end
136
- end
137
-
138
- # assume percentages
139
- def colgroup_widths(table)
140
- table.xpath("./colgroup/col").each_with_object([]) do |c, m|
141
- m << c["width"].sub(/%$/, "").to_f
142
- end
143
- end
144
-
145
- def word_nested_tables(docxml)
146
- docxml.xpath("//table").each do |t|
147
- t.xpath(".//table").reverse.each do |tt|
148
- t.next = tt.remove
149
- end
150
- end
151
- end
152
-
153
- def style_update(node, css)
154
- node or return
155
- node["style"] =
156
- node["style"] ? node["style"].sub(/;?$/, ";#{css}") : css
157
- end
158
-
159
106
  def word_image_caption(docxml)
160
107
  docxml.xpath("//p[@class = 'FigureTitle' or @class = 'SourceTitle']")
161
108
  .each do |t|
@@ -188,21 +135,6 @@ module IsoDoc
188
135
  end
189
136
  end
190
137
 
191
- def word_table_align(docxml)
192
- docxml.xpath("//td[@align]/p | //th[@align]/p").each do |p|
193
- p["align"] and next
194
- style_update(p, "text-align: #{p.parent['align']}")
195
- end
196
- end
197
-
198
- def word_table_separator(docxml)
199
- docxml.xpath("//p[@class = 'TableTitle']").each do |t|
200
- t.children.empty? or next
201
- t["style"] = t["style"].sub(/;?$/, ";font-size:0pt;")
202
- t.children = "&#xa0;"
203
- end
204
- end
205
-
206
138
  def word_annex_cleanup(docxml); end
207
139
 
208
140
  def word_example_cleanup(docxml)
@@ -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
@@ -24,35 +24,53 @@ module IsoDoc
24
24
  def make_tr_attr(cell, row, totalrows, header, bordered)
25
25
  style = cell.name == "th" ? "font-weight:bold;" : ""
26
26
  rowmax = cell["rowspan"] ? row + cell["rowspan"].to_i - 1 : row
27
- style += make_tr_attr_style(row, rowmax, totalrows, header, bordered)
27
+ style += make_tr_attr_style(cell, row, rowmax, totalrows,
28
+ { header: header, bordered: bordered })
28
29
  { rowspan: cell["rowspan"], colspan: cell["colspan"],
29
30
  valign: cell["valign"], align: cell["align"], style: style,
30
31
  class: cell["class"] }
31
32
  end
32
33
 
33
- def make_tr_attr_style(row, rowmax, totalrows, header, bordered)
34
+ def make_tr_attr_style(cell, row, rowmax, totalrows, opt)
35
+ top = row.zero? ? "#{SW1} 1.5pt;" : "none;"
36
+ bottom = "#{SW1} #{rowmax >= totalrows ? '1.5' : '1.0'}pt;"
34
37
  ret = <<~STYLE.gsub(/\n/, "")
35
- border-top:#{row.zero? ? "#{SW1} 1.5pt;" : 'none;'}
36
- mso-border-top-alt:#{row.zero? ? "#{SW1} 1.5pt;" : 'none;'}
37
- border-bottom:#{SW1} #{rowmax >= totalrows ? '1.5' : '1.0'}pt;
38
- mso-border-bottom-alt:#{SW1} #{rowmax >= totalrows ? '1.5' : '1.0'}pt;
38
+ border-top:#{top}mso-border-top-alt:#{top}
39
+ border-bottom:#{bottom}mso-border-bottom-alt:#{bottom}
39
40
  STYLE
40
- bordered or ret = ""
41
- pb = header || (totalrows <= 10 && rowmax < totalrows) ? "avoid" : "auto"
41
+ opt[:bordered] or ret = ""
42
+ pb = keep_rows_together(cell, rowmax, totalrows, opt) ? "avoid" : "auto"
42
43
  "#{ret}page-break-after:#{pb};"
43
44
  end
44
45
 
46
+ def keep_rows_together(cell, rowmax, totalrows, opt)
47
+ opt[:header] and return true
48
+ table_line_count(cell.parent.parent) > 15 and return false
49
+ (totalrows <= 10 && rowmax < totalrows)
50
+ end
51
+
52
+ def table_line_count(tbody)
53
+ sum = 0
54
+ tbody.xpath(ns(".//tr")).each do |r|
55
+ i = 1
56
+ r.xpath(ns(".//td | .//th")).each do |c|
57
+ n = c.xpath(ns(".//li | .//p | .//br")).size
58
+ n > i and i = n
59
+ end
60
+ sum += i
61
+ end
62
+ sum
63
+ end
64
+
45
65
  def table_attrs(node)
46
66
  c = node["class"]
47
67
  bordered = "border-spacing:0;border-width:1px;"
48
68
  (%w(modspec).include?(c) || !c) or bordered = nil
49
69
  ret = {
50
- summary: node["summary"],
51
- width: node["width"],
70
+ summary: node["summary"], width: node["width"],
52
71
  style: "mso-table-anchor-horizontal:column;mso-table-overlap:never;" \
53
72
  "#{bordered}#{keep_style(node)}",
54
- class: (node.text.length > 4000 ? "MsoISOTableBig" : "MsoISOTable"),
55
- }
73
+ class: (node.text.length > 4000 ? "MsoISOTableBig" : "MsoISOTable") }
56
74
  bordered or ret.delete(:class)
57
75
  super.merge(attr_code(ret))
58
76
  end
@@ -61,7 +79,7 @@ module IsoDoc
61
79
  colgroup = node.at(ns("./colgroup")) or return
62
80
  table.colgroup do |cg|
63
81
  colgroup.xpath(ns("./col")).each do |c|
64
- cg.col **{ width: c["width"] }
82
+ cg.col width: c["width"]
65
83
  end
66
84
  end
67
85
  end
@@ -69,7 +87,7 @@ module IsoDoc
69
87
  def table_parse(node, out)
70
88
  @in_table = true
71
89
  table_title_parse(node, out)
72
- out.div **{ align: "center", class: "table_container" } do |div|
90
+ out.div align: "center", class: "table_container" do |div|
73
91
  div.table **table_attrs(node) do |t|
74
92
  colgroup(node, t)
75
93
  thead_parse(node, t)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: isodoc
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.2
4
+ version: 2.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-30 00:00:00.000000000 Z
11
+ date: 2023-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciimath
@@ -480,6 +480,7 @@ files:
480
480
  - lib/isodoc/word_function/inline.rb
481
481
  - lib/isodoc/word_function/postprocess.rb
482
482
  - lib/isodoc/word_function/postprocess_cover.rb
483
+ - lib/isodoc/word_function/postprocess_table.rb
483
484
  - lib/isodoc/word_function/postprocess_toc.rb
484
485
  - lib/isodoc/word_function/table.rb
485
486
  - lib/isodoc/xref.rb