isodoc 1.6.0 → 1.6.5

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 (76) 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/bin/rspec +1 -2
  7. data/isodoc.gemspec +4 -3
  8. data/lib/isodoc-yaml/i18n-ar.yaml +152 -0
  9. data/lib/isodoc-yaml/i18n-de.yaml +149 -0
  10. data/lib/isodoc-yaml/i18n-en.yaml +1 -0
  11. data/lib/isodoc-yaml/i18n-es.yaml +151 -0
  12. data/lib/isodoc-yaml/i18n-fr.yaml +1 -0
  13. data/lib/isodoc-yaml/i18n-ru.yaml +154 -0
  14. data/lib/isodoc-yaml/i18n-zh-Hans.yaml +1 -0
  15. data/lib/isodoc.rb +0 -2
  16. data/lib/isodoc/common.rb +2 -0
  17. data/lib/isodoc/convert.rb +10 -4
  18. data/lib/isodoc/css.rb +30 -26
  19. data/lib/isodoc/function/blocks.rb +26 -8
  20. data/lib/isodoc/function/blocks_example_note.rb +2 -2
  21. data/lib/isodoc/function/cleanup.rb +53 -45
  22. data/lib/isodoc/function/form.rb +51 -0
  23. data/lib/isodoc/function/inline.rb +8 -7
  24. data/lib/isodoc/function/references.rb +71 -77
  25. data/lib/isodoc/function/section.rb +28 -16
  26. data/lib/isodoc/function/table.rb +22 -22
  27. data/lib/isodoc/function/terms.rb +6 -7
  28. data/lib/isodoc/function/to_word_html.rb +19 -25
  29. data/lib/isodoc/function/utils.rb +180 -160
  30. data/lib/isodoc/gem_tasks.rb +36 -38
  31. data/lib/isodoc/headlesshtml_convert.rb +8 -7
  32. data/lib/isodoc/html_convert.rb +10 -4
  33. data/lib/isodoc/html_function/comments.rb +14 -12
  34. data/lib/isodoc/html_function/footnotes.rb +14 -7
  35. data/lib/isodoc/html_function/form.rb +62 -0
  36. data/lib/isodoc/html_function/html.rb +30 -26
  37. data/lib/isodoc/html_function/postprocess.rb +191 -226
  38. data/lib/isodoc/html_function/postprocess_footnotes.rb +59 -0
  39. data/lib/isodoc/html_function/sectionsplit.rb +230 -0
  40. data/lib/isodoc/i18n.rb +33 -31
  41. data/lib/isodoc/metadata.rb +22 -20
  42. data/lib/isodoc/metadata_contributor.rb +31 -28
  43. data/lib/isodoc/pdf_convert.rb +11 -13
  44. data/lib/isodoc/presentation_function/bibdata.rb +54 -30
  45. data/lib/isodoc/presentation_function/block.rb +17 -8
  46. data/lib/isodoc/presentation_function/inline.rb +72 -120
  47. data/lib/isodoc/presentation_function/math.rb +84 -0
  48. data/lib/isodoc/presentation_function/section.rb +55 -19
  49. data/lib/isodoc/presentation_xml_convert.rb +2 -0
  50. data/lib/isodoc/sassc_importer.rb +1 -1
  51. data/lib/isodoc/version.rb +1 -1
  52. data/lib/isodoc/word_function/body.rb +28 -24
  53. data/lib/isodoc/word_function/footnotes.rb +22 -15
  54. data/lib/isodoc/word_function/postprocess.rb +50 -36
  55. data/lib/isodoc/xref.rb +11 -10
  56. data/lib/isodoc/xref/xref_counter.rb +32 -17
  57. data/lib/isodoc/xref/xref_gen.rb +33 -21
  58. data/lib/isodoc/xref/xref_gen_seq.rb +60 -35
  59. data/lib/isodoc/xref/xref_sect_gen.rb +37 -35
  60. data/spec/assets/scripts_override.html +3 -0
  61. data/spec/isodoc/blocks_spec.rb +2258 -2622
  62. data/spec/isodoc/cleanup_spec.rb +1103 -1107
  63. data/spec/isodoc/form_spec.rb +156 -0
  64. data/spec/isodoc/i18n_spec.rb +802 -917
  65. data/spec/isodoc/inline_spec.rb +1105 -921
  66. data/spec/isodoc/lists_spec.rb +316 -315
  67. data/spec/isodoc/metadata_spec.rb +384 -379
  68. data/spec/isodoc/postproc_spec.rb +1783 -1549
  69. data/spec/isodoc/presentation_xml_spec.rb +355 -278
  70. data/spec/isodoc/ref_spec.rb +718 -723
  71. data/spec/isodoc/section_spec.rb +216 -199
  72. data/spec/isodoc/sectionsplit_spec.rb +190 -0
  73. data/spec/isodoc/table_spec.rb +41 -42
  74. data/spec/isodoc/terms_spec.rb +84 -84
  75. data/spec/isodoc/xref_spec.rb +1024 -930
  76. metadata +33 -7
@@ -8,11 +8,11 @@ module IsoDoc::Function
8
8
  insert_tab(out, 1)
9
9
  end
10
10
 
11
- def inline_header_title(out, node, title)
11
+ def inline_header_title(out, _node, title)
12
12
  out.span **{ class: "zzMoveToFollowing" } do |s|
13
13
  s.b do |b|
14
14
  title&.children&.each { |c2| parse(c2, b) }
15
- clausedelimspace(out) if /\S/.match(title&.text)
15
+ clausedelimspace(out) if /\S/.match?(title&.text)
16
16
  end
17
17
  end
18
18
  end
@@ -20,12 +20,14 @@ module IsoDoc::Function
20
20
  # used for subclauses
21
21
  def clause_parse_title(node, div, title, out, header_class = {})
22
22
  return if title.nil?
23
+
23
24
  if node["inline-header"] == "true"
24
25
  inline_header_title(out, node, title)
25
26
  else
26
- depth = (title && title["depth"]) ? title["depth"] :
27
- node.ancestors("clause, annex, terms, references, definitions, "\
28
- "acknowledgements, introduction, foreword").size + 1
27
+ depth = if title && title["depth"] then title["depth"]
28
+ else node.ancestors("clause, annex, terms, references, definitions, "\
29
+ "acknowledgements, introduction, foreword").size + 1
30
+ end
29
31
  div.send "h#{depth}", **attr_code(header_class) do |h|
30
32
  title&.children&.each { |c2| parse(c2, h) }
31
33
  end
@@ -49,8 +51,11 @@ module IsoDoc::Function
49
51
  def clause_name(_num, title, div, header_class)
50
52
  header_class = {} if header_class.nil?
51
53
  div.h1 **attr_code(header_class) do |h1|
52
- title.is_a?(String) ? h1 << title :
54
+ if title.is_a?(String)
55
+ h1 << title
56
+ else
53
57
  title&.children&.each { |c2| parse(c2, h1) }
58
+ end
54
59
  end
55
60
  div.parent.at(".//h1")
56
61
  end
@@ -66,8 +71,9 @@ module IsoDoc::Function
66
71
  end
67
72
  end
68
73
 
69
- def annex_name(annex, name, div)
74
+ def annex_name(_annex, name, div)
70
75
  return if name.nil?
76
+
71
77
  div.h1 **{ class: "Annex" } do |t|
72
78
  name.children.each { |c2| parse(c2, t) }
73
79
  end
@@ -144,7 +150,6 @@ module IsoDoc::Function
144
150
 
145
151
  def introduction(isoxml, out)
146
152
  f = isoxml.at(ns("//introduction")) || return
147
- title_attr = { class: "IntroTitle" }
148
153
  page_break(out)
149
154
  out.div **{ class: "Section3", id: f["id"] } do |div|
150
155
  clause_name(nil, f.at(ns("./title")), div, { class: "IntroTitle" })
@@ -160,7 +165,6 @@ module IsoDoc::Function
160
165
  out.div **attr_code(id: f["id"]) do |s|
161
166
  clause_name(nil, f.at(ns("./title")) || @i18n.foreword, s,
162
167
  { class: "ForewordTitle" })
163
- #s.h1(**{ class: "ForewordTitle" }) { |h1| h1 << @i18n.foreword }
164
168
  f.elements.each { |e| parse(e, s) unless e.name == "title" }
165
169
  end
166
170
  end
@@ -187,12 +191,11 @@ module IsoDoc::Function
187
191
  end
188
192
 
189
193
  def preface(isoxml, out)
190
- title_attr = { class: "IntroTitle" }
191
194
  isoxml.xpath(ns("//preface/clause | //preface/references | "\
192
195
  "//preface/definitions | //preface/terms")).each do |f|
193
196
  page_break(out)
194
197
  out.div **{ class: "Section3", id: f["id"] } do |div|
195
- clause_name(nil, f&.at(ns("./title")), div, title_attr)
198
+ clause_name(nil, f&.at(ns("./title")), div, { class: "IntroTitle" })
196
199
  f.elements.each do |e|
197
200
  parse(e, div) unless e.name == "title"
198
201
  end
@@ -202,37 +205,46 @@ module IsoDoc::Function
202
205
 
203
206
  def is_clause?(name)
204
207
  %w(clause references definitions terms foreword introduction abstract
205
- acknowledgements).include? name
208
+ acknowledgements).include? name
206
209
  end
207
210
 
208
211
  def preface_block(isoxml, out)
209
212
  p = isoxml.at(ns("//preface")) or return
210
213
  p.elements.each do |e|
211
214
  next if is_clause?(e.name)
215
+
212
216
  parse(e, out)
213
217
  end
214
218
  end
215
219
 
216
220
  def copyright_parse(node, out)
217
- out.div **{class: "boilerplate-copyright"} do |div|
221
+ return if @bare
222
+
223
+ out.div **{ class: "boilerplate-copyright" } do |div|
218
224
  node.children.each { |n| parse(n, div) }
219
225
  end
220
226
  end
221
227
 
222
228
  def license_parse(node, out)
223
- out.div **{class: "boilerplate-license"} do |div|
229
+ return if @bare
230
+
231
+ out.div **{ class: "boilerplate-license" } do |div|
224
232
  node.children.each { |n| parse(n, div) }
225
233
  end
226
234
  end
227
235
 
228
236
  def legal_parse(node, out)
229
- out.div **{class: "boilerplate-legal"} do |div|
237
+ return if @bare
238
+
239
+ out.div **{ class: "boilerplate-legal" } do |div|
230
240
  node.children.each { |n| parse(n, div) }
231
241
  end
232
242
  end
233
243
 
234
244
  def feedback_parse(node, out)
235
- out.div **{class: "boilerplate-feedback"} do |div|
245
+ return if @bare
246
+
247
+ out.div **{ class: "boilerplate-feedback" } do |div|
236
248
  node.children.each { |n| parse(n, div) }
237
249
  end
238
250
  end
@@ -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,191 +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} (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
60
60
  end
61
- end
62
61
 
63
- def to_xhtml_fragment(xml)
64
- doc = ::Nokogiri::XML.parse(NOKOHEAD)
65
- fragment = doc.fragment(xml)
66
- fragment
67
- 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
68
72
 
69
- def from_xhtml(xml)
70
- xml.to_xml.sub(%r{ xmlns="http://www.w3.org/1999/xhtml"}, '')
71
- end
73
+ def to_xhtml_fragment(xml)
74
+ doc = ::Nokogiri::XML.parse(NOKOHEAD)
75
+ doc.fragment(xml)
76
+ end
72
77
 
73
- CLAUSE_ANCESTOR =
74
- ".//ancestor::*[local-name() = 'annex' or "\
75
- "local-name() = 'acknowledgements' or local-name() = 'term' or "\
76
- "local-name() = 'appendix' or local-name() = 'foreword' or "\
77
- "local-name() = 'introduction' or local-name() = 'terms' or "\
78
- "local-name() = 'clause' or local-name() = 'references']/@id"
78
+ def from_xhtml(xml)
79
+ xml.to_xml.sub(%r{ xmlns="http://www.w3.org/1999/xhtml"}, "")
80
+ end
79
81
 
80
- def get_clause_id(node)
81
- clause = node.xpath(CLAUSE_ANCESTOR)
82
- clause&.last&.text || nil
83
- 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
84
94
 
85
- NOTE_CONTAINER_ANCESTOR =
86
- ".//ancestor::*[local-name() = 'annex' or "\
87
- "local-name() = 'foreword' or local-name() = 'appendix' or "\
88
- "local-name() = 'introduction' or local-name() = 'terms' or "\
89
- "local-name() = 'acknowledgements' or local-name() = 'term' or "\
90
- "local-name() = 'clause' or local-name() = 'references' or "\
91
- "local-name() = 'figure' or local-name() = 'formula' or "\
92
- "local-name() = 'table' or local-name() = 'example']/@id"
93
-
94
- def get_note_container_id(node)
95
- container = node.xpath(NOTE_CONTAINER_ANCESTOR)
96
- container&.last&.text || nil
97
- end
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
107
+ end
98
108
 
99
- def sentence_join(array)
100
- return '' if array.nil? || array.empty?
101
- if array.length == 1 then array[0]
102
- else
103
- @i18n.l10n("#{array[0..-2].join(', ')} "\
104
- "#{@i18n.and} #{array.last}",
105
- @lang, @script)
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
106
118
  end
107
- end
108
119
 
109
- # avoid `; avoid {{ (Liquid Templates); avoid [[ (Javascript)
110
- def extract_delims(text)
111
- @openmathdelim = '(#('
112
- @closemathdelim = ')#)'
113
- while text.include?(@openmathdelim) || text.include?(@closemathdelim)
114
- @openmathdelim += '('
115
- @closemathdelim += ')'
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]
116
129
  end
117
- [@openmathdelim, @closemathdelim]
118
- end
119
130
 
120
- def header_strip(h)
121
- h = h.to_s.gsub(%r{<br\s*/>}, ' ').gsub(/<\/?h[123456][^>]*>/, '')
122
- .gsub(/<\/?b[^>]*>/, '')
123
- h1 = to_xhtml_fragment(h.dup)
124
- h1.traverse do |x|
125
- x.replace(' ') if x.name == 'span' && /mso-tab-count/.match(x['style'])
126
- x.remove if x.name == 'img'
127
- x.remove if x.name == 'span' && x['class'] == 'MsoCommentReference'
128
- x.remove if x.name == 'a' && x['class'] == 'FootnoteRef'
129
- x.remove if x.name == 'span' && /mso-bookmark/.match(x['style'])
130
- x.replace(x.children) if x.name == 'a'
131
- end
132
- from_xhtml(h1)
133
- 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
134
143
 
135
- def liquid(doc)
136
- self.class.liquid(doc)
137
- 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
138
150
 
139
- def liquid(doc)
140
- # unescape HTML escapes in doc
141
- doc = doc.split(%r<(\{%|%\})>).each_slice(4).map do |a|
142
- a[2] = a[2].gsub(/\&lt;/, '<').gsub(/\&gt;/, '>') if a.size > 2
143
- a.join('')
144
- end.join('')
145
- Liquid::Template.parse(doc)
146
- 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
147
165
 
148
- def empty2nil(v)
149
- return nil if !v.nil? && v.is_a?(String) && v.empty?
150
- v
151
- end
166
+ def empty2nil(str)
167
+ return nil if !str.nil? && str.is_a?(String) && str.empty?
152
168
 
153
- def populate_template(docxml, _format = nil)
154
- meta = @meta
155
- .get
156
- .merge(@labels ? {labels: @labels} : {})
157
- .merge(@meta.labels ? {labels: @meta.labels} : {})
158
- .merge(fonts_options || {})
159
- template = liquid(docxml)
160
- template.render(meta.map { |k, v| [k.to_s, empty2nil(v)] }.to_h)
161
- .gsub('&lt;', '&#x3c;').gsub('&gt;', '&#x3e;').gsub('&amp;', '&#x26;')
162
- end
169
+ str
170
+ end
163
171
 
164
- def save_dataimage(uri, _relative_dir = true)
165
- %r{^data:(image|application)/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ uri
166
- imgtype.sub!(/\+[a-z0-9]+$/, '') # svg+xml
167
- imgtype = 'png' unless /^[a-z0-9]+$/.match imgtype
168
- Tempfile.open(['image', ".#{imgtype}"]) do |f|
169
- f.binmode
170
- f.write(Base64.strict_decode64(imgdata))
171
- @tempfile_cache << f # persist to the end
172
- f.path
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;")
173
181
  end
174
- end
175
182
 
176
- def image_localfile(i)
177
- if /^data:/.match? i['src']
178
- save_dataimage(i['src'], false)
179
- elsif %r{^([A-Z]:)?/}.match? i['src']
180
- i['src']
181
- else
182
- File.join(@localdir, i['src'])
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
183
203
  end
184
- end
185
204
 
186
- def labelled_ancestor(node)
187
- !node.ancestors('example, requirement, recommendation, permission, '\
188
- 'note, table, figure, sourcecode').empty?
205
+ def labelled_ancestor(node)
206
+ !node.ancestors("example, requirement, recommendation, permission, "\
207
+ "note, table, figure, sourcecode").empty?
208
+ end
189
209
  end
190
210
  end
191
211
  end