metanorma-document 0.2.0 → 0.2.2
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 +4 -4
- data/.rubocop_todo.yml +231 -53
- data/README.adoc +59 -18
- data/data/stylesheets/components/bibliography.css +2 -2
- data/data/stylesheets/components/inline.css +11 -12
- data/docs/html-renderer.adoc +261 -0
- data/lib/metanorma/document/version.rb +1 -1
- data/lib/metanorma/html/base_renderer.rb +210 -257
- data/lib/metanorma/html/bipm_renderer.rb +0 -1
- data/lib/metanorma/html/cc_renderer.rb +0 -1
- data/lib/metanorma/html/drops/admonition_drop.rb +26 -0
- data/lib/metanorma/html/drops/block_element_drop.rb +20 -0
- data/lib/metanorma/html/drops/example_drop.rb +35 -0
- data/lib/metanorma/html/drops/figure_drop.rb +53 -0
- data/lib/metanorma/html/drops/formula_drop.rb +44 -0
- data/lib/metanorma/html/drops/note_drop.rb +32 -0
- data/lib/metanorma/html/drops/sourcecode_drop.rb +37 -0
- data/lib/metanorma/html/drops.rb +7 -0
- data/lib/metanorma/html/iec_renderer.rb +0 -1
- data/lib/metanorma/html/ieee_renderer.rb +0 -1
- data/lib/metanorma/html/ietf_renderer.rb +0 -1
- data/lib/metanorma/html/iho_renderer.rb +0 -1
- data/lib/metanorma/html/iso_renderer.rb +77 -209
- data/lib/metanorma/html/itu_renderer.rb +0 -1
- data/lib/metanorma/html/ogc_renderer.rb +5 -6
- data/lib/metanorma/html/oiml_renderer.rb +0 -1
- data/lib/metanorma/html/pdfa_renderer.rb +0 -1
- data/lib/metanorma/html/ribose_renderer.rb +0 -1
- data/lib/metanorma/html/standard_renderer.rb +63 -82
- data/lib/metanorma/html/templates/_admonition.html.liquid +4 -0
- data/lib/metanorma/html/templates/_doc_title.html.liquid +1 -1
- data/lib/metanorma/html/templates/_example.html.liquid +3 -0
- data/lib/metanorma/html/templates/_figure.html.liquid +6 -0
- data/lib/metanorma/html/templates/_formula.html.liquid +6 -0
- data/lib/metanorma/html/templates/_iso_doc_title.html.liquid +2 -2
- data/lib/metanorma/html/templates/_note.html.liquid +3 -0
- data/lib/metanorma/html/templates/_sourcecode.html.liquid +4 -0
- data/lib/metanorma/html.rb +0 -1
- metadata +16 -3
- data/lib/metanorma/html/component_registry.rb +0 -37
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "liquid"
|
|
4
4
|
require "nokogiri"
|
|
5
|
+
require "cgi"
|
|
5
6
|
require_relative "drops/footnote_drop"
|
|
6
7
|
|
|
7
8
|
module Metanorma
|
|
@@ -17,43 +18,33 @@ module Metanorma
|
|
|
17
18
|
class BaseRenderer
|
|
18
19
|
LOGO_DIR = File.expand_path("../../../data/logos", __dir__)
|
|
19
20
|
|
|
20
|
-
#
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"TermNum" => "term-number",
|
|
31
|
-
"Terms" => "term-name",
|
|
32
|
-
"DeprecatedTerms" => "term-deprecated",
|
|
33
|
-
"domain" => "term-domain",
|
|
34
|
-
"boldtitle" => "bold-title",
|
|
35
|
-
"note_label" => "note-label",
|
|
36
|
-
"termnote_label" => "term-note-label",
|
|
37
|
-
"example_label" => "example-label",
|
|
38
|
-
"stddocNumber" => "std-doc-number",
|
|
39
|
-
"stdyear" => "std-year",
|
|
40
|
-
"sourcecode-name" => "code-name",
|
|
21
|
+
# HTML-specific class names for inline spans, keyed by the XML span role.
|
|
22
|
+
# The XML class_attr is INPUT only — we never emit it in HTML.
|
|
23
|
+
SPAN_ROLE_CLASSES = {
|
|
24
|
+
"boldtitle" => "title-text",
|
|
25
|
+
"nonboldtitle" => "subtitle-text",
|
|
26
|
+
"citeapp" => "xref-app",
|
|
27
|
+
"citefig" => "xref-fig",
|
|
28
|
+
"citesec" => "xref-section",
|
|
29
|
+
"citetbl" => "xref-table",
|
|
30
|
+
"fmt-autonum-delim" => "number-delim",
|
|
41
31
|
"fmt-caption-label" => "caption-label",
|
|
42
|
-
"fmt-autonum-delim" => "autonum-delim",
|
|
43
|
-
"fmt-element-name" => "element-name",
|
|
44
32
|
"fmt-caption-delim" => "caption-delim",
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"nonboldtitle" => "doc-subtitle",
|
|
52
|
-
"stddocPartNumber" => "doc-part-number",
|
|
53
|
-
"stddocTitle" => "doc-part-title",
|
|
54
|
-
"std_publisher" => "doc-publisher",
|
|
55
|
-
"stdpublisher" => "doc-publisher-name",
|
|
33
|
+
"fmt-element-name" => "element-label",
|
|
34
|
+
"fmt-comma" => "comma",
|
|
35
|
+
"fmt-conn" => "connector",
|
|
36
|
+
"fmt-label-delim" => "label-delim",
|
|
37
|
+
"fmt-obligation" => "obligation-text",
|
|
38
|
+
"fmt-xref-container" => "xref-container",
|
|
56
39
|
"fmt-xref-label" => "xref-label",
|
|
40
|
+
"std_publisher" => "ref-publisher",
|
|
41
|
+
"stdpublisher" => "ref-publisher-name",
|
|
42
|
+
"stddocNumber" => "ref-doc-number",
|
|
43
|
+
"stddocTitle" => "ref-title",
|
|
44
|
+
"stddocPartNumber" => "ref-part-number",
|
|
45
|
+
"stdyear" => "ref-year",
|
|
46
|
+
"date" => "date",
|
|
47
|
+
"smallcap" => "small-caps",
|
|
57
48
|
}.freeze
|
|
58
49
|
|
|
59
50
|
METANORMA_LOGO = "metanorma-logo.svg"
|
|
@@ -71,6 +62,40 @@ module Metanorma
|
|
|
71
62
|
|
|
72
63
|
# --- Public API ---
|
|
73
64
|
|
|
65
|
+
# Facade object for Drops to call renderer methods without exposing
|
|
66
|
+
# the full private interface. Delegates to the renderer internally.
|
|
67
|
+
class RendererContext
|
|
68
|
+
def initialize(renderer)
|
|
69
|
+
@renderer = renderer
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def safe_attr(obj, method_name) = @renderer.send(:safe_attr, obj, method_name)
|
|
73
|
+
def escape_html(text) = @renderer.send(:escape_html, text)
|
|
74
|
+
def extract_block_label(block, default) = @renderer.send(:extract_block_label, block, default)
|
|
75
|
+
def extract_plain_text(node) = @renderer.send(:extract_plain_text, node)
|
|
76
|
+
def capture_output(&) = @renderer.send(:capture_output, &)
|
|
77
|
+
def render_paragraph(p) = @renderer.send(:render_paragraph, p)
|
|
78
|
+
def render_mixed_inline(node) = @renderer.send(:render_mixed_inline, node)
|
|
79
|
+
def render_inline_element(el) = @renderer.send(:render_inline_element, el)
|
|
80
|
+
def render_unordered_list(ul) = @renderer.send(:render_unordered_list, ul)
|
|
81
|
+
def render_ordered_list(ol) = @renderer.send(:render_ordered_list, ol)
|
|
82
|
+
def render_definition_list(dl) = @renderer.send(:render_definition_list, dl)
|
|
83
|
+
def render_sourcecode(sc) = @renderer.send(:render_sourcecode, sc)
|
|
84
|
+
def render_table(t) = @renderer.send(:render_table, t)
|
|
85
|
+
def render_figure(f) = @renderer.send(:render_figure, f)
|
|
86
|
+
def render_quote(q) = @renderer.send(:render_quote, q)
|
|
87
|
+
def render_formula(f) = @renderer.send(:render_formula, f)
|
|
88
|
+
def render_note(n) = @renderer.send(:render_note, n)
|
|
89
|
+
def render_image(img) = @renderer.send(:render_image, img)
|
|
90
|
+
def render_stem_content(stem) = @renderer.send(:render_stem_content, stem)
|
|
91
|
+
def register_figure_entry(...) = @renderer.send(:register_figure_entry, ...)
|
|
92
|
+
def render_liquid(template_name, assigns) = @renderer.send(:render_liquid, template_name, assigns)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def renderer_context
|
|
96
|
+
@renderer_context ||= RendererContext.new(self)
|
|
97
|
+
end
|
|
98
|
+
|
|
74
99
|
def to_html
|
|
75
100
|
@output
|
|
76
101
|
end
|
|
@@ -117,11 +142,14 @@ module Metanorma
|
|
|
117
142
|
|
|
118
143
|
# --- Document Assembly ---
|
|
119
144
|
|
|
120
|
-
TEMPLATE_CACHE =
|
|
145
|
+
TEMPLATE_CACHE = {}
|
|
146
|
+
TEMPLATE_CACHE_MUTEX = Mutex.new
|
|
121
147
|
|
|
122
148
|
def render_liquid(template_name, assigns)
|
|
123
149
|
template_path = File.join(TEMPLATES_ROOT, template_name)
|
|
124
|
-
template =
|
|
150
|
+
template = TEMPLATE_CACHE_MUTEX.synchronize do
|
|
151
|
+
TEMPLATE_CACHE[template_path] ||= Liquid::Template.parse(File.read(template_path))
|
|
152
|
+
end
|
|
125
153
|
assigns = assigns.transform_keys(&:to_s) if assigns.is_a?(Hash)
|
|
126
154
|
template.render(assigns)
|
|
127
155
|
end
|
|
@@ -132,16 +160,16 @@ module Metanorma
|
|
|
132
160
|
footer = build_footer
|
|
133
161
|
|
|
134
162
|
render_liquid("document.html.liquid", {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
163
|
+
"lang" => language,
|
|
164
|
+
"title" => html_title,
|
|
165
|
+
"font_url" => flavor_font_url,
|
|
166
|
+
"styles" => build_styles,
|
|
167
|
+
"header" => header,
|
|
168
|
+
"toc" => toc_html,
|
|
169
|
+
"body" => body,
|
|
170
|
+
"footer" => footer,
|
|
171
|
+
"scripts" => build_scripts,
|
|
172
|
+
})
|
|
145
173
|
end
|
|
146
174
|
|
|
147
175
|
# --- Header and Footer ---
|
|
@@ -157,20 +185,15 @@ module Metanorma
|
|
|
157
185
|
end
|
|
158
186
|
|
|
159
187
|
render_liquid("_header.html.liquid", {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
188
|
+
"publisher_logos" => pub_logos,
|
|
189
|
+
"doc_id" => display_id,
|
|
190
|
+
"doc_title" => header_title_text,
|
|
191
|
+
})
|
|
164
192
|
end
|
|
165
193
|
|
|
166
194
|
def header_title_text
|
|
167
195
|
raw = html_title.to_s.split(" — ").first.to_s.gsub(/<[^>]+>/, "")
|
|
168
|
-
raw.length > 60 ? raw[0, 57]
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
# Reader controls — kept for backward compat with flavor renderers
|
|
172
|
-
def build_reader_controls
|
|
173
|
-
""
|
|
196
|
+
raw.length > 60 ? "#{raw[0, 57]}..." : raw
|
|
174
197
|
end
|
|
175
198
|
|
|
176
199
|
def build_publisher_logos
|
|
@@ -192,10 +215,6 @@ module Metanorma
|
|
|
192
215
|
end.join("\n")
|
|
193
216
|
end
|
|
194
217
|
|
|
195
|
-
def detect_publishers
|
|
196
|
-
flavor_publishers(extract_primary_doc_id)
|
|
197
|
-
end
|
|
198
|
-
|
|
199
218
|
def load_logo_svg(filename, height: 32)
|
|
200
219
|
path = File.join(LOGO_DIR, filename)
|
|
201
220
|
return nil unless File.exist?(path)
|
|
@@ -205,13 +224,12 @@ module Metanorma
|
|
|
205
224
|
svg = svg.sub(/\A\s*<!--.*?-->\s*/m, "")
|
|
206
225
|
svg = svg.sub(/<path[^>]*style="fill:#e3000f[^"]*"[^>]*\/>/, "")
|
|
207
226
|
svg = svg.sub(/<svg\s/, '<svg class="header-logo" ')
|
|
208
|
-
if svg.match?(/<svg[^>]*\sheight="[^"]*"/)
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
svg
|
|
214
|
-
svg
|
|
227
|
+
svg = if svg.match?(/<svg[^>]*\sheight="[^"]*"/)
|
|
228
|
+
svg.sub(/(<svg[^>]*?)(\sheight="[^"]*")/, "\\1 height=\"#{height}\"")
|
|
229
|
+
else
|
|
230
|
+
svg.sub(/(<svg\b)/, "\\1 height=\"#{height}\"")
|
|
231
|
+
end
|
|
232
|
+
svg.sub(/(<svg[^>]*?)\swidth="[^"]*"/, '\1')
|
|
215
233
|
rescue StandardError
|
|
216
234
|
nil
|
|
217
235
|
end
|
|
@@ -219,9 +237,9 @@ module Metanorma
|
|
|
219
237
|
def build_footer
|
|
220
238
|
mn_logo = load_logo_svg(METANORMA_LOGO, height: 20)
|
|
221
239
|
render_liquid("_footer.html.liquid", {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
240
|
+
"mn_logo" => mn_logo,
|
|
241
|
+
"generated_at" => Time.now.strftime("%Y-%m-%d %H:%M"),
|
|
242
|
+
})
|
|
225
243
|
end
|
|
226
244
|
|
|
227
245
|
# --- ToC generation ---
|
|
@@ -231,32 +249,32 @@ module Metanorma
|
|
|
231
249
|
main_lines = if entries.empty?
|
|
232
250
|
["<li class=\"toc-empty\">No entries</li>"]
|
|
233
251
|
else
|
|
234
|
-
entries.map
|
|
252
|
+
entries.map do |e|
|
|
235
253
|
id = e[:id].to_s
|
|
236
254
|
text = escape_html(e[:text].to_s)
|
|
237
255
|
lvl = e[:level]
|
|
238
256
|
"<li class=\"toc-level-#{lvl}\"><a href=\"##{id}\" class=\"toc-link\" data-target=\"#{id}\">#{text}</a></li>"
|
|
239
|
-
|
|
257
|
+
end
|
|
240
258
|
end
|
|
241
259
|
|
|
242
260
|
# List of Figures — at top of sidebar
|
|
243
261
|
unless @figure_entries.empty?
|
|
244
262
|
top_lines << "<li class=\"toc-list-header\" data-list=\"figures\"><button class=\"toc-list-toggle\" aria-expanded=\"false\"><svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><rect x=\"1\" y=\"2\" width=\"14\" height=\"12\" rx=\"1\"/><circle cx=\"5\" cy=\"6.5\" r=\"1.5\"/><path d=\"M1 12l4-4 2 2 3-3 5 5\"/></svg> Figures <span class=\"toc-list-count\">(#{@figure_entries.size})</span></button></li>"
|
|
245
|
-
@figure_entries.each
|
|
263
|
+
@figure_entries.each do |f|
|
|
246
264
|
id = f[:id].to_s
|
|
247
265
|
text = escape_html(f[:text].to_s)
|
|
248
266
|
top_lines << "<li class=\"toc-list-item toc-figures\" style=\"display:none\"><a href=\"##{id}\" class=\"toc-link\" data-target=\"#{id}\">#{text}</a></li>"
|
|
249
|
-
|
|
267
|
+
end
|
|
250
268
|
end
|
|
251
269
|
|
|
252
270
|
# List of Tables — at top of sidebar
|
|
253
271
|
unless @table_entries.empty?
|
|
254
272
|
top_lines << "<li class=\"toc-list-header\" data-list=\"tables\"><button class=\"toc-list-toggle\" aria-expanded=\"false\"><svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><rect x=\"1\" y=\"2\" width=\"14\" height=\"12\" rx=\"1\"/><line x1=\"1\" y1=\"6\" x2=\"15\" y2=\"6\"/><line x1=\"1\" y1=\"10\" x2=\"15\" y2=\"10\"/><line x1=\"7\" y1=\"2\" x2=\"7\" y2=\"14\"/></svg> Tables <span class=\"toc-list-count\">(#{@table_entries.size})</span></button></li>"
|
|
255
|
-
@table_entries.each
|
|
273
|
+
@table_entries.each do |t|
|
|
256
274
|
id = t[:id].to_s
|
|
257
275
|
text = escape_html(t[:text].to_s)
|
|
258
276
|
top_lines << "<li class=\"toc-list-item toc-tables\" style=\"display:none\"><a href=\"##{id}\" class=\"toc-link\" data-target=\"#{id}\">#{text}</a></li>"
|
|
259
|
-
|
|
277
|
+
end
|
|
260
278
|
end
|
|
261
279
|
|
|
262
280
|
top_lines << "<li class=\"toc-divider\"></li>" unless top_lines.empty?
|
|
@@ -307,12 +325,25 @@ module Metanorma
|
|
|
307
325
|
end
|
|
308
326
|
|
|
309
327
|
if node.is_a?(Lutaml::Model::Serializable)
|
|
310
|
-
return true if
|
|
311
|
-
|
|
328
|
+
return true if begin
|
|
329
|
+
node.fmt_title
|
|
330
|
+
rescue StandardError
|
|
331
|
+
nil
|
|
332
|
+
end
|
|
333
|
+
return true if begin
|
|
334
|
+
node.displayorder
|
|
335
|
+
rescue StandardError
|
|
336
|
+
nil
|
|
337
|
+
end
|
|
312
338
|
|
|
313
339
|
%i[preface sections annex bibliography].each do |attr|
|
|
314
|
-
val =
|
|
340
|
+
val = begin
|
|
341
|
+
node.public_send(attr)
|
|
342
|
+
rescue StandardError
|
|
343
|
+
nil
|
|
344
|
+
end
|
|
315
345
|
next unless val
|
|
346
|
+
|
|
316
347
|
Array(val).each { |v| return true if check_presentation_markers(v) }
|
|
317
348
|
end
|
|
318
349
|
|
|
@@ -405,6 +436,7 @@ module Metanorma
|
|
|
405
436
|
indices = Hash.new(0)
|
|
406
437
|
node.element_order.each do |el|
|
|
407
438
|
next unless el.is_a?(Lutaml::Xml::Element)
|
|
439
|
+
|
|
408
440
|
if el.text?
|
|
409
441
|
parts << el.text_content.to_s
|
|
410
442
|
elsif el.name == "tab"
|
|
@@ -434,42 +466,42 @@ module Metanorma
|
|
|
434
466
|
parts << (t.is_a?(Array) ? t.join : t.to_s) if t
|
|
435
467
|
end
|
|
436
468
|
|
|
437
|
-
parts.join.strip.gsub(
|
|
469
|
+
parts.join.strip.gsub("\u00A0", " ")
|
|
438
470
|
end
|
|
439
471
|
|
|
440
472
|
# Dispatch to the appropriate render method based on node class.
|
|
441
|
-
def render(node, **
|
|
473
|
+
def render(node, **)
|
|
442
474
|
case node
|
|
443
475
|
when Metanorma::Document::Components::Paragraphs::ParagraphBlock
|
|
444
|
-
render_paragraph(node, **
|
|
476
|
+
render_paragraph(node, **)
|
|
445
477
|
when Metanorma::Document::Components::Tables::TableBlock
|
|
446
|
-
render_table(node, **
|
|
478
|
+
render_table(node, **)
|
|
447
479
|
when Metanorma::Document::Components::Lists::UnorderedList
|
|
448
|
-
render_unordered_list(node, **
|
|
480
|
+
render_unordered_list(node, **)
|
|
449
481
|
when Metanorma::Document::Components::Lists::OrderedList
|
|
450
|
-
render_ordered_list(node, **
|
|
482
|
+
render_ordered_list(node, **)
|
|
451
483
|
when Metanorma::Document::Components::Lists::DefinitionList
|
|
452
|
-
render_definition_list(node, **
|
|
484
|
+
render_definition_list(node, **)
|
|
453
485
|
when Metanorma::Document::Components::AncillaryBlocks::FigureBlock
|
|
454
|
-
render_figure(node, **
|
|
486
|
+
render_figure(node, **)
|
|
455
487
|
when Metanorma::Document::Components::Blocks::NoteBlock
|
|
456
|
-
render_note(node, **
|
|
488
|
+
render_note(node, **)
|
|
457
489
|
when Metanorma::Document::Components::AncillaryBlocks::ExampleBlock
|
|
458
|
-
render_example(node, **
|
|
490
|
+
render_example(node, **)
|
|
459
491
|
when Metanorma::Document::Components::AncillaryBlocks::SourcecodeBlock
|
|
460
|
-
render_sourcecode(node, **
|
|
492
|
+
render_sourcecode(node, **)
|
|
461
493
|
when Metanorma::Document::Components::AncillaryBlocks::FormulaBlock
|
|
462
|
-
render_formula(node, **
|
|
494
|
+
render_formula(node, **)
|
|
463
495
|
when Metanorma::Document::Components::MultiParagraph::QuoteBlock
|
|
464
|
-
render_quote(node, **
|
|
496
|
+
render_quote(node, **)
|
|
465
497
|
when Metanorma::Document::Components::MultiParagraph::AdmonitionBlock
|
|
466
|
-
render_admonition(node, **
|
|
498
|
+
render_admonition(node, **)
|
|
467
499
|
when Metanorma::Document::Components::Sections::HierarchicalSection
|
|
468
|
-
render_hierarchical_section(node, **
|
|
500
|
+
render_hierarchical_section(node, **)
|
|
469
501
|
when Metanorma::Document::Components::Sections::BasicSection
|
|
470
|
-
render_basic_section(node, **
|
|
502
|
+
render_basic_section(node, **)
|
|
471
503
|
when Metanorma::Document::Components::Sections::ContentSection
|
|
472
|
-
render_content_section(node, **
|
|
504
|
+
render_content_section(node, **)
|
|
473
505
|
when Metanorma::Document::Components::EmptyElements::PageBreakElement
|
|
474
506
|
""
|
|
475
507
|
when Metanorma::Document::Components::IdElements::Bookmark
|
|
@@ -488,7 +520,7 @@ module Metanorma
|
|
|
488
520
|
# --- Block-level rendering ---
|
|
489
521
|
|
|
490
522
|
def render_paragraph(p, **_opts)
|
|
491
|
-
attrs = element_attrs(id: safe_attr(p, :id),
|
|
523
|
+
attrs = element_attrs(id: safe_attr(p, :id), style: alignment_style(safe_attr(p, :alignment)))
|
|
492
524
|
tag("p", attrs) { render_mixed_inline(p) }
|
|
493
525
|
end
|
|
494
526
|
|
|
@@ -531,19 +563,21 @@ module Metanorma
|
|
|
531
563
|
if table.colgroup&.col && !table.colgroup.col.empty?
|
|
532
564
|
return table.colgroup.col.size
|
|
533
565
|
end
|
|
566
|
+
|
|
534
567
|
# Walk all rows to find max column count, accounting for colspan
|
|
535
568
|
max_cols = 0
|
|
536
|
-
[
|
|
569
|
+
%i[thead tbody tfoot].each do |section|
|
|
537
570
|
sec = table.public_send(section)
|
|
538
571
|
next unless sec&.tr
|
|
572
|
+
|
|
539
573
|
sec.tr.each do |tr|
|
|
540
574
|
cols = 0
|
|
541
|
-
Array(tr.th).each { |th| cols +=
|
|
542
|
-
Array(tr.td).each { |td| cols +=
|
|
575
|
+
Array(tr.th).each { |th| cols += th.colspan && th.colspan > 1 ? th.colspan : 1 }
|
|
576
|
+
Array(tr.td).each { |td| cols += td.colspan && td.colspan > 1 ? td.colspan : 1 }
|
|
543
577
|
max_cols = cols if cols > max_cols
|
|
544
578
|
end
|
|
545
579
|
end
|
|
546
|
-
max_cols
|
|
580
|
+
max_cols.positive? ? max_cols : 1
|
|
547
581
|
end
|
|
548
582
|
|
|
549
583
|
def render_table_colgroup(colgroup)
|
|
@@ -564,6 +598,7 @@ module Metanorma
|
|
|
564
598
|
@output << "<tr>"
|
|
565
599
|
walked = walk_ordered(tr) do |type, obj|
|
|
566
600
|
next unless type == :element
|
|
601
|
+
|
|
567
602
|
render_table_cell(obj)
|
|
568
603
|
end
|
|
569
604
|
unless walked
|
|
@@ -575,7 +610,7 @@ module Metanorma
|
|
|
575
610
|
end
|
|
576
611
|
|
|
577
612
|
def render_unordered_list(ul, **_opts)
|
|
578
|
-
attrs = element_attrs(id: safe_attr(ul, :id)
|
|
613
|
+
attrs = element_attrs(id: safe_attr(ul, :id))
|
|
579
614
|
tag("ul", attrs) do
|
|
580
615
|
ul.listitem&.each { |li| render_list_item(li) }
|
|
581
616
|
end
|
|
@@ -595,7 +630,7 @@ module Metanorma
|
|
|
595
630
|
end
|
|
596
631
|
|
|
597
632
|
def render_ordered_list(ol, **_opts)
|
|
598
|
-
attrs = element_attrs(id: safe_attr(ol, :id),
|
|
633
|
+
attrs = element_attrs(id: safe_attr(ol, :id), start: safe_attr(ol, :start), type: safe_attr(ol, :type_attr))
|
|
599
634
|
tag("ol", attrs) do
|
|
600
635
|
ol.listitem&.each { |li| render_list_item(li) }
|
|
601
636
|
end
|
|
@@ -634,7 +669,8 @@ module Metanorma
|
|
|
634
669
|
children = []
|
|
635
670
|
|
|
636
671
|
walk_ordered(section) do |type, obj|
|
|
637
|
-
next if
|
|
672
|
+
next if %i[text tab].include?(type)
|
|
673
|
+
|
|
638
674
|
children << obj
|
|
639
675
|
end
|
|
640
676
|
|
|
@@ -643,6 +679,7 @@ module Metanorma
|
|
|
643
679
|
supplementary_attrs.each do |attr|
|
|
644
680
|
val = safe_attr(section, attr)
|
|
645
681
|
next if val.nil?
|
|
682
|
+
|
|
646
683
|
Array(val).each do |v|
|
|
647
684
|
children << v unless children.include?(v)
|
|
648
685
|
end
|
|
@@ -665,7 +702,11 @@ module Metanorma
|
|
|
665
702
|
|
|
666
703
|
def sort_by_displayorder(children)
|
|
667
704
|
children.sort_by do |node|
|
|
668
|
-
order =
|
|
705
|
+
order = begin
|
|
706
|
+
node.displayorder
|
|
707
|
+
rescue StandardError
|
|
708
|
+
nil
|
|
709
|
+
end
|
|
669
710
|
order &&= order.to_i
|
|
670
711
|
order || Float::INFINITY
|
|
671
712
|
end
|
|
@@ -689,29 +730,8 @@ module Metanorma
|
|
|
689
730
|
end
|
|
690
731
|
|
|
691
732
|
def render_figure(figure, **_opts)
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
fig_name = safe_attr(figure, :fmt_name) || safe_attr(figure, :name)
|
|
695
|
-
if fig_id && fig_name
|
|
696
|
-
register_figure_entry(id: fig_id, text: extract_plain_text(fig_name))
|
|
697
|
-
end
|
|
698
|
-
tag("figure", attrs) do
|
|
699
|
-
if figure.image
|
|
700
|
-
render_image(figure.image)
|
|
701
|
-
elsif safe_attr(figure, :source)
|
|
702
|
-
@output << %(<img src="#{escape_html(figure.source)}" />)
|
|
703
|
-
end
|
|
704
|
-
render_video(figure.video) if safe_attr(figure, :video)
|
|
705
|
-
render_audio(figure.audio) if safe_attr(figure, :audio)
|
|
706
|
-
figure.figure&.each { |sub| render_figure(sub) }
|
|
707
|
-
if safe_attr(figure, :name) || safe_attr(figure, :fmt_name)
|
|
708
|
-
@output << "<figcaption>"
|
|
709
|
-
render_inline_element(safe_attr(figure, :fmt_name) || figure.name)
|
|
710
|
-
@output << "</figcaption>"
|
|
711
|
-
end
|
|
712
|
-
safe_attr(figure, :note)&.each { |n| render_note(n) }
|
|
713
|
-
safe_attr(figure, :dl)&.then { |dl| render_definition_list(dl) }
|
|
714
|
-
end
|
|
733
|
+
drop = Drops::FigureDrop.from_model(figure, renderer: renderer_context)
|
|
734
|
+
@output << render_liquid("_figure.html.liquid", { "block" => drop })
|
|
715
735
|
end
|
|
716
736
|
|
|
717
737
|
def render_image(image)
|
|
@@ -743,91 +763,23 @@ module Metanorma
|
|
|
743
763
|
end
|
|
744
764
|
|
|
745
765
|
def render_note(note, **_opts)
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
label = extract_block_label(note, "NOTE")
|
|
749
|
-
@output << %(<span class="note-label">#{escape_html(label)}</span> )
|
|
750
|
-
if note.content && !note.content.empty?
|
|
751
|
-
note.content.each { |para| render_paragraph(para) }
|
|
752
|
-
else
|
|
753
|
-
render_mixed_inline(note)
|
|
754
|
-
end
|
|
755
|
-
note.ul&.each { |ul| render_unordered_list(ul) }
|
|
756
|
-
note.ol&.each { |ol| render_ordered_list(ol) }
|
|
757
|
-
note.dl&.then { |dl| render_definition_list(dl) }
|
|
758
|
-
end
|
|
766
|
+
drop = Drops::NoteDrop.from_model(note, renderer: renderer_context)
|
|
767
|
+
@output << render_liquid("_note.html.liquid", { "block" => drop })
|
|
759
768
|
end
|
|
760
769
|
|
|
761
770
|
def render_example(example, **_opts)
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
label = extract_block_label(example, "EXAMPLE")
|
|
765
|
-
@output << %(<span class="example-label">#{escape_html(label)}</span> )
|
|
766
|
-
if example.paragraphs && !example.paragraphs.empty?
|
|
767
|
-
example.paragraphs.each { |para| render_paragraph(para) }
|
|
768
|
-
end
|
|
769
|
-
example.ul&.each { |ul| render_unordered_list(ul) }
|
|
770
|
-
example.ol&.each { |ol| render_ordered_list(ol) }
|
|
771
|
-
example.dl&.each { |dl| render_definition_list(dl) } if example.dl
|
|
772
|
-
example.sourcecode&.each { |sc| render_sourcecode(sc) }
|
|
773
|
-
example.table&.each { |t| render_table(t) }
|
|
774
|
-
example.figure&.each { |f| render_figure(f) }
|
|
775
|
-
example.quote&.each { |q| render_quote(q) }
|
|
776
|
-
example.formula&.each { |f| render_formula(f) }
|
|
777
|
-
end
|
|
771
|
+
drop = Drops::ExampleDrop.from_model(example, renderer: renderer_context)
|
|
772
|
+
@output << render_liquid("_example.html.liquid", { "block" => drop })
|
|
778
773
|
end
|
|
779
774
|
|
|
780
775
|
def render_sourcecode(sc, **_opts)
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
tag("div", attrs) do
|
|
784
|
-
if sc.name
|
|
785
|
-
@output << "<p class=\"code-name\">"
|
|
786
|
-
render_inline_element(sc.name)
|
|
787
|
-
@output << "</p>"
|
|
788
|
-
end
|
|
789
|
-
code_attrs = lang ? %( lang="#{escape_html(lang)}") : ""
|
|
790
|
-
@output << "<pre><code#{code_attrs}>"
|
|
791
|
-
# Use body.content if available, else content, else text
|
|
792
|
-
code_text = if sc.body && sc.body.content
|
|
793
|
-
sc.body.content
|
|
794
|
-
elsif sc.content
|
|
795
|
-
sc.content
|
|
796
|
-
else
|
|
797
|
-
""
|
|
798
|
-
end
|
|
799
|
-
# body.content from map_all_content may contain pre-escaped HTML
|
|
800
|
-
# entities (< etc); decode first to get raw text, then escape
|
|
801
|
-
# for HTML output.
|
|
802
|
-
raw_text = code_text.gsub("<", "<").gsub(">", ">").gsub("&", "&").gsub(""", "\"")
|
|
803
|
-
@output << escape_html(raw_text)
|
|
804
|
-
@output << "</code></pre>"
|
|
805
|
-
end
|
|
776
|
+
drop = Drops::SourcecodeDrop.from_model(sc, renderer: renderer_context)
|
|
777
|
+
@output << render_liquid("_sourcecode.html.liquid", { "block" => drop })
|
|
806
778
|
end
|
|
807
779
|
|
|
808
780
|
def render_formula(formula, **_opts)
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
@output << render_stem_content(formula.stem) if formula.stem
|
|
812
|
-
|
|
813
|
-
# Render "where" clause from key element (non-presentation XML)
|
|
814
|
-
if formula.key
|
|
815
|
-
if formula.key.dl
|
|
816
|
-
@output << "<p class=\"formula-where\">where</p>"
|
|
817
|
-
render_definition_list(formula.key.dl)
|
|
818
|
-
end
|
|
819
|
-
formula.key.p&.each { |para| render_paragraph(para) }
|
|
820
|
-
end
|
|
821
|
-
|
|
822
|
-
formula.dl&.then { |dl| render_definition_list(dl) }
|
|
823
|
-
|
|
824
|
-
name_el = safe_attr(formula, :fmt_name) || safe_attr(formula, :name)
|
|
825
|
-
if name_el
|
|
826
|
-
@output << "<span class=\"formula-number\">"
|
|
827
|
-
render_inline_element(name_el)
|
|
828
|
-
@output << "</span>"
|
|
829
|
-
end
|
|
830
|
-
end
|
|
781
|
+
drop = Drops::FormulaDrop.from_model(formula, renderer: renderer_context)
|
|
782
|
+
@output << render_liquid("_formula.html.liquid", { "block" => drop })
|
|
831
783
|
end
|
|
832
784
|
|
|
833
785
|
def render_quote(quote, **_opts)
|
|
@@ -845,12 +797,8 @@ module Metanorma
|
|
|
845
797
|
end
|
|
846
798
|
|
|
847
799
|
def render_admonition(admonition, **_opts)
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
tag("div", attrs) do
|
|
851
|
-
@output << "<p class=\"admonition-title\">#{escape_html(type.capitalize)}</p>"
|
|
852
|
-
admonition.paragraphs&.each { |para| render_paragraph(para) }
|
|
853
|
-
end
|
|
800
|
+
drop = Drops::AdmonitionDrop.from_model(admonition, renderer: renderer_context)
|
|
801
|
+
@output << render_liquid("_admonition.html.liquid", { "block" => drop })
|
|
854
802
|
end
|
|
855
803
|
|
|
856
804
|
def render_bookmark(bookmark)
|
|
@@ -973,13 +921,14 @@ module Metanorma
|
|
|
973
921
|
skip = {}
|
|
974
922
|
node.element_order.each_with_index do |el, i|
|
|
975
923
|
next unless el.element?
|
|
924
|
+
|
|
976
925
|
next_tag = skip_after[el.name]
|
|
977
926
|
next unless next_tag
|
|
978
927
|
|
|
979
928
|
next_el = node.element_order[i + 1]
|
|
980
929
|
if next_tag.nil?
|
|
981
930
|
skip[i] = true
|
|
982
|
-
elsif next_el
|
|
931
|
+
elsif next_el&.element? && next_el.name == next_tag
|
|
983
932
|
skip[i] = true
|
|
984
933
|
end
|
|
985
934
|
end
|
|
@@ -1035,7 +984,9 @@ module Metanorma
|
|
|
1035
984
|
end
|
|
1036
985
|
|
|
1037
986
|
def raw_content_node?(node)
|
|
1038
|
-
node.is_a?(
|
|
987
|
+
node.is_a?(Lutaml::Model::Serializable) &&
|
|
988
|
+
node.respond_to?(:content) &&
|
|
989
|
+
node.content.is_a?(String)
|
|
1039
990
|
end
|
|
1040
991
|
|
|
1041
992
|
# Iterate element_order directly, preserving whitespace text nodes
|
|
@@ -1107,7 +1058,9 @@ module Metanorma
|
|
|
1107
1058
|
# Source element — skip; rendered via fmt-xref in semx wrapper
|
|
1108
1059
|
nil
|
|
1109
1060
|
when Metanorma::Document::Components::Inline::SpanElement
|
|
1110
|
-
|
|
1061
|
+
xml_class = safe_attr(element, :class_attr).to_s
|
|
1062
|
+
html_class = html_class_for_span(xml_class) unless xml_class.empty?
|
|
1063
|
+
attrs = element_attrs(style: safe_attr(element, :style), class: html_class)
|
|
1111
1064
|
tag("span", attrs) { render_mixed_inline(element) }
|
|
1112
1065
|
when Metanorma::Document::Components::Inline::FnElement
|
|
1113
1066
|
render_fn(element)
|
|
@@ -1183,13 +1136,13 @@ module Metanorma
|
|
|
1183
1136
|
texts = node.text
|
|
1184
1137
|
if texts.is_a?(Array)
|
|
1185
1138
|
texts.each do |t|
|
|
1186
|
-
if t.is_a?(Metanorma::Document::Components::Inline::MathElement)
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1139
|
+
@output << if t.is_a?(Metanorma::Document::Components::Inline::MathElement)
|
|
1140
|
+
t.content.to_s
|
|
1141
|
+
elsif t.is_a?(Metanorma::Document::Components::Inline::AsciimathElement)
|
|
1142
|
+
%(<span class="stem">#{escape_html(Array(t.text).join)}</span>)
|
|
1143
|
+
else
|
|
1144
|
+
escape_html(t.to_s)
|
|
1145
|
+
end
|
|
1193
1146
|
end
|
|
1194
1147
|
elsif texts.is_a?(String)
|
|
1195
1148
|
@output << escape_html(texts)
|
|
@@ -1239,6 +1192,7 @@ module Metanorma
|
|
|
1239
1192
|
display_attrs.each do |attr|
|
|
1240
1193
|
val = safe_attr(element, attr)
|
|
1241
1194
|
next if val.nil?
|
|
1195
|
+
|
|
1242
1196
|
if val.is_a?(Array)
|
|
1243
1197
|
val.each do |v|
|
|
1244
1198
|
if v.is_a?(Metanorma::Document::Components::Paragraphs::ParagraphBlock)
|
|
@@ -1261,7 +1215,7 @@ module Metanorma
|
|
|
1261
1215
|
return semx_text unless first_word
|
|
1262
1216
|
|
|
1263
1217
|
tail = output[-200..]
|
|
1264
|
-
return semx_text unless tail
|
|
1218
|
+
return semx_text unless tail&.rstrip&.end_with?(first_word)
|
|
1265
1219
|
|
|
1266
1220
|
semx_text.sub(/\A\s*#{Regexp.escape(first_word)}\s*/, "")
|
|
1267
1221
|
end
|
|
@@ -1279,7 +1233,7 @@ module Metanorma
|
|
|
1279
1233
|
doc.css("fmt-link").each do |el|
|
|
1280
1234
|
target = el["target"] || el["href"]
|
|
1281
1235
|
if target
|
|
1282
|
-
display_text = target.
|
|
1236
|
+
display_text = target.delete_prefix("mailto:")
|
|
1283
1237
|
a = doc.document.create_element("a", display_text, "href" => target)
|
|
1284
1238
|
el.replace(a)
|
|
1285
1239
|
else
|
|
@@ -1292,11 +1246,12 @@ module Metanorma
|
|
|
1292
1246
|
doc.traverse do |node|
|
|
1293
1247
|
next unless node.element?
|
|
1294
1248
|
next unless %w[xref eref stem link].include?(node.name)
|
|
1249
|
+
|
|
1295
1250
|
next_sib = node.next_sibling
|
|
1296
1251
|
while next_sib.is_a?(Nokogiri::XML::Text) && next_sib.text.strip.empty?
|
|
1297
1252
|
next_sib = next_sib.next_sibling
|
|
1298
1253
|
end
|
|
1299
|
-
next unless next_sib
|
|
1254
|
+
next unless next_sib&.element? && next_sib.name == "semx"
|
|
1300
1255
|
|
|
1301
1256
|
deduplicate_semx_label(node, next_sib)
|
|
1302
1257
|
node.remove
|
|
@@ -1305,6 +1260,10 @@ module Metanorma
|
|
|
1305
1260
|
%w[semx fmt-xref].each do |tag|
|
|
1306
1261
|
doc.css(tag).each { |el| el.replace(el.children) }
|
|
1307
1262
|
end
|
|
1263
|
+
# Remap XML class names to HTML-specific class names
|
|
1264
|
+
doc.css("[class]").each do |el|
|
|
1265
|
+
el["class"] = el["class"].split(/\s+/).map { |c| html_class_for_span(c) }.join(" ")
|
|
1266
|
+
end
|
|
1308
1267
|
doc.inner_html
|
|
1309
1268
|
end
|
|
1310
1269
|
|
|
@@ -1328,13 +1287,13 @@ module Metanorma
|
|
|
1328
1287
|
|
|
1329
1288
|
def render_link(link)
|
|
1330
1289
|
target = safe_attr(link, :target) || safe_attr(link, :href)
|
|
1331
|
-
attrs = element_attrs(href: target, id: safe_attr(link, :id)
|
|
1290
|
+
attrs = element_attrs(href: target, id: safe_attr(link, :id))
|
|
1332
1291
|
tag("a", attrs) do
|
|
1333
1292
|
content = safe_attr(link, :content)
|
|
1334
1293
|
if content && !Array(content).join.strip.empty?
|
|
1335
1294
|
render_mixed_inline(link)
|
|
1336
1295
|
else
|
|
1337
|
-
display_text = target.to_s.
|
|
1296
|
+
display_text = target.to_s.delete_prefix("mailto:")
|
|
1338
1297
|
@output << escape_html(display_text)
|
|
1339
1298
|
end
|
|
1340
1299
|
end
|
|
@@ -1342,7 +1301,7 @@ module Metanorma
|
|
|
1342
1301
|
|
|
1343
1302
|
def render_xref(xref)
|
|
1344
1303
|
target = safe_attr(xref, :target) || safe_attr(xref, :to_attr)
|
|
1345
|
-
attrs = element_attrs(href: "##{escape_html(target)}", id: safe_attr(xref, :id)
|
|
1304
|
+
attrs = element_attrs(href: "##{escape_html(target)}", id: safe_attr(xref, :id))
|
|
1346
1305
|
tag("a", attrs) { render_mixed_inline(xref) }
|
|
1347
1306
|
end
|
|
1348
1307
|
|
|
@@ -1460,38 +1419,39 @@ module Metanorma
|
|
|
1460
1419
|
attrs.each do |k, v|
|
|
1461
1420
|
next if v.nil? || v == false || (v.is_a?(String) && v.empty?)
|
|
1462
1421
|
|
|
1463
|
-
|
|
1464
|
-
parts << %( #{k}="#{escape_html(val)}")
|
|
1422
|
+
parts << %( #{k}="#{escape_html(v.to_s)}")
|
|
1465
1423
|
end
|
|
1466
1424
|
parts.join
|
|
1467
1425
|
end
|
|
1468
1426
|
|
|
1469
|
-
|
|
1470
|
-
|
|
1427
|
+
BLOCK_TYPES = Set[
|
|
1428
|
+
Metanorma::Document::Components::Paragraphs::ParagraphBlock,
|
|
1429
|
+
Metanorma::Document::Components::Tables::TableBlock,
|
|
1430
|
+
Metanorma::Document::Components::Lists::UnorderedList,
|
|
1431
|
+
Metanorma::Document::Components::Lists::OrderedList,
|
|
1432
|
+
Metanorma::Document::Components::Lists::DefinitionList,
|
|
1433
|
+
Metanorma::Document::Components::AncillaryBlocks::FigureBlock,
|
|
1434
|
+
Metanorma::Document::Components::Blocks::NoteBlock,
|
|
1435
|
+
Metanorma::Document::Components::AncillaryBlocks::ExampleBlock,
|
|
1436
|
+
Metanorma::Document::Components::AncillaryBlocks::SourcecodeBlock,
|
|
1437
|
+
Metanorma::Document::Components::AncillaryBlocks::FormulaBlock,
|
|
1438
|
+
Metanorma::Document::Components::MultiParagraph::QuoteBlock,
|
|
1439
|
+
Metanorma::Document::Components::MultiParagraph::AdmonitionBlock,
|
|
1440
|
+
Metanorma::Document::Components::Sections::HierarchicalSection,
|
|
1441
|
+
Metanorma::Document::Components::Sections::BasicSection,
|
|
1442
|
+
Metanorma::Document::Components::Sections::ContentSection,
|
|
1443
|
+
].freeze
|
|
1444
|
+
|
|
1445
|
+
def html_class_for_span(xml_class)
|
|
1446
|
+
SPAN_ROLE_CLASSES[xml_class] || "span-#{xml_class}"
|
|
1471
1447
|
end
|
|
1472
1448
|
|
|
1473
1449
|
def block_element?(obj)
|
|
1474
|
-
obj.is_a?(
|
|
1475
|
-
obj.is_a?(Metanorma::Document::Components::Tables::TableBlock) ||
|
|
1476
|
-
obj.is_a?(Metanorma::Document::Components::Lists::UnorderedList) ||
|
|
1477
|
-
obj.is_a?(Metanorma::Document::Components::Lists::OrderedList) ||
|
|
1478
|
-
obj.is_a?(Metanorma::Document::Components::Lists::DefinitionList) ||
|
|
1479
|
-
obj.is_a?(Metanorma::Document::Components::AncillaryBlocks::FigureBlock) ||
|
|
1480
|
-
obj.is_a?(Metanorma::Document::Components::Blocks::NoteBlock) ||
|
|
1481
|
-
obj.is_a?(Metanorma::Document::Components::AncillaryBlocks::ExampleBlock) ||
|
|
1482
|
-
obj.is_a?(Metanorma::Document::Components::AncillaryBlocks::SourcecodeBlock) ||
|
|
1483
|
-
obj.is_a?(Metanorma::Document::Components::AncillaryBlocks::FormulaBlock) ||
|
|
1484
|
-
obj.is_a?(Metanorma::Document::Components::MultiParagraph::QuoteBlock) ||
|
|
1485
|
-
obj.is_a?(Metanorma::Document::Components::MultiParagraph::AdmonitionBlock) ||
|
|
1486
|
-
obj.is_a?(Metanorma::Document::Components::Sections::HierarchicalSection) ||
|
|
1487
|
-
obj.is_a?(Metanorma::Document::Components::Sections::BasicSection) ||
|
|
1488
|
-
obj.is_a?(Metanorma::Document::Components::Sections::ContentSection)
|
|
1450
|
+
BLOCK_TYPES.any? { |type| obj.is_a?(type) }
|
|
1489
1451
|
end
|
|
1490
1452
|
|
|
1491
1453
|
def safe_attr(obj, method_name)
|
|
1492
|
-
obj.public_send(method_name)
|
|
1493
|
-
rescue NoMethodError
|
|
1494
|
-
nil
|
|
1454
|
+
obj.public_send(method_name) if obj.respond_to?(method_name)
|
|
1495
1455
|
end
|
|
1496
1456
|
|
|
1497
1457
|
def collect_index_term(element)
|
|
@@ -1503,7 +1463,7 @@ module Metanorma
|
|
|
1503
1463
|
secondary: safe_attr(element, :secondary)&.to_s&.strip,
|
|
1504
1464
|
tertiary: safe_attr(element, :tertiary)&.to_s&.strip,
|
|
1505
1465
|
target_id: @current_section_id,
|
|
1506
|
-
target_text: @current_section_number
|
|
1466
|
+
target_text: @current_section_number,
|
|
1507
1467
|
)
|
|
1508
1468
|
rescue StandardError
|
|
1509
1469
|
nil
|
|
@@ -1543,14 +1503,7 @@ module Metanorma
|
|
|
1543
1503
|
end
|
|
1544
1504
|
|
|
1545
1505
|
def escape_html(text)
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
text
|
|
1549
|
-
.to_s
|
|
1550
|
-
.gsub("&", "&")
|
|
1551
|
-
.gsub("<", "<")
|
|
1552
|
-
.gsub(">", ">")
|
|
1553
|
-
.gsub('"', """)
|
|
1506
|
+
CGI.escapeHTML(text.to_s)
|
|
1554
1507
|
end
|
|
1555
1508
|
|
|
1556
1509
|
def extract_text_value(val)
|