isodoc 1.6.1 → 1.6.6

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +2 -12
  3. data/.hound.yml +3 -1
  4. data/.rubocop.yml +4 -8
  5. data/Rakefile +2 -2
  6. data/isodoc.gemspec +4 -3
  7. data/lib/isodoc-yaml/i18n-ar.yaml +152 -0
  8. data/lib/isodoc-yaml/i18n-de.yaml +149 -0
  9. data/lib/isodoc-yaml/i18n-en.yaml +1 -0
  10. data/lib/isodoc-yaml/i18n-es.yaml +151 -0
  11. data/lib/isodoc-yaml/i18n-fr.yaml +1 -0
  12. data/lib/isodoc-yaml/i18n-ru.yaml +154 -0
  13. data/lib/isodoc-yaml/i18n-zh-Hans.yaml +1 -0
  14. data/lib/isodoc.rb +0 -2
  15. data/lib/isodoc/common.rb +2 -0
  16. data/lib/isodoc/convert.rb +8 -2
  17. data/lib/isodoc/function/blocks.rb +15 -4
  18. data/lib/isodoc/function/cleanup.rb +52 -43
  19. data/lib/isodoc/function/form.rb +51 -0
  20. data/lib/isodoc/function/inline.rb +8 -7
  21. data/lib/isodoc/function/references.rb +71 -77
  22. data/lib/isodoc/function/section.rb +28 -16
  23. data/lib/isodoc/function/table.rb +22 -22
  24. data/lib/isodoc/function/terms.rb +6 -7
  25. data/lib/isodoc/function/to_word_html.rb +19 -25
  26. data/lib/isodoc/function/utils.rb +181 -163
  27. data/lib/isodoc/gem_tasks.rb +8 -9
  28. data/lib/isodoc/headlesshtml_convert.rb +8 -7
  29. data/lib/isodoc/html_convert.rb +6 -0
  30. data/lib/isodoc/html_function/comments.rb +14 -12
  31. data/lib/isodoc/html_function/footnotes.rb +14 -7
  32. data/lib/isodoc/html_function/form.rb +62 -0
  33. data/lib/isodoc/html_function/html.rb +30 -26
  34. data/lib/isodoc/html_function/postprocess.rb +191 -182
  35. data/lib/isodoc/html_function/sectionsplit.rb +230 -0
  36. data/lib/isodoc/i18n.rb +13 -11
  37. data/lib/isodoc/metadata.rb +22 -20
  38. data/lib/isodoc/metadata_contributor.rb +31 -28
  39. data/lib/isodoc/pdf_convert.rb +11 -13
  40. data/lib/isodoc/presentation_function/bibdata.rb +54 -30
  41. data/lib/isodoc/presentation_function/inline.rb +70 -120
  42. data/lib/isodoc/presentation_function/math.rb +84 -0
  43. data/lib/isodoc/presentation_function/section.rb +55 -19
  44. data/lib/isodoc/presentation_xml_convert.rb +3 -0
  45. data/lib/isodoc/sassc_importer.rb +1 -1
  46. data/lib/isodoc/version.rb +1 -1
  47. data/lib/isodoc/word_function/body.rb +28 -24
  48. data/lib/isodoc/word_function/postprocess.rb +50 -36
  49. data/lib/isodoc/xref.rb +2 -0
  50. data/lib/isodoc/xref/xref_counter.rb +1 -2
  51. data/lib/isodoc/xref/xref_gen.rb +21 -14
  52. data/lib/isodoc/xref/xref_gen_seq.rb +60 -35
  53. data/lib/isodoc/xref/xref_sect_gen.rb +15 -15
  54. data/spec/assets/scripts_override.html +3 -0
  55. data/spec/isodoc/blocks_spec.rb +624 -997
  56. data/spec/isodoc/cleanup_spec.rb +40 -42
  57. data/spec/isodoc/form_spec.rb +156 -0
  58. data/spec/isodoc/i18n_spec.rb +694 -821
  59. data/spec/isodoc/inline_spec.rb +1105 -921
  60. data/spec/isodoc/metadata_spec.rb +384 -379
  61. data/spec/isodoc/postproc_spec.rb +461 -333
  62. data/spec/isodoc/presentation_xml_spec.rb +355 -278
  63. data/spec/isodoc/ref_spec.rb +5 -5
  64. data/spec/isodoc/section_spec.rb +216 -199
  65. data/spec/isodoc/sectionsplit_spec.rb +190 -0
  66. data/spec/isodoc/table_spec.rb +41 -42
  67. data/spec/isodoc/terms_spec.rb +84 -84
  68. data/spec/isodoc/xref_spec.rb +974 -932
  69. metadata +32 -7
@@ -1,17 +1,16 @@
1
1
  module IsoDoc::Function
2
2
  module Table
3
-
4
3
  def table_title_parse(node, out)
5
4
  name = node.at(ns("./name")) or return
6
5
  out.p **{ class: "TableTitle", style: "text-align:center;" } do |p|
7
- name and name.children.each { |n| parse(n, p) }
6
+ name&.children&.each { |n| parse(n, p) }
8
7
  end
9
8
  end
10
9
 
11
- def thead_parse(node, t)
10
+ def thead_parse(node, table)
12
11
  thead = node.at(ns("./thead"))
13
12
  if thead
14
- t.thead do |h|
13
+ table.thead do |h|
15
14
  thead.element_children.each_with_index do |n, i|
16
15
  tr_parse(n, h, i, thead.element_children.size, true)
17
16
  end
@@ -19,19 +18,19 @@ module IsoDoc::Function
19
18
  end
20
19
  end
21
20
 
22
- def tbody_parse(node, t)
21
+ def tbody_parse(node, table)
23
22
  tbody = node.at(ns("./tbody")) || return
24
- t.tbody do |h|
23
+ table.tbody do |h|
25
24
  tbody.element_children.each_with_index do |n, i|
26
25
  tr_parse(n, h, i, tbody.element_children.size, false)
27
26
  end
28
27
  end
29
28
  end
30
29
 
31
- def tfoot_parse(node, t)
30
+ def tfoot_parse(node, table)
32
31
  tfoot = node.at(ns("./tfoot"))
33
32
  if tfoot
34
- t.tfoot do |h|
33
+ table.tfoot do |h|
35
34
  tfoot.element_children.each_with_index do |n, i|
36
35
  tr_parse(n, h, i, tfoot.element_children.size, false)
37
36
  end
@@ -45,22 +44,23 @@ module IsoDoc::Function
45
44
  id: node["id"],
46
45
  class: "MsoISOTable",
47
46
  style: "border-width:1px;border-spacing:0;#{width}#{keep_style(node)}",
48
- title: node["alt"]
47
+ title: node["alt"],
49
48
  )
50
49
  end
51
50
 
52
- def tcaption(node, t)
51
+ def tcaption(node, table)
53
52
  return unless node["summary"]
54
- t.caption do |c|
53
+
54
+ table.caption do |c|
55
55
  c.span **{ style: "display:none" } do |s|
56
56
  s << node["summary"]
57
57
  end
58
58
  end
59
59
  end
60
60
 
61
- def colgroup(node, t)
61
+ def colgroup(node, table)
62
62
  colgroup = node.at(ns("./colgroup")) or return
63
- t.colgroup do |cg|
63
+ table.colgroup do |cg|
64
64
  colgroup.xpath(ns("./col")).each do |c|
65
65
  cg.col **{ style: "width: #{c['width']};" }
66
66
  end
@@ -89,19 +89,19 @@ module IsoDoc::Function
89
89
  # border-left:#{col.zero? ? "#{SW} 1.5pt;" : "none;"}
90
90
  # border-right:#{SW} #{col == totalcols && !header ? "1.5" : "1.0"}pt;
91
91
 
92
- def make_tr_attr(td, row, totalrows, header)
93
- style = td.name == "th" ? "font-weight:bold;" : ""
94
- td["align"] and style += "text-align:#{td['align']};"
95
- td["valign"] and style += "vertical-align:#{td['valign']};"
96
- rowmax = td["rowspan"] ? row + td["rowspan"].to_i - 1 : row
92
+ def make_tr_attr(cell, row, totalrows, header)
93
+ style = cell.name == "th" ? "font-weight:bold;" : ""
94
+ cell["align"] and style += "text-align:#{cell['align']};"
95
+ cell["valign"] and style += "vertical-align:#{cell['valign']};"
96
+ rowmax = cell["rowspan"] ? row + cell["rowspan"].to_i - 1 : row
97
97
  style += <<~STYLE
98
98
  border-top:#{row.zero? ? "#{SW} 1.5pt;" : 'none;'}
99
99
  border-bottom:#{SW} #{rowmax == totalrows ? '1.5' : '1.0'}pt;
100
100
  STYLE
101
- header and scope = (td["colspan"] ? "colgroup" : "col")
102
- !header and td.name == "th" and scope =
103
- (td["rowspan"] ? "rowgroup" : "row")
104
- { rowspan: td["rowspan"], colspan: td["colspan"],
101
+ header and scope = (cell["colspan"] ? "colgroup" : "col")
102
+ !header and cell.name == "th" and scope =
103
+ (cell["rowspan"] ? "rowgroup" : "row")
104
+ { rowspan: cell["rowspan"], colspan: cell["colspan"],
105
105
  style: style.gsub(/\n/, ""), scope: scope }
106
106
  end
107
107
 
@@ -11,27 +11,27 @@ module IsoDoc::Function
11
11
  end
12
12
 
13
13
  def deprecated_term_parse(node, out)
14
- out.p **{ class: "DeprecatedTerms", style:"text-align:left;" } do |p|
14
+ out.p **{ class: "DeprecatedTerms", style: "text-align:left;" } do |p|
15
15
  p << l10n("#{@i18n.deprecated}: ")
16
16
  node.children.each { |c| parse(c, p) }
17
17
  end
18
18
  end
19
19
 
20
20
  def admitted_term_parse(node, out)
21
- out.p **{ class: "AltTerms", style:"text-align:left;" } do |p|
21
+ out.p **{ class: "AltTerms", style: "text-align:left;" } do |p|
22
22
  node.children.each { |c| parse(c, p) }
23
23
  end
24
24
  end
25
25
 
26
26
  def term_parse(node, out)
27
- out.p **{ class: "Terms", style:"text-align:left;" } do |p|
27
+ out.p **{ class: "Terms", style: "text-align:left;" } do |p|
28
28
  node.children.each { |c| parse(c, p) }
29
29
  end
30
30
  end
31
31
 
32
- def para_then_remainder(first, node, p, div)
32
+ def para_then_remainder(first, node, para, div)
33
33
  if first.name == "p"
34
- first.children.each { |n| parse(n, p) }
34
+ first.children.each { |n| parse(n, para) }
35
35
  node.elements.drop(1).each { |n| parse(n, div) }
36
36
  else
37
37
  node.elements.each { |n| parse(n, div) }
@@ -72,7 +72,6 @@ module IsoDoc::Function
72
72
  node.children.each { |n| parse(n, out) }
73
73
  end
74
74
 
75
- def termdocsource_parse(_node, _out)
76
- end
75
+ def termdocsource_parse(_node, _out); end
77
76
  end
78
77
  end
@@ -18,19 +18,20 @@ module IsoDoc::Function
18
18
 
19
19
  def init_file(filename, debug)
20
20
  filepath = Pathname.new(filename)
21
- filename = filepath.sub_ext('').sub(/\.presentation$/, "").to_s
21
+ filename = filepath.sub_ext("").sub(/\.presentation$/, "").to_s
22
22
  dir = init_dir(filename, debug)
23
23
  @filename = filename
24
- @localdir = filepath.parent.to_s + '/'
24
+ @localdir = "#{filepath.parent}/"
25
25
  @sourcedir = @localdir
26
- @sourcefilename and @sourcedir = Pathname.new(@sourcefilename).parent.to_s + '/'
26
+ @sourcefilename and
27
+ @sourcedir = "#{Pathname.new(@sourcefilename).parent}/"
27
28
  [filename, dir]
28
29
  end
29
30
 
30
31
  def init_dir(filename, debug)
31
32
  dir = "#{filename}_files"
32
33
  unless debug
33
- Dir.mkdir(dir, 0777) unless File.exists?(dir)
34
+ Dir.mkdir(dir, 0o777) unless File.exists?(dir)
34
35
  FileUtils.rm_rf "#{dir}/*"
35
36
  end
36
37
  dir
@@ -47,13 +48,11 @@ module IsoDoc::Function
47
48
 
48
49
  # isodoc.css overrides any CSS injected by Html2Doc, which
49
50
  # is inserted before this CSS.
50
- def define_head(head, filename, _dir)
51
+ def define_head(head, _filename, _dir)
51
52
  if @standardstylesheet
52
53
  head.style do |style|
53
54
  @standardstylesheet.open
54
- stylesheet = @standardstylesheet.read.gsub(
55
- "FILENAME", File.basename(filename).sub(/\.presentation$/, "")
56
- )
55
+ stylesheet = @standardstylesheet.read
57
56
  style.comment "\n#{stylesheet}\n"
58
57
  end
59
58
  end
@@ -78,7 +77,7 @@ module IsoDoc::Function
78
77
  section_break(body)
79
78
  end
80
79
 
81
- def make_body2(body, docxml)
80
+ def make_body2(body, _docxml)
82
81
  body.div **{ class: "prefatory-section" } do |div2|
83
82
  div2.p { |p| p << "&nbsp;" } # placeholder
84
83
  end
@@ -117,16 +116,6 @@ module IsoDoc::Function
117
116
  @meta.get
118
117
  end
119
118
 
120
- def middle_title(_isoxml, out)
121
- out.p(**{ class: "zzSTDTitle1" }) { |p| p << @meta.get[:doctitle] }
122
- end
123
-
124
- def middle_admonitions(isoxml, out)
125
- isoxml.xpath(ns("//sections/note | //sections/admonition")).each do |x|
126
- parse(x, out)
127
- end
128
- end
129
-
130
119
  def middle(isoxml, out)
131
120
  middle_title(isoxml, out)
132
121
  middle_admonitions(isoxml, out)
@@ -140,6 +129,8 @@ module IsoDoc::Function
140
129
  end
141
130
 
142
131
  def boilerplate(node, out)
132
+ return if @bare
133
+
143
134
  boilerplate = node.at(ns("//boilerplate")) or return
144
135
  out.div **{ class: "authority" } do |s|
145
136
  boilerplate.children.each do |n|
@@ -147,16 +138,14 @@ module IsoDoc::Function
147
138
  s.h1 do |h|
148
139
  n.children.each { |nn| parse(nn, h) }
149
140
  end
150
- else
151
- parse(n, s)
141
+ else parse(n, s)
152
142
  end
153
143
  end
154
144
  end
155
145
  end
156
146
 
157
147
  def parse(node, out)
158
- if node.text?
159
- text_parse(node, out)
148
+ if node.text? then text_parse(node, out)
160
149
  else
161
150
  case node.name
162
151
  when "em" then em_parse(node, out)
@@ -236,8 +225,13 @@ module IsoDoc::Function
236
225
  when "svg" then svg_parse(node, out) # in Presentation XML only
237
226
  when "add" then add_parse(node, out)
238
227
  when "del" then del_parse(node, out)
239
- else
240
- error_parse(node, out)
228
+ when "form" then form_parse(node, out)
229
+ when "input" then input_parse(node, out)
230
+ when "select" then select_parse(node, out)
231
+ when "label" then label_parse(node, out)
232
+ when "option" then option_parse(node, out)
233
+ when "textarea" then textarea_parse(node, out)
234
+ else error_parse(node, out)
241
235
  end
242
236
  end
243
237
  end
@@ -1,193 +1,211 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module IsoDoc::Function
4
- module Utils
5
- def date_range(date)
6
- self.class.date_range(date)
7
- end
3
+ module IsoDoc
4
+ module Function
5
+ module Utils
6
+ def date_range(date)
7
+ self.class.date_range(date)
8
+ end
8
9
 
9
- def ns(xpath)
10
- self.class.ns(xpath)
11
- end
10
+ def ns(xpath)
11
+ self.class.ns(xpath)
12
+ end
12
13
 
13
- def insert_tab(out, n)
14
- tab = %w(Hans Hant).include?(@script) ? "&#x3000;" : "&nbsp; "
15
- [1..n].each { out << tab }
16
- end
14
+ def insert_tab(out, count)
15
+ tab = %w(Hans Hant).include?(@script) ? "&#x3000;" : "&nbsp; "
16
+ [1..count].each { out << tab }
17
+ end
17
18
 
18
- # add namespaces for Word fragments
19
- NOKOHEAD = <<~HERE
20
- <!DOCTYPE html SYSTEM
21
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
22
- <html xmlns="http://www.w3.org/1999/xhtml">
23
- <head> <title></title> <meta charset="UTF-8" /> </head>
24
- <body> </body> </html>
25
- HERE
26
-
27
- # block for processing XML document fragments as XHTML,
28
- # to allow for HTMLentities
29
- def noko(&block)
30
- doc = ::Nokogiri::XML.parse(NOKOHEAD)
31
- fragment = doc.fragment("")
32
- ::Nokogiri::XML::Builder.with fragment, &block
33
- fragment.to_xml(encoding: "US-ASCII").lines.map do |l|
34
- l.gsub(/\s*\n/, "")
19
+ # add namespaces for Word fragments
20
+ NOKOHEAD = <<~HERE
21
+ <!DOCTYPE html SYSTEM
22
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
23
+ <html xmlns="http://www.w3.org/1999/xhtml">
24
+ <head> <title></title> <meta charset="UTF-8" /> </head>
25
+ <body> </body> </html>
26
+ HERE
27
+
28
+ # block for processing XML document fragments as XHTML,
29
+ # to allow for HTMLentities
30
+ def noko(&block)
31
+ doc = ::Nokogiri::XML.parse(NOKOHEAD)
32
+ fragment = doc.fragment("")
33
+ ::Nokogiri::XML::Builder.with fragment, &block
34
+ fragment.to_xml(encoding: "US-ASCII").lines.map do |l|
35
+ l.gsub(/\s*\n/, "")
36
+ end
35
37
  end
36
- end
37
38
 
38
- def attr_code(attributes)
39
- attributes = attributes.reject { |_, val| val.nil? }.map
40
- attributes.map do |k, v|
41
- [k, v.is_a?(String) ? HTMLEntities.new.decode(v) : v]
42
- end.to_h
43
- end
39
+ def attr_code(attributes)
40
+ attributes = attributes.reject { |_, val| val.nil? }.map
41
+ attributes.map do |k, v|
42
+ [k, v.is_a?(String) ? HTMLEntities.new.decode(v) : v]
43
+ end.to_h
44
+ end
44
45
 
45
- DOCTYPE_HDR = '<!DOCTYPE html SYSTEM '\
46
- '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
47
-
48
- def to_xhtml(xml)
49
- xml.gsub!(/<\?xml[^>]*>/, "")
50
- /<!DOCTYPE /.match(xml) || (xml = DOCTYPE_HDR + xml)
51
- xml = xml.split(/(\&[^ \r\n\t#;]+;)/).map do |t|
52
- /^(\&[^ \t\r\n#;]+;)/.match?(t) ?
53
- HTMLEntities.new.encode(HTMLEntities.new.decode(t), :hexadecimal) : t
54
- end.join("")
55
- begin
56
- Nokogiri::XML.parse(xml, &:strict)
57
- rescue Nokogiri::XML::SyntaxError => e
58
- File.open("#{@filename}.#{@format}.err", "w:UTF-8") { |f| f.write xml }
59
- abort "Malformed Output XML for #{@format}: #{e} "\
60
- "(see #{@filename}.#{@format}.err)"
46
+ DOCTYPE_HDR = "<!DOCTYPE html SYSTEM "\
47
+ '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
48
+
49
+ def to_xhtml(xml)
50
+ xml = to_xhtml_prep(xml)
51
+ begin
52
+ Nokogiri::XML.parse(xml, &:strict)
53
+ rescue Nokogiri::XML::SyntaxError => e
54
+ File.open("#{@filename}.#{@format}.err", "w:UTF-8") do |f|
55
+ f.write xml
56
+ end
57
+ abort "Malformed Output XML for #{@format}: #{e} "\
58
+ "(see #{@filename}.#{@format}.err)"
59
+ end
61
60
  end
62
- end
63
61
 
64
- def to_xhtml_fragment(xml)
65
- doc = ::Nokogiri::XML.parse(NOKOHEAD)
66
- fragment = doc.fragment(xml)
67
- fragment
68
- end
62
+ def to_xhtml_prep(xml)
63
+ xml.gsub!(/<\?xml[^>]*>/, "")
64
+ /<!DOCTYPE /.match(xml) || (xml = DOCTYPE_HDR + xml)
65
+ xml.split(/(&[^ \r\n\t#;]+;)/).map do |t|
66
+ if /^(&[^ \t\r\n#;]+;)/.match?(t)
67
+ HTMLEntities.new.encode(HTMLEntities.new.decode(t), :hexadecimal)
68
+ else t
69
+ end
70
+ end.join("")
71
+ end
69
72
 
70
- def from_xhtml(xml)
71
- xml.to_xml.sub(%r{ xmlns="http://www.w3.org/1999/xhtml"}, "")
72
- end
73
+ def to_xhtml_fragment(xml)
74
+ doc = ::Nokogiri::XML.parse(NOKOHEAD)
75
+ doc.fragment(xml)
76
+ end
73
77
 
74
- CLAUSE_ANCESTOR =
75
- ".//ancestor::*[local-name() = 'annex' or "\
76
- "local-name() = 'definitions' or "\
77
- "local-name() = 'acknowledgements' or local-name() = 'term' or "\
78
- "local-name() = 'appendix' or local-name() = 'foreword' or "\
79
- "local-name() = 'introduction' or local-name() = 'terms' or "\
80
- "local-name() = 'clause' or local-name() = 'references']/@id"
81
-
82
- def get_clause_id(node)
83
- clause = node.xpath(CLAUSE_ANCESTOR)
84
- clause&.last&.text || nil
85
- end
78
+ def from_xhtml(xml)
79
+ xml.to_xml.sub(%r{ xmlns="http://www.w3.org/1999/xhtml"}, "")
80
+ end
86
81
 
87
- NOTE_CONTAINER_ANCESTOR =
88
- ".//ancestor::*[local-name() = 'annex' or "\
89
- "local-name() = 'foreword' or local-name() = 'appendix' or "\
90
- "local-name() = 'introduction' or local-name() = 'terms' or "\
91
- "local-name() = 'acknowledgements' or local-name() = 'term' or "\
92
- "local-name() = 'clause' or local-name() = 'references' or "\
93
- "local-name() = 'figure' or local-name() = 'formula' or "\
94
- "local-name() = 'table' or local-name() = 'example']/@id"
95
-
96
- def get_note_container_id(node)
97
- container = node.xpath(NOTE_CONTAINER_ANCESTOR)
98
- container&.last&.text || nil
99
- end
82
+ CLAUSE_ANCESTOR =
83
+ ".//ancestor::*[local-name() = 'annex' or "\
84
+ "local-name() = 'definitions' or "\
85
+ "local-name() = 'acknowledgements' or local-name() = 'term' or "\
86
+ "local-name() = 'appendix' or local-name() = 'foreword' or "\
87
+ "local-name() = 'introduction' or local-name() = 'terms' or "\
88
+ "local-name() = 'clause' or local-name() = 'references']/@id"
89
+
90
+ def get_clause_id(node)
91
+ clause = node.xpath(CLAUSE_ANCESTOR)
92
+ clause&.last&.text || nil
93
+ end
100
94
 
101
- def sentence_join(array)
102
- return '' if array.nil? || array.empty?
103
- if array.length == 1 then array[0]
104
- else
105
- @i18n.l10n("#{array[0..-2].join(', ')} "\
106
- "#{@i18n.and} #{array.last}",
107
- @lang, @script)
95
+ NOTE_CONTAINER_ANCESTOR =
96
+ ".//ancestor::*[local-name() = 'annex' or "\
97
+ "local-name() = 'foreword' or local-name() = 'appendix' or "\
98
+ "local-name() = 'introduction' or local-name() = 'terms' or "\
99
+ "local-name() = 'acknowledgements' or local-name() = 'term' or "\
100
+ "local-name() = 'clause' or local-name() = 'references' or "\
101
+ "local-name() = 'figure' or local-name() = 'formula' or "\
102
+ "local-name() = 'table' or local-name() = 'example']/@id"
103
+
104
+ def get_note_container_id(node)
105
+ container = node.xpath(NOTE_CONTAINER_ANCESTOR)
106
+ container&.last&.text || nil
108
107
  end
109
- end
110
108
 
111
- # avoid `; avoid {{ (Liquid Templates); avoid [[ (Javascript)
112
- def extract_delims(text)
113
- @openmathdelim = "(#("
114
- @closemathdelim = ")#)"
115
- while text.include?(@openmathdelim) || text.include?(@closemathdelim)
116
- @openmathdelim += "("
117
- @closemathdelim += ")"
109
+ def sentence_join(array)
110
+ return "" if array.nil? || array.empty?
111
+
112
+ if array.length == 1 then array[0]
113
+ else
114
+ @i18n.l10n("#{array[0..-2].join(', ')} "\
115
+ "#{@i18n.and} #{array.last}",
116
+ @lang, @script)
117
+ end
118
118
  end
119
- [@openmathdelim, @closemathdelim]
120
- end
121
119
 
122
- def header_strip(h)
123
- h = h.to_s.gsub(%r{<br\s*/>}, " ").gsub(/<\/?h[123456][^>]*>/, "")
124
- .gsub(/<\/?b[^>]*>/, "")
125
- h1 = to_xhtml_fragment(h.dup)
126
- h1.traverse do |x|
127
- x.replace(" ") if x.name == "span" && /mso-tab-count/.match(x["style"])
128
- x.remove if x.name == "img"
129
- x.remove if x.name == "span" && x["class"] == "MsoCommentReference"
130
- x.remove if x.name == "a" && x["class"] == "FootnoteRef"
131
- x.remove if x.name == "span" && /mso-bookmark/.match(x["style"])
132
- x.replace(x.children) if x.name == "a"
133
- end
134
- from_xhtml(h1)
135
- end
120
+ # avoid `; avoid {{ (Liquid Templates); avoid [[ (Javascript)
121
+ def extract_delims(text)
122
+ @openmathdelim = "(#("
123
+ @closemathdelim = ")#)"
124
+ while text.include?(@openmathdelim) || text.include?(@closemathdelim)
125
+ @openmathdelim += "("
126
+ @closemathdelim += ")"
127
+ end
128
+ [@openmathdelim, @closemathdelim]
129
+ end
136
130
 
137
- def liquid(doc)
138
- self.class.liquid(doc)
139
- end
131
+ def header_strip(hdr)
132
+ h1 = to_xhtml_fragment(hdr.to_s.gsub(%r{<br\s*/>}, " ")
133
+ .gsub(/<\/?h[123456][^>]*>/, "").gsub(/<\/?b[^>]*>/, "").dup)
134
+ h1.traverse do |x|
135
+ if x.name == "span" && /mso-tab-count/.match(x["style"])
136
+ x.replace(" ")
137
+ elsif header_strip_elem?(x) then x.remove
138
+ elsif x.name == "a" then x.replace(x.children)
139
+ end
140
+ end
141
+ from_xhtml(h1)
142
+ end
140
143
 
141
- def liquid(doc)
142
- # unescape HTML escapes in doc
143
- doc = doc.split(%r<(\{%|%\})>).each_slice(4).map do |a|
144
- a[2] = a[2].gsub(/\&lt;/, "<").gsub(/\&gt;/, ">") if a.size > 2
145
- a.join("")
146
- end.join("")
147
- Liquid::Template.parse(doc)
148
- end
144
+ def header_strip_elem?(elem)
145
+ elem.name == "img" ||
146
+ elem.name == "span" && elem["class"] == "MsoCommentReference" ||
147
+ elem.name == "a" && elem["class"] == "FootnoteRef" ||
148
+ elem.name == "span" && /mso-bookmark/.match(elem["style"])
149
+ end
149
150
 
150
- def empty2nil(v)
151
- return nil if !v.nil? && v.is_a?(String) && v.empty?
152
- v
153
- end
151
+ =begin
152
+ def liquid(doc)
153
+ self.class.liquid(doc)
154
+ end
155
+ =end
156
+
157
+ def liquid(doc)
158
+ # unescape HTML escapes in doc
159
+ doc = doc.split(%r<(\{%|%\})>).each_slice(4).map do |a|
160
+ a[2] = a[2].gsub(/&lt;/, "<").gsub(/&gt;/, ">") if a.size > 2
161
+ a.join("")
162
+ end.join("")
163
+ Liquid::Template.parse(doc)
164
+ end
154
165
 
155
- def populate_template(docxml, _format = nil)
156
- meta = @meta
157
- .get
158
- .merge(@labels ? {labels: @labels} : {})
159
- .merge(@meta.labels ? {labels: @meta.labels} : {})
160
- .merge(fonts_options || {})
161
- template = liquid(docxml)
162
- template.render(meta.map { |k, v| [k.to_s, empty2nil(v)] }.to_h)
163
- .gsub("&lt;", "&#x3c;").gsub("&gt;", "&#x3e;").gsub("&amp;", "&#x26;")
164
- end
166
+ def empty2nil(str)
167
+ return nil if !str.nil? && str.is_a?(String) && str.empty?
165
168
 
166
- def save_dataimage(uri, _relative_dir = true)
167
- %r{^data:(image|application)/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ uri
168
- imgtype.sub!(/\+[a-z0-9]+$/, "") # svg+xml
169
- imgtype = "png" unless /^[a-z0-9]+$/.match imgtype
170
- Tempfile.open(["image", ".#{imgtype}"]) do |f|
171
- f.binmode
172
- f.write(Base64.strict_decode64(imgdata))
173
- @tempfile_cache << f # persist to the end
174
- f.path
169
+ str
175
170
  end
176
- end
177
171
 
178
- def image_localfile(i)
179
- if /^data:/.match? i["src"]
180
- save_dataimage(i["src"], false)
181
- elsif %r{^([A-Z]:)?/}.match? i["src"]
182
- i["src"]
183
- else
184
- File.join(@localdir, i["src"])
172
+ def populate_template(docxml, _format = nil)
173
+ meta = @meta
174
+ .get
175
+ .merge(@labels ? { labels: @labels } : {})
176
+ .merge(@meta.labels ? { labels: @meta.labels } : {})
177
+ .merge(fonts_options || {})
178
+ template = liquid(docxml)
179
+ template.render(meta.map { |k, v| [k.to_s, empty2nil(v)] }.to_h)
180
+ .gsub("&lt;", "&#x3c;").gsub("&gt;", "&#x3e;").gsub("&amp;", "&#x26;")
185
181
  end
186
- end
187
182
 
188
- def labelled_ancestor(node)
189
- !node.ancestors("example, requirement, recommendation, permission, "\
190
- "note, table, figure, sourcecode").empty?
183
+ def save_dataimage(uri, _relative_dir = true)
184
+ %r{^data:(image|application)/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ uri
185
+ imgtype.sub!(/\+[a-z0-9]+$/, "") # svg+xml
186
+ imgtype = "png" unless /^[a-z0-9]+$/.match? imgtype
187
+ Tempfile.open(["image", ".#{imgtype}"]) do |f|
188
+ f.binmode
189
+ f.write(Base64.strict_decode64(imgdata))
190
+ @tempfile_cache << f # persist to the end
191
+ f.path
192
+ end
193
+ end
194
+
195
+ def image_localfile(img)
196
+ if /^data:/.match? img["src"]
197
+ save_dataimage(img["src"], false)
198
+ elsif %r{^([A-Z]:)?/}.match? img["src"]
199
+ img["src"]
200
+ else
201
+ File.join(@localdir, img["src"])
202
+ end
203
+ end
204
+
205
+ def labelled_ancestor(node)
206
+ !node.ancestors("example, requirement, recommendation, permission, "\
207
+ "note, table, figure, sourcecode").empty?
208
+ end
191
209
  end
192
210
  end
193
211
  end