isodoc 3.2.6 → 3.3.0

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: 43165a177a896526892723b216ed2cff72eee876ace1c099c52ea92ec549fff8
4
- data.tar.gz: fc24432b8ccaeecbc0fad71bc64f5311c3307d0a1b336b32c3bc9399269ba031
3
+ metadata.gz: ac5bfd800fc89d9c1725ca6d96db1a708396bbc4ee89edcdef2c54d34ad51b2d
4
+ data.tar.gz: 26924ac140cd0ba29ca309086554a03baf0055d3f6415c03c95d1c68c56ff7a4
5
5
  SHA512:
6
- metadata.gz: 58ddea5bae6b878309b915ba9e70837dbfdfd26d6d1b257f80a46345064770949b67dca7940aa9e1675a4089541e1c6d46961f01b8f42b1184ddbf7dcdeaf908
7
- data.tar.gz: df2b697149cdbbc2c0e855047c7f7e2c5bced1ae89b1dc3d3d8b382e1b877ad195ea1251d5786e45eb769034f87e517a5ca613243637f4b1363a13c9f29a6ccf
6
+ metadata.gz: f0ff182791d2994fabd4f839a4a4fb9082447a7fdc73f2e4657229b81be656bf3dbb1a24b8f60c9a8e09e61bcab1b59ca35ba79584c0fde20e31cdac99f882a2
7
+ data.tar.gz: 62b50a7714b7e5cba905cbbd96d390b9b93d859cbb7248b5ff3f340750c2bae102178859cda6bfbd4e9288aeae376303a36c71cbc27de1c47cbd3587736268b1
data/isodoc.gemspec CHANGED
@@ -37,7 +37,7 @@ Gem::Specification.new do |spec|
37
37
  spec.add_dependency "mn2pdf", ">= 2.13"
38
38
  spec.add_dependency "mn-requirements", "~> 0.5.0"
39
39
 
40
- spec.add_dependency "relaton-render", "~> 0.9.0"
40
+ spec.add_dependency "relaton-render", "~> 0.10.0"
41
41
  spec.add_dependency "roman-numerals"
42
42
  spec.add_dependency "rouge", "~> 4.0"
43
43
  spec.add_dependency "thread_safe"
@@ -138,16 +138,6 @@ div.document-stage-band, div.document-type-band {
138
138
  background-color: #333333;
139
139
  }
140
140
 
141
- a.FootnoteRef + a.FootnoteRef::before {
142
- content: ", ";
143
- vertical-align: super;
144
- }
145
-
146
- a.TableFootnoteRef + a.TableFootnoteRef::before {
147
- content: ", ";
148
- vertical-align: super;
149
- }
150
-
151
141
  a.TableFootnoteRef, span.TableFootnoteRef,
152
142
  a.FootnoteRef, span.FootnoteRef {
153
143
  vertical-align: super;
@@ -138,16 +138,6 @@ div.document-stage-band, div.document-type-band {
138
138
  background-color: #333333;
139
139
  }
140
140
 
141
- a.FootnoteRef + a.FootnoteRef::before {
142
- content: ", ";
143
- vertical-align: super;
144
- }
145
-
146
- a.TableFootnoteRef + a.TableFootnoteRef::before {
147
- content: ", ";
148
- vertical-align: super;
149
- }
150
-
151
141
  a.TableFootnoteRef, span.TableFootnoteRef,
152
142
  a.FootnoteRef, span.FootnoteRef {
153
143
  vertical-align: super;
@@ -145,16 +145,6 @@ div.document-stage-band, div.document-type-band {
145
145
  background-color: #333333;
146
146
  }
147
147
 
148
- a.FootnoteRef + a.FootnoteRef::before {
149
- content: ", ";
150
- vertical-align: super;
151
- }
152
-
153
- a.TableFootnoteRef + a.TableFootnoteRef::before {
154
- content: ", ";
155
- vertical-align: super;
156
- }
157
-
158
148
  a.TableFootnoteRef, span.TableFootnoteRef,
159
149
  a.FootnoteRef, span.FootnoteRef {
160
150
  vertical-align: super;
@@ -86,8 +86,9 @@ module IsoDoc
86
86
  end
87
87
 
88
88
  def bibrenderer(options = {})
89
- ::Relaton::Render::IsoDoc::General.new(options.merge(language: @lang,
90
- i18nhash: @i18n.get))
89
+ ::Relaton::Render::IsoDoc::General
90
+ .new(options.merge(language: @lang, script: @script,
91
+ i18nhash: @i18n.get))
91
92
  end
92
93
 
93
94
  def convert1_namespaces(html)
data/lib/isodoc/css.rb CHANGED
@@ -88,7 +88,6 @@ module IsoDoc
88
88
  def compile_scss(modified_stylesheet)
89
89
  SassC::Engine
90
90
  .new(modified_stylesheet, quiet_deps: true, syntax: :scss,
91
- silence_deprecations: %w(mixed-decls),
92
91
  importer: SasscImporter)
93
92
  .render.gsub(/__WORD__/, "")
94
93
  end
@@ -36,6 +36,12 @@ module IsoDoc
36
36
  end
37
37
  end
38
38
 
39
+ def related_parse(node, out)
40
+ out.div class: "RelatedTerms", style: "text-align:left;" do |p|
41
+ node.children.each { |c1| parse(c1, p) }
42
+ end
43
+ end
44
+
39
45
  def semx_term_parse(node, out); end
40
46
 
41
47
  def semx_related_parse(node, out); end
@@ -166,7 +166,7 @@ module IsoDoc
166
166
  when "image" then image_parse(node, out, nil)
167
167
  when "sourcecode" then sourcecode_parse(node, out)
168
168
  when "pre" then pre_parse(node, out)
169
- when "annotation" then annotation_parse(node, out)
169
+ when "callout-annotation" then annotation_parse(node, out)
170
170
  when "term" then termdef_parse(node, out)
171
171
  when "preferred" then semx_term_parse(node, out)
172
172
  when "fmt-preferred" then term_parse(node, out)
@@ -180,6 +180,7 @@ module IsoDoc
180
180
  when "termsource" then semx_termref_parse(node, out)
181
181
  when "fmt-termsource" then termref_parse(node, out)
182
182
  when "related" then semx_related_parse(node, out)
183
+ when "fmt-related" then related_parse(node, out)
183
184
  when "modification" then modification_parse(node, out)
184
185
  when "termnote" then termnote_parse(node, out)
185
186
  when "terms" then terms_parse(node, out)
@@ -118,7 +118,7 @@ module IsoDoc
118
118
  sheet_content = File.read(filename, encoding: "UTF-8")
119
119
  .gsub(%r<([a-z])\.([0-9])(?=[^{}]*{)>m, "\\1.__WORD__\\2")
120
120
  SassC::Engine.new(%<@use "variables" as *;\n#{sheet_content}>,
121
- syntax: :scss, importer: SasscImporter)
121
+ syntax: :scss, quiet_deps: true, importer: SasscImporter)
122
122
  .render.gsub(/__WORD__/, "")
123
123
  end
124
124
  end
@@ -25,10 +25,9 @@ module IsoDoc
25
25
  end
26
26
 
27
27
  def html_cleanup(html)
28
- html = term_header(html_footnote_filter(html_preface(htmlstyle(html))))
29
- html = footnote_backlinks(html)
30
- html = mathml(html_list_clean(remove_placeholder_paras(html)))
31
- html_toc(heading_anchors(sourcecode_cleanup(html)))
28
+ html = term_header(html_preface(htmlstyle(html)))
29
+ html = html_list_clean(remove_placeholder_paras(html_footnote(html)))
30
+ html_toc(heading_anchors(sourcecode_cleanup(mathml(html))))
32
31
  end
33
32
 
34
33
  def heading_anchors(html)
@@ -13,8 +13,7 @@ module IsoDoc
13
13
  end
14
14
 
15
15
  def htmlstylesheet(file)
16
- return if file.nil?
17
-
16
+ file.nil? and return
18
17
  file.open if file.is_a?(Tempfile)
19
18
  stylesheet = file.read
20
19
  xml = Nokogiri::XML("<style/>")
@@ -26,8 +25,7 @@ module IsoDoc
26
25
  end
27
26
 
28
27
  def htmlstyle(docxml)
29
- return docxml unless @htmlstylesheet
30
-
28
+ @htmlstylesheet or return docxml
31
29
  head = docxml.at("//*[local-name() = 'head']")
32
30
  head << htmlstylesheet(@htmlstylesheet)
33
31
  s = htmlstylesheet(@htmlstylesheet_override) and head << s
@@ -53,10 +51,10 @@ module IsoDoc
53
51
  def authority_cleanup1(docxml, klass)
54
52
  dest = docxml.at("//div[@id = 'boilerplate-#{klass}-destination']")
55
53
  auth = docxml.at("//div[@id = 'boilerplate-#{klass}' or " \
56
- "@class = 'boilerplate-#{klass}']")
57
- auth&.xpath(".//h1[not(text())] | .//h2[not(text())]")&.each(&:remove)
58
- auth&.xpath(".//h1 | .//h2")&.each { |h| h["class"] = "IntroTitle" }
59
- dest and auth and dest.replace(auth.remove)
54
+ "@class = 'boilerplate-#{klass}']") or return
55
+ auth.xpath(".//h1[not(text())] | .//h2[not(text())]").each(&:remove)
56
+ auth.xpath(".//h1 | .//h2").each { |h| h["class"] = "IntroTitle" }
57
+ dest && auth and dest.replace(auth.remove)
60
58
  end
61
59
 
62
60
  def authority_cleanup(docxml)
@@ -163,8 +161,7 @@ module IsoDoc
163
161
  end
164
162
 
165
163
  def inject_script(doc)
166
- return doc unless @scripts
167
-
164
+ @scripts or return doc
168
165
  scripts = File.read(@scripts, encoding: "UTF-8")
169
166
  scripts_override = ""
170
167
  @scripts_override and
@@ -1,25 +1,18 @@
1
1
  module IsoDoc
2
2
  module HtmlFunction
3
3
  module Html
4
- def update_footnote_filter(fnote, xref, idx, seen)
5
- if seen[fnote.text]
6
- xref.at("./sup").content = seen[fnote.text][:num].to_s
7
- fnote.remove unless xref["href"] == seen[fnote.text][:href]
8
- xref["href"] = seen[fnote.text][:href]
9
- else
10
- seen[fnote.text] = { num: idx, href: xref["href"] }
11
- xref.at("./sup").content = idx.to_s
12
- idx += 1
13
- end
14
- [idx, seen]
4
+ def html_footnote(html)
5
+ footnote_delimit(footnote_backlinks(html))
15
6
  end
16
7
 
17
- def html_footnote_filter(docxml)
18
- seen = {}
19
- i = 1
20
- docxml.xpath('//a[@class = "FootnoteRef"]').each do |x|
21
- fn = docxml.at(%<//*[@id = '#{x['href'].sub(/^#/, '')}']>) || next
22
- i, seen = update_footnote_filter(fn, x, i, seen)
8
+ def footnote_delimit(docxml)
9
+ k = %w(FootnoteRef TableFootnoteRef)
10
+ docxml.xpath("//a").each do |a|
11
+ k.include?(a["class"]) or next
12
+ a1 = a.next_element or next
13
+ k.include?(a1["class"]) or next
14
+ sup = a.at("./sup") and a = sup
15
+ a << ", "
23
16
  end
24
17
  docxml
25
18
  end
@@ -37,14 +30,19 @@ module IsoDoc
37
30
  def footnote_backlinks(docxml)
38
31
  seen = {}
39
32
  docxml.xpath('//a[@class = "FootnoteRef"]').each_with_index do |x, i|
40
- (seen[x["href"]] and next) or seen[x["href"]] = true
41
- fn = docxml.at(%<//*[@id = '#{x['href'].sub(/^#/, '')}']>) || next
33
+ fn = footnote_backlink?(x, docxml, seen) or next
34
+ seen[x["href"]] = true
42
35
  footnote_backlinks1(x, fn)
43
36
  x["id"] ||= "fnref:#{i + 1}"
44
37
  fn.add_child "<a href='##{x['id']}'>&#x21A9;</a>"
45
38
  end
46
39
  docxml
47
40
  end
41
+
42
+ def footnote_backlink?(elem, docxml, seen)
43
+ seen[elem["href"]] and return
44
+ docxml.at(%<//*[@id = '#{elem['href'].sub(/^#/, '')}']>)
45
+ end
48
46
  end
49
47
  end
50
48
  end
data/lib/isodoc/init.rb CHANGED
@@ -14,8 +14,9 @@ module IsoDoc
14
14
  i18nyaml: i18nyaml || @i18nyaml)
15
15
  end
16
16
 
17
- def l10n(expr, lang = @lang, script = @script, locale = @locale)
18
- @i18n.l10n(expr, lang, script, locale)
17
+ def l10n(expr, lang = @lang, script = @script, opt = {})
18
+ opt[:locale] ||= @locale
19
+ @i18n.l10n(expr, lang, script, opt)
19
20
  end
20
21
 
21
22
  def toc_init(docxml)
@@ -170,8 +171,8 @@ module IsoDoc
170
171
 
171
172
  def omit_docid_prefix(prefix)
172
173
  prefix.nil? || prefix.empty? and return true
173
- %w(ISO IEC IEV ITU W3C BIPM csd metanorma repository metanorma-ordinal)
174
- .include? prefix
174
+ %w(ISO IEC IEV ITU W3C BIPM csd metanorma repository metanorma-ordinal
175
+ title).include? prefix
175
176
  end
176
177
 
177
178
  def connectives_spans(text)
@@ -9,8 +9,9 @@ module IsoDoc
9
9
  Common::ns(xpath)
10
10
  end
11
11
 
12
- def l10n(expr, lang = @lang, script = @script, locale = @locale)
13
- @i18n.l10n(expr, lang, script, locale)
12
+ def l10n(expr, lang = @lang, script = @script, opt = {})
13
+ opt[:locale] ||= @locale
14
+ @i18n.l10n(expr, lang, script, opt)
14
15
  end
15
16
 
16
17
  def connectives_strip(text)
@@ -84,11 +85,6 @@ module IsoDoc
84
85
  status_print(docstatus).split(/ /).map { |s| s[0].upcase }.join
85
86
  end
86
87
 
87
- # KILL
88
- def unpublishedx(status)
89
- !status.casecmp("published").zero?
90
- end
91
-
92
88
  def status_print(status)
93
89
  status.split(/[- ]/).map do |w|
94
90
  letters = w.chars
@@ -120,7 +116,7 @@ module IsoDoc
120
116
  draftinfo = " (#{@labels['draft_label']} #{draft}"
121
117
  draftinfo += ", #{revdate}" if revdate
122
118
  draftinfo += ")"
123
- l10n(draftinfo, @lang, @script, @locale)
119
+ l10n(draftinfo, @lang, @script)
124
120
  end
125
121
 
126
122
  def version(isoxml, _out)
@@ -87,7 +87,8 @@ module IsoDoc
87
87
 
88
88
  def admonition_label(elem, num)
89
89
  lbl = if elem["type"] == "box" then @i18n.box
90
- else @i18n.admonition[elem["type"]]&.upcase end
90
+ else @i18n.admonition[elem["type"]]&.upcase
91
+ end
91
92
  labelled_autonum(lbl, elem["id"], num)
92
93
  end
93
94
 
@@ -184,17 +185,29 @@ module IsoDoc
184
185
  source1(elem, :figure)
185
186
  end
186
187
 
188
+ def source_join_delim(_elem)
189
+ "; "
190
+ end
191
+
187
192
  def source1(elem, ancestor)
188
- n = elem
189
- while n = n&.next_element
190
- case n.name
193
+ source_elems = source1_gather(elem)
194
+ source_elems.each do |e|
195
+ elem << "#{source_join_delim(elem)}#{to_xml(e.remove.children).strip}"
196
+ end
197
+ source1_label(elem, to_xml(elem.children).strip, ancestor)
198
+ end
199
+
200
+ def source1_gather(elem)
201
+ source_elems = []
202
+ while elem = elem&.next_element
203
+ case elem.name
191
204
  when "source"
192
205
  when "fmt-source"
193
- elem << "; #{to_xml(n.remove.children)}"
206
+ source_elems << elem
194
207
  else break
195
208
  end
196
209
  end
197
- source1_label(elem, to_xml(elem.children).strip, ancestor)
210
+ source_elems
198
211
  end
199
212
 
200
213
  def source1_label(elem, sources, _ancestor)
@@ -104,153 +104,5 @@ module IsoDoc
104
104
  ref.previous = prev
105
105
  ref.next = foll
106
106
  end
107
-
108
- def related(docxml)
109
- docxml.xpath(ns("//fmt-related/semx")).each { |f| related1(f) }
110
- end
111
-
112
- def related1(node)
113
- p, ref, orig = related1_prep(node)
114
- label = @i18n.relatedterms[orig["type"]].upcase
115
- ret = "<strong>**RELATED TERM NOT FOUND**</strong>"
116
- p && ref and ret = "<em>#{to_xml(p)}</em> (#{Common::to_xml(ref)})"
117
- node.children = (l10n("<p><strong>#{label}:</strong> #{ret}</p>"))
118
- end
119
-
120
- def related1_prep(node)
121
- p = node.at(ns("./fmt-preferred"))&.children
122
- ref = node.at(ns("./xref | ./eref | ./termref"))
123
- orig = semx_orig(node)
124
- [p, ref, orig]
125
- end
126
-
127
- def related_designation1(desgn)
128
- out = desgn.parent.at(ns("./fmt-#{desgn.name}"))
129
- d1 = semx_fmt_dup(desgn)
130
- %w(preferred admitted deprecates).each do |w|
131
- d = d1.at(ns("./#{w}[last()]")) and d.after("<fmt-#{w}/>")
132
- end
133
- out << d1
134
- end
135
-
136
- def designation(docxml)
137
- docxml.xpath(ns("//related")).each { |p| related_designation1(p) }
138
- docxml.xpath(ns("//preferred | //admitted | //deprecates"))
139
- .each { |p| designation1(p) }
140
- docxml.xpath(ns("//fmt-preferred | //fmt-admitted | //fmt-deprecates"))
141
- .each { |t| merge_second_preferred(t) }
142
- docxml.xpath(ns("//fmt-deprecates")).each { |d| deprecates(d) }
143
- docxml.xpath(ns("//fmt-admitted")).each { |d| admits(d) }
144
- end
145
-
146
- def deprecates(elem)
147
- elem.xpath(ns(".//semx[@element = 'deprecates']")).each do |t|
148
- t.previous = @i18n.l10n("#{@i18n.deprecated}: ")
149
- end
150
- end
151
-
152
- def admits(elem); end
153
-
154
- def merge_second_preferred(term)
155
- pref = nil
156
- out = term.xpath(ns("./semx")).each_with_index
157
- .with_object([]) do |(p, i), m|
158
- if (i.zero? && (pref = p)) || merge_preferred_eligible?(pref, p)
159
- m << p
160
- else p.wrap("<p></p>")
161
- end
162
- end
163
- pref&.replace(merge_second_preferred1(out, term))
164
- end
165
-
166
- def merge_second_preferred1(desgns, term)
167
- desgns[1..].each(&:remove)
168
- ret = l10n(desgns.map { |x| to_xml(x) }.join("; "))
169
- term.ancestors("fmt-related").empty? and ret = "<p>#{ret}</p>"
170
- ret
171
- end
172
-
173
- def merge_preferred_eligible?(first, second)
174
- orig_first, orig_second, firstex, secondex =
175
- merge_preferred_eligible_prep(first, second)
176
- orig_first["geographic-area"] == orig_second["geographic-area"] &&
177
- firstex["language"] == secondex["language"] &&
178
- !orig_first.at(ns("./pronunciation | ./grammar | ./graphical-symbol")) &&
179
- !orig_second.at(ns("./pronunciation | ./grammar | ./graphical-symbol")) &&
180
- orig_first.name == "preferred" && orig_second.name == "preferred"
181
- end
182
-
183
- def merge_preferred_eligible_prep(first, second)
184
- orig_first = semx_orig(first)
185
- orig_second = semx_orig(second)
186
- firstex = orig_first.at(ns("./expression")) || {}
187
- secondex = orig_second.at(ns("./expression")) || {}
188
- [orig_first, orig_second, firstex, secondex]
189
- end
190
-
191
- def designation1(desgn)
192
- desgn.parent.name == "related" and return
193
- out = desgn.parent.at(ns("./fmt-#{desgn.name}"))
194
- d1 = semx_fmt_dup(desgn)
195
- s = d1.at(ns("./source"))
196
- modification_dup_align(desgn.at(ns("./source")), s)
197
- name = d1.at(ns("./expression/name | ./letter-symbol/name | " \
198
- "./graphical-symbol")) or return
199
- designation_annotate(d1, name, desgn)
200
- out << d1
201
- s and out << s.wrap("<fmt-termsource></fmt-termsource>").parent
202
- end
203
-
204
- def designation_annotate(desgn, name, orig)
205
- designation_boldface(desgn)
206
- designation_field(desgn, name, orig)
207
- designation_grammar(desgn, name)
208
- designation_localization(desgn, name, orig)
209
- designation_pronunciation(desgn, name)
210
- designation_bookmarks(desgn, name)
211
- desgn.children = name.children
212
- end
213
-
214
- def designation_boldface(desgn)
215
- desgn["element"] == "preferred" or return
216
- name = desgn.at(ns("./expression/name | ./letter-symbol/name")) or return
217
- name.children = "<strong>#{name.children}</strong>"
218
- end
219
-
220
- def designation_field(_desgn, name, orig)
221
- f = orig.xpath(ns("./field-of-application | ./usage-info"))
222
- &.map { |u| to_xml(semx_fmt_dup(u)) }&.join(", ")
223
- f&.empty? and return nil
224
- name << "<span class='fmt-designation-field'>, &#x3c;#{f}&#x3e;</span>"
225
- end
226
-
227
- def designation_grammar(desgn, name)
228
- g = desgn.at(ns("./expression/grammar")) or return
229
- ret = g.xpath(ns("./gender | ./number")).each_with_object([]) do |x, m|
230
- m << @i18n.grammar_abbrevs[x.text]
231
- end
232
- %w(isPreposition isParticiple isAdjective isVerb isAdverb isNoun)
233
- .each do |x|
234
- g.at(ns("./#{x}[text() = 'true']")) and ret << @i18n.grammar_abbrevs[x]
235
- end
236
- name << ", #{ret.join(', ')}"
237
- end
238
-
239
- def designation_localization(desgn, name, orig_desgn)
240
- loc = [desgn.at(ns("./expression/@language"))&.text,
241
- desgn.at(ns("./expression/@script"))&.text,
242
- orig_desgn.at("./@geographic-area")&.text].compact
243
- loc.empty? and return
244
- name << ", #{loc.join(' ')}"
245
- end
246
-
247
- def designation_pronunciation(desgn, name)
248
- f = desgn.at(ns("./expression/pronunciation")) or return
249
- name << ", /#{to_xml(f.children)}/"
250
- end
251
-
252
- def designation_bookmarks(desgn, name)
253
- desgn.xpath(ns(".//bookmark")).each { |b| name << b.remove }
254
- end
255
107
  end
256
108
  end
@@ -0,0 +1,158 @@
1
+ module IsoDoc
2
+ class PresentationXMLConvert < ::IsoDoc::Convert
3
+ def related(docxml)
4
+ docxml.xpath(ns("//fmt-related/semx")).each { |f| related1(f) }
5
+ end
6
+
7
+ # Only render related if rendered and hyperlinked
8
+ def related1(node)
9
+ p, ref, orig = related1_prep(node)
10
+ label = @i18n.relatedterms[orig["type"]].upcase
11
+ ret = if p && ref
12
+ if p.text == ref.text
13
+ "<em>#{Common::to_xml(ref)}</em>"
14
+ else
15
+ "<em>#{to_xml(p)}</em> (#{Common::to_xml(ref)})"
16
+ end
17
+ else "<strong>**RELATED TERM NOT FOUND**</strong>"
18
+ end
19
+ node.children = (l10n("<p><strong>#{label}:</strong> #{ret}</p>"))
20
+ end
21
+
22
+ def related1_prep(node)
23
+ p = node.at(ns("./fmt-preferred"))&.children
24
+ ref = node.at(ns("./xref | ./eref | ./termref"))
25
+ orig = semx_orig(node)
26
+ [p, ref, orig]
27
+ end
28
+
29
+ def related_designation1(desgn)
30
+ out = desgn.parent.at(ns("./fmt-#{desgn.name}"))
31
+ d1 = semx_fmt_dup(desgn)
32
+ %w(preferred admitted deprecates).each do |w|
33
+ d = d1.at(ns("./#{w}[last()]")) and d.after("<fmt-#{w}/>")
34
+ end
35
+ out << d1
36
+ end
37
+
38
+ def designation(docxml)
39
+ docxml.xpath(ns("//related")).each { |p| related_designation1(p) }
40
+ docxml.xpath(ns("//preferred | //admitted | //deprecates"))
41
+ .each { |p| designation1(p) }
42
+ docxml.xpath(ns("//fmt-preferred | //fmt-admitted | //fmt-deprecates"))
43
+ .each { |t| merge_second_preferred(t) }
44
+ docxml.xpath(ns("//fmt-deprecates")).each { |d| deprecates(d) }
45
+ docxml.xpath(ns("//fmt-admitted")).each { |d| admits(d) }
46
+ end
47
+
48
+ def deprecates(elem)
49
+ elem.xpath(ns(".//semx[@element = 'deprecates']")).each do |t|
50
+ t.previous = @i18n.l10n("#{@i18n.deprecated}: ")
51
+ end
52
+ end
53
+
54
+ def admits(elem); end
55
+
56
+ def merge_second_preferred(term)
57
+ pref = nil
58
+ out = term.xpath(ns("./semx")).each_with_index
59
+ .with_object([]) do |(p, i), m|
60
+ if (i.zero? && (pref = p)) || merge_preferred_eligible?(pref, p)
61
+ m << p
62
+ else p.wrap("<p></p>")
63
+ end
64
+ end
65
+ pref&.replace(merge_second_preferred1(out, term))
66
+ end
67
+
68
+ def merge_second_preferred1(desgns, term)
69
+ desgns[1..].each(&:remove)
70
+ ret = l10n(desgns.map { |x| to_xml(x) }.join("; "))
71
+ term.ancestors("fmt-related").empty? and ret = "<p>#{ret}</p>"
72
+ ret
73
+ end
74
+
75
+ def merge_preferred_eligible?(first, second)
76
+ orig_first, orig_second, firstex, secondex =
77
+ merge_preferred_eligible_prep(first, second)
78
+ orig_first["geographic-area"] == orig_second["geographic-area"] &&
79
+ firstex["language"] == secondex["language"] &&
80
+ !orig_first.at(ns("./pronunciation | ./grammar | ./graphical-symbol")) &&
81
+ !orig_second.at(ns("./pronunciation | ./grammar | ./graphical-symbol")) &&
82
+ orig_first.name == "preferred" && orig_second.name == "preferred"
83
+ end
84
+
85
+ def merge_preferred_eligible_prep(first, second)
86
+ orig_first = semx_orig(first)
87
+ orig_second = semx_orig(second)
88
+ firstex = orig_first.at(ns("./expression")) || {}
89
+ secondex = orig_second.at(ns("./expression")) || {}
90
+ [orig_first, orig_second, firstex, secondex]
91
+ end
92
+
93
+ def designation1(desgn)
94
+ desgn.parent.name == "related" and return
95
+ out = desgn.parent.at(ns("./fmt-#{desgn.name}"))
96
+ d1 = semx_fmt_dup(desgn)
97
+ s = d1.at(ns("./source"))
98
+ modification_dup_align(desgn.at(ns("./source")), s)
99
+ name = d1.at(ns("./expression/name | ./letter-symbol/name | " \
100
+ "./graphical-symbol")) or return
101
+ designation_annotate(d1, name, desgn)
102
+ out << d1
103
+ s and out << s.wrap("<fmt-termsource></fmt-termsource>").parent
104
+ end
105
+
106
+ def designation_annotate(desgn, name, orig)
107
+ designation_boldface(desgn)
108
+ designation_field(desgn, name, orig)
109
+ designation_grammar(desgn, name)
110
+ designation_localization(desgn, name, orig)
111
+ designation_pronunciation(desgn, name)
112
+ designation_bookmarks(desgn, name)
113
+ desgn.children = name.children
114
+ end
115
+
116
+ def designation_boldface(desgn)
117
+ desgn["element"] == "preferred" or return
118
+ name = desgn.at(ns("./expression/name | ./letter-symbol/name")) or return
119
+ name.children = "<strong>#{name.children}</strong>"
120
+ end
121
+
122
+ def designation_field(_desgn, name, orig)
123
+ f = orig.xpath(ns("./field-of-application | ./usage-info"))
124
+ &.map { |u| to_xml(semx_fmt_dup(u)) }&.join(", ")
125
+ f&.empty? and return nil
126
+ name << "<span class='fmt-designation-field'>, &#x3c;#{f}&#x3e;</span>"
127
+ end
128
+
129
+ def designation_grammar(desgn, name)
130
+ g = desgn.at(ns("./expression/grammar")) or return
131
+ ret = g.xpath(ns("./gender | ./number")).each_with_object([]) do |x, m|
132
+ m << @i18n.grammar_abbrevs[x.text]
133
+ end
134
+ %w(isPreposition isParticiple isAdjective isVerb isAdverb isNoun)
135
+ .each do |x|
136
+ g.at(ns("./#{x}[text() = 'true']")) and ret << @i18n.grammar_abbrevs[x]
137
+ end
138
+ name << ", #{ret.join(', ')}"
139
+ end
140
+
141
+ def designation_localization(desgn, name, orig_desgn)
142
+ loc = [desgn.at(ns("./expression/@language"))&.text,
143
+ desgn.at(ns("./expression/@script"))&.text,
144
+ orig_desgn.at("./@geographic-area")&.text].compact
145
+ loc.empty? and return
146
+ name << ", #{loc.join(' ')}"
147
+ end
148
+
149
+ def designation_pronunciation(desgn, name)
150
+ f = desgn.at(ns("./expression/pronunciation")) or return
151
+ name << ", /#{to_xml(f.children)}/"
152
+ end
153
+
154
+ def designation_bookmarks(desgn, name)
155
+ desgn.xpath(ns(".//bookmark")).each { |b| name << b.remove }
156
+ end
157
+ end
158
+ end
@@ -31,11 +31,13 @@ module IsoDoc
31
31
  id, id1, id2, id3 = bibitem_ref_code_prep(bib)
32
32
  id || id1 || id2 || id3 and return [id, id1, id2, id3]
33
33
  bib["suppress_identifier"] == "true" and return [nil, nil, nil, nil]
34
- [nil, no_identifier(bib), nil, nil]
34
+ # [nil, no_identifier(bib), nil, nil]
35
+ [nil, nil, nil, nil]
35
36
  end
36
37
 
37
38
  def bibitem_ref_code_prep(bib)
38
- id = bib.at(ns("./docidentifier[@type = 'metanorma']"))
39
+ id = bib.at(ns("./docidentifier[@type = 'metanorma']")) ||
40
+ bib.at(ns("./docidentifier[@type = 'title']"))
39
41
  id1 = pref_ref_code(bib)
40
42
  id2 = bib.at(ns("./docidentifier[#{SKIP_DOCID}]"))
41
43
  id3 = bib.at(ns("./docidentifier[@type = 'metanorma-ordinal']"))
@@ -15,6 +15,7 @@ module IsoDoc
15
15
  end
16
16
 
17
17
  def citeas_cleanup(ref)
18
+ ref.nil? and return nil
18
19
  if ref.include?("<")
19
20
  xml = Nokogiri::XML("<root>#{ref}</root>")
20
21
  xml.xpath("//semx").each { |x| x.replace(x.children) }
@@ -39,18 +40,17 @@ module IsoDoc
39
40
  def eref_localities(refs, target, node)
40
41
  if can_conflate_eref_rendering?(refs)
41
42
  l10n(", #{eref_localities_conflated(refs, target, node)}"
42
- .gsub(/\s+/, " "))
43
+ .gsub(/\s+/, " "), @lang, @script, { prev: target })
43
44
  else
44
45
  ret = resolve_eref_connectives(eref_locality_stacks(refs, target, node))
45
- l10n(ret.join.gsub(/\s+/, " "))
46
+ l10n(ret.join.gsub(/\s+/, " "), @lang, @script, { prev: target })
46
47
  end
47
48
  end
48
49
 
49
50
  def eref_localities_conflated(refs, target, node)
50
51
  droploc = node["droploc"]
51
52
  node["droploc"] = true
52
- ret = resolve_eref_connectives(eref_locality_stacks(refs, target,
53
- node))
53
+ ret = resolve_eref_connectives(eref_locality_stacks(refs, target, node))
54
54
  node.delete("droploc") unless droploc
55
55
  eref_localities1({ target:, number: "pl",
56
56
  type: refs.first.at(ns("./locality/@type")).text,
@@ -216,7 +216,7 @@ module IsoDoc
216
216
  def eref2link1(node, href)
217
217
  url = href[:link]
218
218
  att = href[:type] == :attachment ? "attachment='true'" : ""
219
- repl = "<fmt-link #{att} target='#{url}'>#{node.children}</link>"
219
+ repl = "<fmt-link #{att} target='#{url}'>#{to_xml(node.children)}</link>"
220
220
  node["type"] == "footnote" and repl = "<sup>#{repl}</sup>"
221
221
  node.replace(repl)
222
222
  end
@@ -3,7 +3,8 @@ module IsoDoc
3
3
  def footnote_collect(fnotes)
4
4
  seen = {}
5
5
  fnotes.each_with_object([]) do |x, m|
6
- seen[x["reference"]] or m << fnbody(x, seen)
6
+ x["reference"] or next # ignore semx-only footnotes
7
+ b = fnbody(x, seen) and m << b
7
8
  x["target"] = seen[x["reference"]]
8
9
  ref = x["hiddenref"] == "true" ? "" : fn_ref_label(x)
9
10
  x << <<~FNOTE.strip
@@ -21,6 +22,7 @@ module IsoDoc
21
22
  end
22
23
 
23
24
  def fnbody(fnote, seen)
25
+ add_fnbody?(fnote, seen) or return nil
24
26
  body = Nokogiri::XML::Node.new("fmt-fn-body", fnote.document)
25
27
  add_id(body)
26
28
  body["target"] = fnote["id"]
@@ -31,6 +33,10 @@ module IsoDoc
31
33
  body
32
34
  end
33
35
 
36
+ def add_fnbody?(fnote, seen)
37
+ !seen[fnote["reference"]]
38
+ end
39
+
34
40
  def insert_fn_body_ref(fnote, body)
35
41
  ins = body.at(ns(".//p")) ||
36
42
  body.at(ns("./semx")).children.first.before("<p> </p>").previous
@@ -116,7 +122,10 @@ module IsoDoc
116
122
 
117
123
  def renumber_document_footnote(fnote, idx, seen)
118
124
  fnote["original-reference"] = fnote["reference"]
119
- if seen[fnote["reference"]]
125
+ if sem_xml_descendant?(fnote)
126
+ fnote.delete("reference")
127
+ return idx
128
+ elsif seen[fnote["reference"]]
120
129
  fnote["reference"] = seen[fnote["reference"]]
121
130
  else
122
131
  seen[fnote["reference"]] = idx
@@ -3,12 +3,12 @@ require_relative "docid"
3
3
  module IsoDoc
4
4
  class PresentationXMLConvert < ::IsoDoc::Convert
5
5
  def references(docxml)
6
- bibliography_bibitem_number(docxml)
7
6
  @ref_renderings = references_render(docxml)
8
7
  docxml.xpath(ns("//references/bibitem")).each do |x|
9
8
  bibitem(x, @ref_renderings)
10
9
  reference_name(x)
11
10
  end
11
+ bibliography_bibitem_number(docxml)
12
12
  hidden_items(docxml)
13
13
  move_norm_ref_to_sections(docxml)
14
14
  end
@@ -174,7 +174,7 @@ module IsoDoc
174
174
  else norm_ref_entry_code(ordinal, idents, ids, standard, datefn,
175
175
  bib)
176
176
  end
177
- bib << "<biblio-tag>#{ret}</biblio-tag>"
177
+ bib.add_first_child("<biblio-tag>#{ret}</biblio-tag>")
178
178
  end
179
179
 
180
180
  def norm_ref_entry_code(_ordinal, idents, _ids, _standard, datefn, _bib)
@@ -184,6 +184,7 @@ module IsoDoc
184
184
  ret += datefn
185
185
  ret.empty? and return ret
186
186
  idents[:sdo] and ret += ","
187
+ ret.sub(",", "").strip.empty? and return ""
187
188
  "#{ret} "
188
189
  end
189
190
 
@@ -192,7 +193,7 @@ module IsoDoc
192
193
  def biblio_ref_entry_code(ordinal, ids, _id, _standard, datefn, _bib)
193
194
  # standard and id = nil
194
195
  ret = ids[:ordinal] || ids[:metanorma] || "[#{ordinal}]"
195
- if ids[:sdo]
196
+ if ids[:sdo] && !ids[:sdo].empty?
196
197
  ret = prefix_bracketed_ref(ret)
197
198
  ret += "#{ids[:sdo]}#{datefn}, "
198
199
  else
@@ -71,10 +71,15 @@ module IsoDoc
71
71
  if unnumbered_clause?(elem)
72
72
  prefix_name(elem, {}, nil, "title")
73
73
  else
74
- prefix_name(elem, { caption: annex_delim(elem) }, lbl, "title")
74
+ prefix_name(elem, { caption: annex_delim_override(elem) }, lbl, "title")
75
75
  end
76
76
  end
77
77
 
78
+ def annex_delim_override(elem)
79
+ m = elem.document.root.at(ns("//presentation-metadata/annex-delim"))
80
+ m ? to_xml(m.children) : annex_delim(elem)
81
+ end
82
+
78
83
  def annex_delim(_elem)
79
84
  "<br/><br/>"
80
85
  end
@@ -37,13 +37,14 @@ module IsoDoc
37
37
  docxml.xpath(ns("//termnote")).each { |f| termnote1(f) }
38
38
  end
39
39
 
40
- def termnote_delim(_elem)
41
- l10n(": ")
40
+ def termnote_delim(_elem, lbl)
41
+ l10n(": ", { prev: lbl })
42
42
  end
43
43
 
44
44
  def termnote1(elem)
45
45
  lbl = termnote_label(elem)
46
- prefix_name(elem, { label: termnote_delim(elem) }, lower2cap(lbl), "name")
46
+ prefix_name(elem, { label: termnote_delim(elem, lbl) },
47
+ lower2cap(lbl), "name")
47
48
  end
48
49
 
49
50
  def termnote_label(elem)
@@ -96,10 +97,11 @@ module IsoDoc
96
97
  p.add_first_child "&lt;#{to_xml(d1)}&gt; "
97
98
  end
98
99
 
100
+ # TODO should I wrap fmt-definition//termsource in fmt-termsource,
101
+ # in order to preserve termsource attributes?
102
+ # differentiating term and nonterm source under designations is not worth it
99
103
  def termsource(docxml)
100
104
  copy_baselevel_termsource(docxml)
101
- # TODO should I wrap fmt-definition//termsource in fmt-termsource, in order to preserve termsource attributes?
102
- # differentiating term and nonterm source under designations is not worth it
103
105
  docxml.xpath(ns("//fmt-termsource/source | //fmt-definition//source | //fmt-preferred//source | //fmt-admitted//source | //fmt-deprecates//source"))
104
106
  .each do |f|
105
107
  termsource_modification(f)
@@ -151,10 +153,15 @@ module IsoDoc
151
153
  while elem&.next_element&.name == "source"
152
154
  ret << semx_fmt_dup(elem.next_element.remove)
153
155
  end
154
- s = ret.map { |x| to_xml(x) }.map(&:strip).join("; ")
156
+ s = ret.map { |x| to_xml(x) }.map(&:strip)
157
+ .join(termsource_join_delim(elem))
155
158
  termsource_label(elem, s)
156
159
  end
157
160
 
161
+ def termsource_join_delim(_elem)
162
+ "; "
163
+ end
164
+
158
165
  def termsource_label(elem, sources)
159
166
  elem.replace(l10n("[#{@i18n.source}: #{sources}]"))
160
167
  end
@@ -162,7 +169,8 @@ module IsoDoc
162
169
  def termsource_modification(elem)
163
170
  elem.xpath(".//text()[normalize-space() = '']").each(&:remove)
164
171
  origin = elem.at(ns("./origin"))
165
- s = termsource_status(elem["status"]) and origin.next = l10n(", #{s}")
172
+ s = termsource_status(elem["status"]) and
173
+ origin.next = l10n(", #{s}", @lang, @script, { prev: origin.text })
166
174
  mod = elem.at(ns("./modification")) or return
167
175
  termsource_add_modification_text(mod)
168
176
  end
@@ -3,10 +3,23 @@ require_relative "refs"
3
3
  module IsoDoc
4
4
  class PresentationXMLConvert < ::IsoDoc::Convert
5
5
  def middle_title(docxml)
6
- s = docxml.at(ns("//sections")) or return
7
- t = @meta.get[:doctitle]
8
- t.nil? || t.empty? and return
9
- s.add_first_child "<p class='zzSTDTitle1'>#{t}</p>"
6
+ sections = docxml.at(ns("//sections")) or return
7
+ template = middle_title_get_template(docxml) or return
8
+ title = populate_template(template, nil) or return
9
+ title.strip.empty? and return
10
+ Nokogiri::XML(title).root.text.strip.empty? and return
11
+ sections.add_first_child title
12
+ end
13
+
14
+ def middle_title_get_template(docxml)
15
+ m = docxml.at(ns("//presentation-metadata/middle-title"))
16
+ template = m ? to_xml(m.children) : middle_title_template
17
+ template&.strip&.empty? and template = nil
18
+ template
19
+ end
20
+
21
+ def middle_title_template
22
+ "<p class='zzSTDTitle1'>{{ doctitle }}</p>"
10
23
  end
11
24
 
12
25
  def missing_title(docxml)
@@ -79,7 +92,8 @@ module IsoDoc
79
92
  if prev.name == "floating-title"
80
93
  ret << prev
81
94
  p = prev
82
- else break end
95
+ else break
96
+ end
83
97
  end
84
98
  ret
85
99
  end
@@ -2,6 +2,7 @@ require_relative "presentation_function/block"
2
2
  require_relative "presentation_function/list"
3
3
  require_relative "presentation_function/reqt"
4
4
  require_relative "presentation_function/concepts"
5
+ require_relative "presentation_function/designations"
5
6
  require_relative "presentation_function/terms"
6
7
  require_relative "presentation_function/xrefs"
7
8
  require_relative "presentation_function/erefs"
@@ -1,3 +1,3 @@
1
1
  module IsoDoc
2
- VERSION = "3.2.6".freeze
2
+ VERSION = "3.3.0".freeze
3
3
  end
@@ -147,7 +147,6 @@ refer_list)
147
147
  list_item_value(li, c, depth,
148
148
  { list_anchor:, prev_label:,
149
149
  refer_list: depth == 1 ? refer_list : nil })
150
- #li["id"] ||= "_#{UUIDTools::UUID.random_create}"
151
150
  @anchors[li["id"]] =
152
151
  { label: bare_label, bare_xref: "#{label})", type: "listitem",
153
152
  xref: %[#{label}#{delim_wrap(list_item_delim)}], refer_list:,
@@ -131,18 +131,19 @@ module IsoDoc
131
131
  def sequential_permission_body(id, parent_id, elem, label, klass, model,
132
132
  container: false)
133
133
  lbl = parent_id ? "#{parent_id}#{subreqt_separator}#{id}" : id
134
- @anchors[elem["id"]] = model.postprocess_anchor_struct(
134
+ e = elem["id"]
135
+ @anchors[e] = model.postprocess_anchor_struct(
135
136
  elem, anchor_struct(lbl, elem,
136
137
  label, klass, { unnumb: elem["unnumbered"], container: })
137
138
  )
138
- @anchors[elem["id"]][:semx] = semx(elem, lbl)
139
+ @anchors[e][:semx] = semx(elem, lbl)
139
140
  if parent_id
140
141
  x = "#{subreqt_separator(markup: true)}#{semx(elem, id)}"
141
- @anchors[elem["id"]][:semx] = @anchors[elem.parent["id"]][:semx] + x
142
- @anchors[elem["id"]][:label] =
143
- "<span class='fmt-element-name'>#{label}</span> #{@anchors[elem['id']][:semx]}"
144
- @anchors[elem["id"]][:xref] =
145
- "<span class='fmt-element-name'>#{label}</span> #{@anchors[elem['id']][:semx]}"
142
+ @anchors[e][:semx] = @anchors[elem.parent["id"]][:semx] + x
143
+ @anchors[e][:label] =
144
+ "<span class='fmt-element-name'>#{label}</span> #{@anchors[e][:semx]}"
145
+ @anchors[e][:xref] =
146
+ "<span class='fmt-element-name'>#{label}</span> #{@anchors[e][:semx]}"
146
147
  end
147
148
  model.permission_parts(elem, id, label, klass).each do |n|
148
149
  @anchors[n[:id]] = anchor_struct(n[:number], n[:elem], n[:label],
data/lib/isodoc/xref.rb CHANGED
@@ -90,8 +90,9 @@ module IsoDoc
90
90
  Common::ns(xpath)
91
91
  end
92
92
 
93
- def l10n(text, lang = @lang, script = @script, locale = @locale)
94
- @i18n.l10n(text, lang, script, locale)
93
+ def l10n(expr, lang = @lang, script = @script, opt = {})
94
+ opt[:locale] ||= @locale
95
+ @i18n.l10n(expr, lang, script, opt)
95
96
  end
96
97
 
97
98
  include ::IsoDoc::XrefGen::Util
@@ -96,7 +96,6 @@ no_identifier: (識別子なし)
96
96
  all_parts: 規格群
97
97
  edition_ordinal: "第{{ var1 }}版"
98
98
  edition: 版
99
- version: version
100
99
  toc_figures: List of figures
101
100
  toc_tables: List of tables
102
101
  toc_recommendations: List of recommendations
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: 3.2.6
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-09-02 00:00:00.000000000 Z
11
+ date: 2025-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 0.9.0
89
+ version: 0.10.0
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 0.9.0
96
+ version: 0.10.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: roman-numerals
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -440,6 +440,7 @@ files:
440
440
  - lib/isodoc/presentation_function/block.rb
441
441
  - lib/isodoc/presentation_function/cleanup.rb
442
442
  - lib/isodoc/presentation_function/concepts.rb
443
+ - lib/isodoc/presentation_function/designations.rb
443
444
  - lib/isodoc/presentation_function/docid.rb
444
445
  - lib/isodoc/presentation_function/erefs.rb
445
446
  - lib/isodoc/presentation_function/footnotes.rb