metanorma-document 0.2.12 → 0.4.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.
Files changed (194) hide show
  1. checksums.yaml +4 -4
  2. data/CLAUDE.md +3 -2
  3. data/README.adoc +1 -1
  4. data/Rakefile +30 -5
  5. data/frontend/dist/app.css +1 -0
  6. data/frontend/dist/app.iife.js +24 -0
  7. data/frontend/package-lock.json +7 -505
  8. data/frontend/tailwind.config.js +5 -0
  9. data/lib/metanorma/csa_document/root.rb +27 -0
  10. data/lib/metanorma/csa_document.rb +9 -0
  11. data/lib/metanorma/document/cli.rb +52 -0
  12. data/lib/metanorma/document/components/ancillary_blocks/sourcecode_body.rb +14 -0
  13. data/lib/metanorma/document/components/inline/comma_element.rb +3 -0
  14. data/lib/metanorma/document/components/inline/enum_comma_element.rb +3 -0
  15. data/lib/metanorma/document/components/inline/eref_element.rb +4 -1
  16. data/lib/metanorma/document/components/inline/fmt_termsource_element.rb +4 -2
  17. data/lib/metanorma/document/components/inline/math_element.rb +13 -7
  18. data/lib/metanorma/document/components/inline/semx_element.rb +7 -8
  19. data/lib/metanorma/document/components/inline/vocabulary.rb +4 -0
  20. data/lib/metanorma/document/components/multi_paragraph/admonition_block.rb +6 -1
  21. data/lib/metanorma/document/components/paragraphs/paragraph_block.rb +3 -0
  22. data/lib/metanorma/document/components/reference_elements/callout.rb +3 -2
  23. data/lib/metanorma/document/components/tables/table_cell.rb +3 -0
  24. data/lib/metanorma/document/elements/input.rb +44 -0
  25. data/lib/metanorma/document/elements.rb +1 -0
  26. data/lib/metanorma/document/relaton/address.rb +5 -0
  27. data/lib/metanorma/document/relaton/affiliation.rb +3 -0
  28. data/lib/metanorma/document/relaton/bib_item_size.rb +8 -9
  29. data/lib/metanorma/document/relaton/bib_item_type.rb +3 -0
  30. data/lib/metanorma/document/relaton/bibliographic_date.rb +5 -0
  31. data/lib/metanorma/document/relaton/contact_method.rb +5 -0
  32. data/lib/metanorma/document/relaton/contribution_info.rb +6 -2
  33. data/lib/metanorma/document/relaton/contributor.rb +4 -0
  34. data/lib/metanorma/document/relaton/contributor_role.rb +3 -0
  35. data/lib/metanorma/document/relaton/copyright_association.rb +3 -0
  36. data/lib/metanorma/document/relaton/copyright_owner.rb +3 -0
  37. data/lib/metanorma/document/relaton/date_time.rb +3 -0
  38. data/lib/metanorma/document/relaton/document_identifier.rb +4 -0
  39. data/lib/metanorma/document/relaton/document_relation.rb +8 -0
  40. data/lib/metanorma/document/relaton/document_status.rb +4 -0
  41. data/lib/metanorma/document/relaton/formatted_address.rb +4 -0
  42. data/lib/metanorma/document/relaton/full_name.rb +14 -3
  43. data/lib/metanorma/document/relaton/keyword_type.rb +3 -0
  44. data/lib/metanorma/document/relaton/locality_stack.rb +6 -9
  45. data/lib/metanorma/document/relaton/localized_name.rb +8 -5
  46. data/lib/metanorma/document/relaton/logo_element.rb +5 -0
  47. data/lib/metanorma/document/relaton/medium_type.rb +5 -16
  48. data/lib/metanorma/document/relaton/org_identifier.rb +2 -0
  49. data/lib/metanorma/document/relaton/org_subdivision.rb +2 -0
  50. data/lib/metanorma/document/relaton/org_subdivision_identifier.rb +2 -0
  51. data/lib/metanorma/document/relaton/organization.rb +3 -0
  52. data/lib/metanorma/document/relaton/person.rb +7 -1
  53. data/lib/metanorma/document/relaton/person_identifier.rb +3 -0
  54. data/lib/metanorma/document/relaton/place_type.rb +5 -0
  55. data/lib/metanorma/document/relaton/region_element.rb +3 -9
  56. data/lib/metanorma/document/relaton/relaton_collection.rb +2 -0
  57. data/lib/metanorma/document/relaton/series_type.rb +7 -0
  58. data/lib/metanorma/document/relaton/typed_note.rb +4 -0
  59. data/lib/metanorma/document/relaton/typed_title_string.rb +4 -0
  60. data/lib/metanorma/document/relaton/typed_uri.rb +3 -8
  61. data/lib/metanorma/document/relaton/validity_type.rb +8 -10
  62. data/lib/metanorma/document/relaton/variant_full_name.rb +3 -0
  63. data/lib/metanorma/document/relaton/variant_org_name.rb +3 -0
  64. data/lib/metanorma/document/relaton/version_info.rb +5 -0
  65. data/lib/metanorma/document/relaton/vocab_id_type.rb +6 -12
  66. data/lib/metanorma/document/relaton.rb +0 -14
  67. data/lib/metanorma/document/version.rb +1 -1
  68. data/lib/metanorma/document.rb +1 -0
  69. data/lib/metanorma/html/base_renderer.rb +133 -307
  70. data/lib/metanorma/html/component/base.rb +2 -9
  71. data/lib/metanorma/html/concerns/metadata_extraction.rb +61 -0
  72. data/lib/metanorma/html/concerns/presentation_validation.rb +61 -0
  73. data/lib/metanorma/html/concerns/svg_processing.rb +32 -0
  74. data/lib/metanorma/html/concerns/text_extraction.rb +93 -0
  75. data/lib/metanorma/html/concerns/toc_registry.rb +47 -0
  76. data/lib/metanorma/html/csa_renderer.rb +9 -0
  77. data/lib/metanorma/html/drops/figure_drop.rb +33 -10
  78. data/lib/metanorma/html/drops/sourcecode_drop.rb +3 -6
  79. data/lib/metanorma/html/flavor.rb +50 -0
  80. data/lib/metanorma/html/flavor_registry.rb +49 -0
  81. data/lib/metanorma/html/generator.rb +113 -29
  82. data/lib/metanorma/html/iso_renderer.rb +0 -142
  83. data/lib/metanorma/html/renderer_delegation.rb +21 -0
  84. data/lib/metanorma/html/renderers/block_renderer.rb +10 -0
  85. data/lib/metanorma/html/renderers/element_order_traversal.rb +48 -0
  86. data/lib/metanorma/html/renderers/inline_renderer.rb +49 -124
  87. data/lib/metanorma/html/renderers/pubid_renderer.rb +4 -26
  88. data/lib/metanorma/html/renderers.rb +2 -0
  89. data/lib/metanorma/html/standard_renderer.rb +198 -36
  90. data/lib/metanorma/html.rb +4 -51
  91. data/lib/metanorma/iso_document/sections/iso_preface.rb +27 -13
  92. data/lib/metanorma/mirror/default_registry.rb +21 -0
  93. data/lib/metanorma/mirror/handlers/inline/catalog.rb +52 -0
  94. data/lib/metanorma/mirror/handlers/inline/rich_html_renderer.rb +34 -35
  95. data/lib/metanorma/mirror/handlers/inline.rb +1 -0
  96. data/lib/metanorma/mirror/handlers/sourcecode.rb +1 -1
  97. data/lib/metanorma/mirror/model/guide.rb +3 -2
  98. data/lib/metanorma/mirror/output/formats/inline_format.rb +64 -3
  99. data/lib/metanorma/mirror/output/pipeline.rb +1 -0
  100. data/lib/metanorma/mirror/output.rb +0 -2
  101. data/lib/metanorma/mirror/rewriter.rb +3 -1
  102. data/lib/metanorma/mirror/transformer.rb +91 -3
  103. data/lib/metanorma/mirror.rb +0 -1
  104. data/lib/metanorma/registers/setup.rb +10 -0
  105. data/lib/metanorma/standard_document/annotation_container.rb +2 -0
  106. data/lib/metanorma/standard_document/elements/input.rb +4 -25
  107. data/lib/metanorma/standard_document/metadata/metanorma_extension.rb +12 -2
  108. data/lib/metanorma/standard_document/metadata/presentation_metadata.rb +107 -0
  109. data/lib/metanorma/standard_document/metadata/semantic_metadata.rb +18 -0
  110. data/lib/metanorma/standard_document/metadata/unitsml/amount_of_substance.rb +19 -0
  111. data/lib/metanorma/standard_document/metadata/unitsml/base_quantity.rb +34 -0
  112. data/lib/metanorma/standard_document/metadata/unitsml/dimension.rb +39 -0
  113. data/lib/metanorma/standard_document/metadata/unitsml/dimension_set.rb +19 -0
  114. data/lib/metanorma/standard_document/metadata/unitsml/electric_current.rb +19 -0
  115. data/lib/metanorma/standard_document/metadata/unitsml/enumerated_root_unit.rb +23 -0
  116. data/lib/metanorma/standard_document/metadata/unitsml/length.rb +19 -0
  117. data/lib/metanorma/standard_document/metadata/unitsml/luminous_intensity.rb +19 -0
  118. data/lib/metanorma/standard_document/metadata/unitsml/mass.rb +19 -0
  119. data/lib/metanorma/standard_document/metadata/unitsml/namespace.rb +17 -0
  120. data/lib/metanorma/standard_document/metadata/unitsml/plane_angle.rb +19 -0
  121. data/lib/metanorma/standard_document/metadata/unitsml/prefix.rb +30 -0
  122. data/lib/metanorma/standard_document/metadata/unitsml/prefix_name.rb +21 -0
  123. data/lib/metanorma/standard_document/metadata/unitsml/prefix_set.rb +19 -0
  124. data/lib/metanorma/standard_document/metadata/unitsml/prefix_symbol.rb +21 -0
  125. data/lib/metanorma/standard_document/metadata/unitsml/quantity.rb +28 -0
  126. data/lib/metanorma/standard_document/metadata/unitsml/quantity_name.rb +21 -0
  127. data/lib/metanorma/standard_document/metadata/unitsml/quantity_set.rb +19 -0
  128. data/lib/metanorma/standard_document/metadata/unitsml/root_units.rb +19 -0
  129. data/lib/metanorma/standard_document/metadata/unitsml/thermodynamic_temperature.rb +19 -0
  130. data/lib/metanorma/standard_document/metadata/unitsml/time.rb +19 -0
  131. data/lib/metanorma/standard_document/metadata/unitsml/unit.rb +32 -0
  132. data/lib/metanorma/standard_document/metadata/unitsml/unit_name.rb +21 -0
  133. data/lib/metanorma/standard_document/metadata/unitsml/unit_set.rb +19 -0
  134. data/lib/metanorma/standard_document/metadata/unitsml/unit_symbol.rb +36 -0
  135. data/lib/metanorma/standard_document/metadata/unitsml/unit_system.rb +23 -0
  136. data/lib/metanorma/standard_document/metadata/unitsml/unitsml_root.rb +28 -0
  137. data/lib/metanorma/standard_document/metadata/unitsml.rb +39 -0
  138. data/lib/metanorma/standard_document/metadata.rb +4 -0
  139. data/lib/metanorma/standard_document/sections/misc_container.rb +8 -6
  140. data/lib/metanorma/standard_document/sections/sections.rb +7 -0
  141. data/lib/metanorma/un_document/blocks/un_admonition_block.rb +86 -0
  142. data/lib/metanorma/un_document/blocks.rb +9 -0
  143. data/lib/metanorma/un_document/root.rb +8 -0
  144. data/lib/metanorma/un_document/sections/un_abstract_section.rb +48 -0
  145. data/lib/metanorma/un_document/sections/un_preface.rb +19 -2
  146. data/lib/metanorma/un_document/sections.rb +1 -0
  147. data/lib/metanorma/un_document/un_text_element.rb +116 -0
  148. data/lib/metanorma/un_document.rb +2 -0
  149. data/script/benchmark_render.rb +35 -0
  150. data/tasks/roundtrip_samples.rake +1 -1
  151. metadata +78 -50
  152. data/.rubocop_todo.yml +0 -327
  153. data/TODO.finalize/01-split-multi-class-files.md +0 -8
  154. data/TODO.finalize/02-remove-data-dist-iso-document-frontend.md +0 -6
  155. data/TODO.finalize/03-align-frontend-iife-and-gha-build.md +0 -11
  156. data/TODO.finalize/04-theme-per-flavor-config-driven.md +0 -9
  157. data/TODO.finalize/05-migrate-all-html-to-liquid.md +0 -16
  158. data/TODO.finalize/06-integrate-pubid-library.md +0 -16
  159. data/TODO.finalize/07-replace-relaton-models-with-relaton-bib.md +0 -39
  160. data/TODO.finalize/08-refactor-renderer-architecture.md +0 -25
  161. data/TODO.finalize/09-eliminate-code-smells.md +0 -14
  162. data/TODO.finalize/10-comprehensive-spec-coverage.md +0 -24
  163. data/TODO.finalize/11-config-driven-flavor-metadata.md +0 -20
  164. data/TODO.finalize/12-add-frozen-string-literal.md +0 -6
  165. data/TODO.finalize/13-extract-composition-from-god-class.md +0 -96
  166. data/TODO.finalize/14-config-driven-section-ordering.md +0 -31
  167. data/TODO.finalize/15-theme-directories-per-flavor.md +0 -46
  168. data/TODO.finalize/16-theme-lutaml-model-schema.md +0 -44
  169. data/docs/html-renderer.adoc +0 -261
  170. data/lib/data/dist/iso_document/frontend/assets/index-mwzbzmnK.js +0 -22
  171. data/lib/data/dist/iso_document/frontend/assets/index-pGvKTNid.css +0 -1
  172. data/lib/data/dist/iso_document/frontend/assets/iso-red.svg +0 -53
  173. data/lib/data/dist/iso_document/frontend/index.html +0 -13
  174. data/lib/metanorma/document/relaton/bib_item_size_type.rb +0 -21
  175. data/lib/metanorma/document/relaton/bibliographic_date_type.rb +0 -22
  176. data/lib/metanorma/document/relaton/document_relation_type.rb +0 -31
  177. data/lib/metanorma/document/relaton/iso4217_code.rb +0 -17
  178. data/lib/metanorma/document/relaton/iso8601_date.rb +0 -17
  179. data/lib/metanorma/document/relaton/personal_identifier_type.rb +0 -21
  180. data/lib/metanorma/document/relaton/region_type.rb +0 -20
  181. data/lib/metanorma/document/relaton/series_type_type.rb +0 -21
  182. data/lib/metanorma/document/relaton/specific_locality_type.rb +0 -25
  183. data/lib/metanorma/document/relaton/title_type.rb +0 -21
  184. data/lib/metanorma/mirror/metanorma_to_mirror.rb +0 -101
  185. data/lib/metanorma/mirror/output/html_renderer.rb +0 -95
  186. data/lib/metanorma/mirror/output/html_renderers/block_renderers.rb +0 -178
  187. data/lib/metanorma/mirror/output/html_renderers/inline_renderer.rb +0 -61
  188. data/lib/metanorma/mirror/output/html_renderers/list_renderers.rb +0 -96
  189. data/lib/metanorma/mirror/output/html_renderers/mark_renderers.rb +0 -64
  190. data/lib/metanorma/mirror/output/html_renderers/section_renderers.rb +0 -129
  191. data/lib/metanorma/mirror/output/html_renderers/structural_renderers.rb +0 -80
  192. data/lib/metanorma/mirror/output/html_renderers/table_renderers.rb +0 -87
  193. data/lib/metanorma/mirror/output/html_renderers.rb +0 -76
  194. data/lib/metanorma/standard_document/annotation.rb +0 -37
@@ -330,148 +330,6 @@ module Metanorma
330
330
 
331
331
  # --- ISO Term rendering ---
332
332
 
333
- def render_term(term, **_opts)
334
- term_name = extract_term_name(term)
335
- term_def = extract_term_definition(term)
336
- data_attrs = {}
337
- if term_name && !term_name.empty?
338
- data_attrs["data-term-name"] = term_name
339
- end
340
- if term_def && !term_def.empty?
341
- data_attrs["data-term-definition"] = term_def
342
- end
343
- attrs = element_attrs(id: safe_attr(term, :id), **data_attrs)
344
- fmt_name = safe_attr(term, :fmt_name)
345
- fmt_preferred = safe_attr(term, :fmt_preferred)
346
- fmt_admitted = safe_attr(term, :fmt_admitted)
347
- fmt_deprecates = safe_attr(term, :fmt_deprecates)
348
- fmt_definition = safe_attr(term, :fmt_definition)
349
- fmt_termsource = safe_attr(term, :fmt_termsource)
350
- term_number = safe_attr(term, :term_number)
351
- term_p = safe_attr(term, :p)
352
- term_note = safe_attr(term, :termnote) || Array(safe_attr(term, :note))
353
- term_example = safe_attr(term,
354
- :termexample) || Array(safe_attr(term,
355
- :example))
356
- term_termsource = safe_attr(term, :termsource)
357
- term_admonition = safe_attr(term, :admonition)
358
- term_nested = safe_attr(term, :term)
359
-
360
- parts = []
361
- if fmt_name
362
- tn_content = render_inline_element(fmt_name)
363
- parts << render_liquid("_term_number.html.liquid",
364
- { "content" => tn_content })
365
- elsif term_number
366
- tn_text = if term_number.is_a?(String)
367
- term_number
368
- else
369
- extract_text_value(term_number)
370
- end
371
- parts << render_liquid("_term_number.html.liquid",
372
- { "content" => escape_html(tn_text) })
373
- end
374
-
375
- if fmt_preferred && !fmt_preferred.empty?
376
- fmt_preferred.each do |fp|
377
- fp.p&.each { |para| parts << (render_paragraph(para) || "") }
378
- end
379
- elsif term.preferred && !term.preferred.empty?
380
- term.preferred&.each do |designation|
381
- parts << (render_term_designation(designation, "preferred") || "")
382
- end
383
- end
384
-
385
- if fmt_admitted && !fmt_admitted.empty?
386
- fmt_admitted.each do |fa|
387
- fa.p&.each { |para| parts << (render_paragraph(para) || "") }
388
- end
389
- elsif term.admitted && !term.admitted.empty?
390
- term.admitted&.each do |designation|
391
- parts << (render_term_designation(designation, "admitted") || "")
392
- end
393
- end
394
-
395
- if fmt_deprecates
396
- fmt_deprecates.p&.each do |para|
397
- parts << (render_paragraph(para) || "")
398
- end
399
- elsif term.deprecates && !term.deprecates.empty?
400
- term.deprecates&.each do |designation|
401
- parts << (render_term_designation(designation, "deprecated") || "")
402
- end
403
- end
404
-
405
- if term.domain && !fmt_definition
406
- domain_text = safe_attr(term.domain, :text)
407
- if domain_text
408
- parts << render_liquid("_term_domain.html.liquid", {
409
- "text" => escape_html(domain_text),
410
- })
411
- end
412
- end
413
-
414
- if fmt_definition
415
- parts << (render_ordered_content(fmt_definition) || "")
416
- else
417
- term_p&.each { |para| parts << (render_paragraph(para) || "") }
418
- term.definition&.each do |defn|
419
- parts << (render_term_definition(defn) || "")
420
- end
421
- end
422
-
423
- term_note&.each { |note| parts << (render_term_note(note) || "") }
424
- term_example&.each { |ex| parts << (render_term_example(ex) || "") }
425
-
426
- if fmt_termsource && !fmt_termsource.empty?
427
- fmt_termsource.each do |fts|
428
- src_content = render_mixed_inline(fts)
429
- parts << render_liquid("_paragraph.html.liquid", {
430
- "attrs" => " class=\"term-source\"",
431
- "content" => src_content,
432
- })
433
- end
434
- else
435
- term.source&.each { |src| parts << (render_term_source(src) || "") }
436
- term_termsource&.each do |src|
437
- parts << (render_term_source_element(src) || "")
438
- end
439
- end
440
-
441
- term_admonition&.each { |adm| parts << (render_admonition(adm) || "") }
442
- term_nested&.each { |sub| parts << (render_term(sub) || "") }
443
-
444
- render_liquid("_element.html.liquid", "tag" => "div",
445
- "extra_attrs" => attrs, "content" => parts.join)
446
- end
447
-
448
- def extract_term_name(term)
449
- fmt_pref = safe_attr(term, :fmt_preferred)
450
- if fmt_pref && !fmt_pref.empty?
451
- fp = fmt_pref.first
452
- if fp.p && !fp.p.empty?
453
- return extract_plain_text(fp.p.first)
454
- end
455
- end
456
- if term.preferred && !term.preferred.empty?
457
- return extract_designation_name(term.preferred.first).to_s
458
- end
459
-
460
- safe_attr(term, :id).to_s.delete_prefix("term-")
461
- end
462
-
463
- def extract_term_definition(term)
464
- fmt_def = safe_attr(term, :fmt_definition)
465
- return extract_plain_text(fmt_def) if fmt_def
466
-
467
- term_p = safe_attr(term, :p)
468
- if term_p && !term_p.empty?
469
- text = term_p.map { |para| extract_plain_text(para) }.join(" ")
470
- return text.strip unless text.strip.empty?
471
- end
472
- nil
473
- end
474
-
475
333
  def render_term_designation(designation, type)
476
334
  css_class = type == "deprecated" ? "term-deprecated" : "term-name"
477
335
  name = extract_designation_name(designation)
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Html
5
+ # Shared forwarding methods for narrowing wrappers around a
6
+ # renderer. Both RendererContext (used by Drop factories) and
7
+ # Component::Base (used by Component renderers) include this
8
+ # module so the shared forwarding surface is declared in one
9
+ # place. Adding a new shared method is one edit here, not two.
10
+ #
11
+ # Per-class-specific forwarders stay declared in each wrapper.
12
+ module RendererDelegation
13
+ def safe_attr(...) = @renderer.safe_attr(...)
14
+ def escape_html(...) = @renderer.escape_html(...)
15
+ def extract_block_label(...)= @renderer.extract_block_label(...)
16
+ def extract_plain_text(...) = @renderer.extract_plain_text(...)
17
+ def render_mixed_inline(...)= @renderer.render_mixed_inline(...)
18
+ def render_liquid(...) = @renderer.render_liquid(...)
19
+ end
20
+ end
21
+ end
@@ -271,6 +271,16 @@ module Metanorma
271
271
  render_liquid("_example.html.liquid", { "block" => drop })
272
272
  end
273
273
 
274
+ def render_form(form, **_opts)
275
+ attrs = element_attrs(id: safe_attr(form, :id), class: "form")
276
+ content = coordinator.render_ordered_content(form)
277
+ render_liquid("_element.html.liquid", {
278
+ "tag" => "div",
279
+ "extra_attrs" => attrs,
280
+ "content" => content,
281
+ })
282
+ end
283
+
274
284
  def render_sourcecode(sc, **_opts)
275
285
  drop = Drops::SourcecodeDrop.from_model(sc,
276
286
  renderer: coordinator.renderer_context)
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Html
5
+ module Renderers
6
+ # Builds the reverse lookup `{ xml_element_name => attribute_name }`
7
+ # from a node's xml mapping. Shared between walkers that iterate
8
+ # element_order: InlineRenderer#walk_ordered (renders in document
9
+ # order) and BaseRenderer#extract_plain_text (extracts text).
10
+ #
11
+ # Both walkers previously reimplemented this hash construction
12
+ # inline; the construction is the genuinely-shared traversal
13
+ # concern. Per-element handling (recursion, span emission, tab/br
14
+ # spacing) differs and stays in each walker.
15
+ module ElementOrderTraversal
16
+ module_function
17
+
18
+ # The map depends only on the model class's xml mapping, which is
19
+ # immutable after class definition — cache one map per mapping
20
+ # object instead of rebuilding it for every rendered node.
21
+ @cache = {}.compare_by_identity
22
+
23
+ def element_to_attr_map(xml_mapping)
24
+ @cache[xml_mapping] ||= build_map(xml_mapping)
25
+ end
26
+
27
+ # Test/benchmark hook: drop all memoized maps.
28
+ def reset_cache!
29
+ @cache.clear
30
+ end
31
+
32
+ # Returns `{ xml_element_name => attr_name }` including both
33
+ # symbol and string keys for each mapped element, so callers
34
+ # can look up by either el.name form.
35
+ def build_map(xml_mapping)
36
+ {}.tap do |map|
37
+ xml_mapping.mapping_elements_hash.each_value do |rule_or_array|
38
+ Array(rule_or_array).each do |rule|
39
+ map[rule.name] = rule.to
40
+ map[rule.name.to_s] = rule.to if rule.name.is_a?(Symbol)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -15,16 +15,8 @@ module Metanorma
15
15
  xml_mapping = node.class.mappings_for(:xml, node.lutaml_register)
16
16
  return false unless xml_mapping
17
17
 
18
- element_to_attr = {}
19
- xml_mapping.mapping_elements_hash.each_value do |rule_or_array|
20
- Array(rule_or_array).each do |rule|
21
- element_to_attr[rule.name] = rule.to
22
- if rule.name.is_a?(Symbol)
23
- element_to_attr[rule.name.to_s] =
24
- rule.to
25
- end
26
- end
27
- end
18
+ element_to_attr =
19
+ Renderers::ElementOrderTraversal.element_to_attr_map(xml_mapping)
28
20
 
29
21
  skip_indices = build_semx_skip_set(node)
30
22
 
@@ -112,13 +104,6 @@ module Metanorma
112
104
  end
113
105
 
114
106
  def render_mixed_inline(node)
115
- if raw_content_node?(node)
116
- raw = node.content
117
- if raw.is_a?(String) && !raw.strip.empty?
118
- return render_raw_content(raw)
119
- end
120
- end
121
-
122
107
  if node.is_a?(Lutaml::Model::Serializable) && node.element_order && !node.element_order.empty?
123
108
  render_ordered_inline(node)
124
109
  elsif node.is_a?(Lutaml::Model::Serializable)
@@ -137,13 +122,6 @@ module Metanorma
137
122
  end
138
123
  end
139
124
 
140
- def raw_content_node?(node)
141
- node.is_a?(Lutaml::Model::Serializable) &&
142
- node.content.is_a?(String)
143
- rescue NoMethodError
144
- false
145
- end
146
-
147
125
  def render_ordered_inline(node)
148
126
  parts = []
149
127
  walked = walk_ordered(node) do |type, obj|
@@ -251,8 +229,19 @@ module Metanorma
251
229
  ", "
252
230
  end
253
231
 
232
+ # Form inputs render as disabled HTML inputs — this is a document
233
+ # rendering, not an interactive form.
234
+ def render_input(el)
235
+ attrs = element_attrs(
236
+ type: safe_attr(el, :type) || "text",
237
+ disabled: "disabled",
238
+ checked: safe_attr(el, :checked) ? "checked" : nil,
239
+ )
240
+ "<input#{attrs}>"
241
+ end
242
+
254
243
  def render_math(el)
255
- el.content.to_s
244
+ el.to_xml
256
245
  end
257
246
 
258
247
  def render_asciimath(el)
@@ -299,13 +288,14 @@ module Metanorma
299
288
  parts << escape_html(texts)
300
289
  end
301
290
 
302
- inline_attrs = %i[em strong smallcap sub sup tt underline strike
303
- xref eref link span stem concept fn br tab keyword
304
- fmt_annotation_start fmt_annotation_end
305
- fmt_stem fmt_fn_label fmt_concept
306
- bookmark image semx fmt_xref_label]
307
- inline_attrs.each do |attr|
308
- values = safe_attr(node, attr)
291
+ # Derive the element-mapped attribute list from the node's own
292
+ # xml_mapping rather than maintaining a parallel hardcoded list.
293
+ # The model is the single source of truth; adding a new inline
294
+ # element type via map_element on the model class is enough.
295
+ node.class.mappings[:xml].elements.each do |rule|
296
+ next if rule.to == :text
297
+
298
+ values = safe_attr(node, rule.to)
309
299
  next if values.nil?
310
300
 
311
301
  Array(values).each { |v| parts << (render_inline_element(v) || "") }
@@ -381,65 +371,6 @@ module Metanorma
381
371
  })
382
372
  end
383
373
 
384
- def render_raw_content(raw_xml)
385
- doc = Nokogiri::XML.fragment(raw_xml)
386
- doc.css("fmt-link").each do |el|
387
- target = el["target"] || el["href"]
388
- if target
389
- display_text = target.delete_prefix("mailto:")
390
- a = doc.document.create_element("a", display_text,
391
- "href" => target)
392
- el.replace(a)
393
- else
394
- el.replace(el.children)
395
- end
396
- end
397
- doc.traverse do |node|
398
- next unless node.element?
399
- next unless %w[xref eref stem link].include?(node.name)
400
-
401
- next_sib = node.next_sibling
402
- while next_sib.is_a?(Nokogiri::XML::Text) && next_sib.text.strip.empty?
403
- next_sib = next_sib.next_sibling
404
- end
405
- next unless next_sib&.element? && next_sib.name == "semx"
406
-
407
- deduplicate_semx_label(node, next_sib)
408
- node.remove
409
- end
410
- %w[semx fmt-xref].each do |tag|
411
- doc.css(tag).each { |el| el.replace(el.children) }
412
- end
413
- doc.css("[class]").each do |el|
414
- el["class"] = el["class"].split(/\s+/).map do |c|
415
- html_class_for_span(c)
416
- end.join(" ")
417
- end
418
- doc.inner_html
419
- end
420
-
421
- def deduplicate_semx_label(source_node, semx_node)
422
- first_text = semx_node.children.find do |c|
423
- c.text? && !c.text.strip.empty?
424
- end
425
- return unless first_text
426
-
427
- semx_prefix = first_text.text[/\A(\s*\S+)/, 1]
428
- return unless semx_prefix && !semx_prefix.strip.empty?
429
-
430
- prev = source_node.previous_sibling
431
- return unless prev.is_a?(Nokogiri::XML::Text)
432
-
433
- label = semx_prefix.strip
434
- prev_text = prev.text.rstrip
435
- return unless prev_text.end_with?(label)
436
-
437
- prev.content = prev_text.sub(/#{Regexp.escape(label)}\s*\z/, "")
438
- first_text.content = first_text.text.sub(
439
- /\A\s*#{Regexp.escape(label)}\s*/, ""
440
- )
441
- end
442
-
443
374
  def render_link(link)
444
375
  target = safe_attr(link, :target) || safe_attr(link, :href)
445
376
  attrs = element_attrs(href: target, id: safe_attr(link, :id))
@@ -524,7 +455,7 @@ module Metanorma
524
455
  end
525
456
 
526
457
  if math_items.any?
527
- content = math_items.map { |m| m.content.to_s }.join
458
+ content = math_items.map(&:to_xml).join
528
459
  unless content.empty?
529
460
  return render_liquid("_math_container.html.liquid", {
530
461
  "data_attrs" => data_attrs,
@@ -541,50 +472,44 @@ module Metanorma
541
472
  nil
542
473
  end
543
474
 
475
+ # Stem content formats in priority order. Each entry binds an
476
+ # attribute reader on the stem element to the value-render path
477
+ # (raw XML when serializable, escaped text otherwise). Adding a
478
+ # new format = one entry here.
479
+ STEM_FORMATS = [
480
+ { attr: :math, raw_xml: true },
481
+ { attr: :asciimath },
482
+ { attr: :latexmath },
483
+ ].freeze
484
+
544
485
  def render_stem_content(stem)
545
486
  return nil if stem.nil?
546
487
 
547
- if stem.is_a?(Metanorma::Document::Components::Inline::StemInlineElement)
548
- return nil
549
- end
550
-
551
- if stem.is_a?(Metanorma::Document::Components::Inline::FmtStemElement)
552
- return nil
553
- end
554
-
555
- if stem.is_a?(Metanorma::Document::Components::TextElements::StemElement)
556
- if stem.math
557
- math_val = stem.math
558
- if math_val.is_a?(Lutaml::Model::Serializable)
559
- return math_val.to_xml
560
- end
488
+ return nil if stem.is_a?(Metanorma::Document::Components::Inline::StemInlineElement) ||
489
+ stem.is_a?(Metanorma::Document::Components::Inline::FmtStemElement)
561
490
 
562
- text = escape_html(coordinator.extract_text_value(math_val))
563
- return render_liquid("_stem_span.html.liquid", {
564
- "data_attrs" => "",
565
- "text" => text,
566
- })
567
- elsif stem.asciimath
568
- text = escape_html(coordinator.extract_text_value(stem.asciimath))
569
- return render_liquid("_stem_span.html.liquid", {
570
- "data_attrs" => "",
571
- "text" => text,
572
- })
573
- end
574
- if stem.latexmath
575
- text = escape_html(coordinator.extract_text_value(stem.latexmath))
491
+ unless stem.is_a?(Metanorma::Document::Components::TextElements::StemElement)
492
+ text = coordinator.extract_text_value(stem)
493
+ unless text.empty?
576
494
  return render_liquid("_stem_span.html.liquid", {
577
495
  "data_attrs" => "",
578
- "text" => text,
496
+ "text" => escape_html(text),
579
497
  })
580
498
  end
499
+ return nil
581
500
  end
582
501
 
583
- text = coordinator.extract_text_value(stem)
584
- unless text.empty?
502
+ STEM_FORMATS.each do |format|
503
+ value = stem.public_send(format[:attr])
504
+ next unless value
505
+
506
+ if format[:raw_xml] && value.is_a?(Lutaml::Model::Serializable)
507
+ return value.to_xml
508
+ end
509
+
585
510
  return render_liquid("_stem_span.html.liquid", {
586
511
  "data_attrs" => "",
587
- "text" => escape_html(text),
512
+ "text" => escape_html(coordinator.extract_text_value(value)),
588
513
  })
589
514
  end
590
515
  nil
@@ -4,15 +4,6 @@ module Metanorma
4
4
  module Html
5
5
  module Renderers
6
6
  class PubidRenderer
7
- FLAVOR_PUBID_MAP = {
8
- "IsoDocument" => :"Pubid::Iso",
9
- "IecDocument" => :"Pubid::Iec",
10
- "IeeeDocument" => :"Pubid::Ieee",
11
- "IhoDocument" => :"Pubid::Iho",
12
- "ItuDocument" => :"Pubid::Ithu",
13
- "OimlDocument" => :"Pubid::Oiml",
14
- }.freeze
15
-
16
7
  def initialize(coordinator)
17
8
  @coordinator = coordinator
18
9
  end
@@ -44,24 +35,11 @@ module Metanorma
44
35
  @coordinator.escape_html(text)
45
36
  end
46
37
 
38
+ # Flavor identity comes from the shared FlavorRegistry via the
39
+ # coordinator — no local duplicate of the flavor-to-pubid-module
40
+ # map.
47
41
  def resolve_pubid_module
48
- flavor_name = @coordinator.flavor_name
49
- return nil unless flavor_name
50
-
51
- @coordinator.class.ancestors.each do |ancestor|
52
- next unless ancestor.is_a?(Class)
53
-
54
- ns = ancestor.name&.split("::")&.detect do |n|
55
- FLAVOR_PUBID_MAP.key?(n)
56
- end
57
- next unless ns
58
-
59
- mod = FLAVOR_PUBID_MAP[ns]
60
- return Object.const_get(mod.to_s)
61
- end
62
- nil
63
- rescue NameError
64
- nil
42
+ @coordinator.pubid_module
65
43
  end
66
44
  end
67
45
  end
@@ -3,6 +3,8 @@
3
3
  module Metanorma
4
4
  module Html
5
5
  module Renderers
6
+ autoload :ElementOrderTraversal,
7
+ "metanorma/html/renderers/element_order_traversal"
6
8
  end
7
9
  end
8
10
  end