metanorma-document 0.2.9 → 0.2.12

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 (390) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +164 -66
  3. data/CLAUDE.md +26 -0
  4. data/README.adoc +144 -0
  5. data/Rakefile +14 -2
  6. data/TODO.finalize/01-split-multi-class-files.md +8 -0
  7. data/TODO.finalize/02-remove-data-dist-iso-document-frontend.md +6 -0
  8. data/TODO.finalize/03-align-frontend-iife-and-gha-build.md +11 -0
  9. data/TODO.finalize/04-theme-per-flavor-config-driven.md +9 -0
  10. data/TODO.finalize/05-migrate-all-html-to-liquid.md +16 -0
  11. data/TODO.finalize/06-integrate-pubid-library.md +16 -0
  12. data/TODO.finalize/07-replace-relaton-models-with-relaton-bib.md +39 -0
  13. data/TODO.finalize/08-refactor-renderer-architecture.md +25 -0
  14. data/TODO.finalize/09-eliminate-code-smells.md +14 -0
  15. data/TODO.finalize/10-comprehensive-spec-coverage.md +24 -0
  16. data/TODO.finalize/11-config-driven-flavor-metadata.md +20 -0
  17. data/TODO.finalize/12-add-frozen-string-literal.md +6 -0
  18. data/TODO.finalize/13-extract-composition-from-god-class.md +96 -0
  19. data/TODO.finalize/14-config-driven-section-ordering.md +31 -0
  20. data/TODO.finalize/15-theme-directories-per-flavor.md +46 -0
  21. data/TODO.finalize/16-theme-lutaml-model-schema.md +44 -0
  22. data/data/javascripts/components/mn-footnotes.js +68 -0
  23. data/data/javascripts/components/mn-lightbox.js +18 -2
  24. data/data/javascripts/components/mn-shortcuts.js +2 -0
  25. data/data/javascripts/core/mn-navigation.js +8 -0
  26. data/data/javascripts/core/mn-theme.js +9 -9
  27. data/data/logos/oiml-logo-full-dark.svg +1 -0
  28. data/data/logos/oiml-logo-full-light.svg +1 -0
  29. data/data/logos/oiml-logo-icon-dark.svg +1 -0
  30. data/data/logos/oiml-logo-icon-light.svg +1 -0
  31. data/data/logos/oiml-logo.svg +1 -0
  32. data/data/logos/pdfa-logo.svg +31 -94
  33. data/data/stylesheets/base/_layout.css +3 -0
  34. data/data/stylesheets/base/_reset.css +3 -3
  35. data/data/stylesheets/base/_typography.css +0 -5
  36. data/data/stylesheets/components/bibliography.css +3 -3
  37. data/data/stylesheets/components/cover.css +3 -1
  38. data/data/stylesheets/components/figure.css +13 -1
  39. data/data/stylesheets/components/footnote.css +65 -5
  40. data/data/stylesheets/components/formula.css +44 -0
  41. data/data/stylesheets/components/header.css +17 -2
  42. data/data/stylesheets/components/inline.css +1 -1
  43. data/data/stylesheets/components/table.css +15 -2
  44. data/data/stylesheets/components/term.css +0 -1
  45. data/data/themes/bipm.yaml +60 -0
  46. data/data/themes/cc.yaml +43 -0
  47. data/data/themes/icc.yaml +39 -0
  48. data/data/themes/iec.yaml +44 -0
  49. data/data/themes/ieee.yaml +43 -0
  50. data/data/themes/ietf.yaml +45 -0
  51. data/data/themes/iho.yaml +46 -0
  52. data/data/themes/iso.yaml +40 -0
  53. data/data/themes/itu.yaml +45 -0
  54. data/data/themes/ogc.yaml +51 -0
  55. data/data/themes/oiml.yaml +56 -0
  56. data/data/themes/pdfa.yaml +44 -0
  57. data/data/themes/ribose.yaml +43 -0
  58. data/exe/metanorma-document +11 -0
  59. data/frontend/e2e/sample-html.test.ts +256 -0
  60. data/frontend/index.html +12 -0
  61. data/frontend/package-lock.json +4725 -0
  62. data/frontend/package.json +32 -0
  63. data/frontend/postcss.config.js +6 -0
  64. data/frontend/src/App.vue +79 -0
  65. data/frontend/src/app.ts +21 -0
  66. data/frontend/src/components/AppSidebar.vue +77 -0
  67. data/frontend/src/components/DocumentReader.vue +180 -0
  68. data/frontend/src/components/MirrorRenderer.vue +23 -0
  69. data/frontend/src/components/ReadingProgressBar.vue +29 -0
  70. data/frontend/src/components/TextRenderer.vue +131 -0
  71. data/frontend/src/components/TocItem.vue +57 -0
  72. data/frontend/src/components/TopBar.vue +49 -0
  73. data/frontend/src/components/__tests__/MirrorRenderer.test.ts +178 -0
  74. data/frontend/src/components/blocks/AdmonitionBlock.vue +74 -0
  75. data/frontend/src/components/blocks/ClauseBlock.vue +53 -0
  76. data/frontend/src/components/blocks/ExampleBlock.vue +21 -0
  77. data/frontend/src/components/blocks/FallbackBlock.vue +18 -0
  78. data/frontend/src/components/blocks/FigureBlock.vue +26 -0
  79. data/frontend/src/components/blocks/FootnotesBlock.vue +25 -0
  80. data/frontend/src/components/blocks/ListBlocks.vue +62 -0
  81. data/frontend/src/components/blocks/NoteBlock.vue +21 -0
  82. data/frontend/src/components/blocks/ParagraphBlock.vue +25 -0
  83. data/frontend/src/components/blocks/QuoteBlock.vue +25 -0
  84. data/frontend/src/components/blocks/ReviewBlock.vue +39 -0
  85. data/frontend/src/components/blocks/SourcecodeBlock.vue +52 -0
  86. data/frontend/src/components/blocks/TableBlock.vue +48 -0
  87. data/frontend/src/components/blocks/index.ts +36 -0
  88. data/frontend/src/stores/__tests__/documentStore.fixture.test.ts +272 -0
  89. data/frontend/src/stores/__tests__/documentStore.test.ts +143 -0
  90. data/frontend/src/stores/__tests__/ebookStore.test.ts +145 -0
  91. data/frontend/src/stores/__tests__/uiStore.test.ts +42 -0
  92. data/frontend/src/stores/documentStore.ts +153 -0
  93. data/frontend/src/stores/ebookStore.ts +179 -0
  94. data/frontend/src/stores/uiStore.ts +32 -0
  95. data/frontend/src/styles.css +156 -0
  96. data/frontend/src/types/__tests__/rendering-contract.test.ts +172 -0
  97. data/frontend/src/types/rendering-contract.ts +209 -0
  98. data/frontend/src/utils/__tests__/typeMetadata.test.ts +102 -0
  99. data/frontend/src/utils/typeMetadata.ts +121 -0
  100. data/frontend/tailwind.config.js +18 -0
  101. data/frontend/test/fixtures/iso-document.json +271 -0
  102. data/frontend/tmp/debug_e2e.cjs +46 -0
  103. data/frontend/tsconfig.json +25 -0
  104. data/frontend/tsconfig.node.json +11 -0
  105. data/frontend/vite.config.ts +37 -0
  106. data/frontend/vitest.e2e.config.ts +9 -0
  107. data/lib/metanorma/bipm_document/metadata/bipm_bibliographic_item.rb +0 -14
  108. data/lib/metanorma/bipm_document/metadata/depiction_element.rb +18 -0
  109. data/lib/metanorma/bipm_document/metadata.rb +1 -1
  110. data/lib/metanorma/document/cli.rb +116 -0
  111. data/lib/metanorma/document/components/ancillary_blocks/callout_annotation.rb +27 -0
  112. data/lib/metanorma/document/components/ancillary_blocks/sourcecode_block.rb +0 -65
  113. data/lib/metanorma/document/components/ancillary_blocks/sourcecode_body.rb +18 -0
  114. data/lib/metanorma/document/components/ancillary_blocks.rb +4 -0
  115. data/lib/metanorma/document/components/bib_data/bib_data.rb +7 -0
  116. data/lib/metanorma/document/components/blocks/classification_value.rb +21 -0
  117. data/lib/metanorma/document/components/blocks/permission_model.rb +28 -0
  118. data/lib/metanorma/document/components/blocks/recommendation_model.rb +28 -0
  119. data/lib/metanorma/document/components/blocks/requirement_base.rb +30 -0
  120. data/lib/metanorma/document/components/blocks/requirement_classification.rb +20 -0
  121. data/lib/metanorma/document/components/blocks/requirement_description.rb +43 -0
  122. data/lib/metanorma/document/components/blocks/requirement_inherit.rb +24 -0
  123. data/lib/metanorma/document/components/blocks/requirement_model.rb +0 -131
  124. data/lib/metanorma/document/components/blocks.rb +8 -7
  125. data/lib/metanorma/document/components/id_elements/image.rb +2 -0
  126. data/lib/metanorma/document/components/inline/asciimath_element.rb +2 -0
  127. data/lib/metanorma/document/components/inline/attribution_element.rb +2 -0
  128. data/lib/metanorma/document/components/inline/bcp14_element.rb +2 -0
  129. data/lib/metanorma/document/components/inline/biblio_tag_element.rb +2 -0
  130. data/lib/metanorma/document/components/inline/br_element.rb +2 -0
  131. data/lib/metanorma/document/components/inline/comma_element.rb +2 -0
  132. data/lib/metanorma/document/components/inline/concept_element.rb +2 -0
  133. data/lib/metanorma/document/components/inline/display_text_element.rb +2 -0
  134. data/lib/metanorma/document/components/inline/em_raw_element.rb +2 -0
  135. data/lib/metanorma/document/components/inline/enum_comma_element.rb +2 -0
  136. data/lib/metanorma/document/components/inline/eref_element.rb +2 -0
  137. data/lib/metanorma/document/components/inline/fmt_admitted_element.rb +4 -0
  138. data/lib/metanorma/document/components/inline/fmt_annotation_body_element.rb +4 -0
  139. data/lib/metanorma/document/components/inline/fmt_annotation_end_element.rb +4 -0
  140. data/lib/metanorma/document/components/inline/fmt_annotation_start_element.rb +4 -0
  141. data/lib/metanorma/document/components/inline/fmt_concept_element.rb +4 -0
  142. data/lib/metanorma/document/components/inline/fmt_definition_element.rb +4 -0
  143. data/lib/metanorma/document/components/inline/fmt_fn_body_element.rb +4 -0
  144. data/lib/metanorma/document/components/inline/fmt_fn_label_element.rb +4 -0
  145. data/lib/metanorma/document/components/inline/fmt_footnote_container_element.rb +4 -0
  146. data/lib/metanorma/document/components/inline/fmt_identifier_element.rb +4 -0
  147. data/lib/metanorma/document/components/inline/fmt_name_element.rb +4 -0
  148. data/lib/metanorma/document/components/inline/fmt_preferred_element.rb +4 -0
  149. data/lib/metanorma/document/components/inline/fmt_sourcecode_element.rb +4 -0
  150. data/lib/metanorma/document/components/inline/fmt_stem_element.rb +10 -0
  151. data/lib/metanorma/document/components/inline/fmt_termsource_element.rb +4 -0
  152. data/lib/metanorma/document/components/inline/fmt_title_element.rb +4 -0
  153. data/lib/metanorma/document/components/inline/fmt_xref_element.rb +4 -0
  154. data/lib/metanorma/document/components/inline/fmt_xref_label_element.rb +4 -0
  155. data/lib/metanorma/document/components/inline/fn_element.rb +2 -0
  156. data/lib/metanorma/document/components/inline/link_element.rb +2 -0
  157. data/lib/metanorma/document/components/inline/localized_string_element.rb +2 -0
  158. data/lib/metanorma/document/components/inline/localized_strings_element.rb +2 -0
  159. data/lib/metanorma/document/components/inline/location_element.rb +24 -0
  160. data/lib/metanorma/document/components/inline/math_element.rb +2 -0
  161. data/lib/metanorma/document/components/inline/name_with_id_element.rb +4 -0
  162. data/lib/metanorma/document/components/inline/rendered_display.rb +23 -0
  163. data/lib/metanorma/document/components/inline/rendered_math_element.rb +21 -0
  164. data/lib/metanorma/document/components/inline/semantic_content.rb +51 -0
  165. data/lib/metanorma/document/components/inline/semantic_math_element.rb +20 -0
  166. data/lib/metanorma/document/components/inline/semx_child_element.rb +2 -0
  167. data/lib/metanorma/document/components/inline/semx_element.rb +13 -1
  168. data/lib/metanorma/document/components/inline/small_cap_element.rb +2 -0
  169. data/lib/metanorma/document/components/inline/span_element.rb +10 -15
  170. data/lib/metanorma/document/components/inline/stem_inline_element.rb +7 -1
  171. data/lib/metanorma/document/components/inline/strong_raw_element.rb +2 -0
  172. data/lib/metanorma/document/components/inline/sub_element.rb +2 -0
  173. data/lib/metanorma/document/components/inline/sup_element.rb +2 -0
  174. data/lib/metanorma/document/components/inline/tab_element.rb +2 -0
  175. data/lib/metanorma/document/components/inline/title_with_annotation_element.rb +4 -0
  176. data/lib/metanorma/document/components/inline/tt_element.rb +2 -0
  177. data/lib/metanorma/document/components/inline/variant_title_element.rb +2 -0
  178. data/lib/metanorma/document/components/inline/vocabulary.rb +184 -0
  179. data/lib/metanorma/document/components/inline/xref_element.rb +10 -0
  180. data/lib/metanorma/document/components/inline.rb +12 -0
  181. data/lib/metanorma/document/components/multi_paragraph/quote_author_element.rb +20 -0
  182. data/lib/metanorma/document/components/multi_paragraph/quote_block.rb +0 -29
  183. data/lib/metanorma/document/components/multi_paragraph.rb +2 -0
  184. data/lib/metanorma/document/components/reference_elements/source_element.rb +0 -31
  185. data/lib/metanorma/document/components/reference_elements/source_modification.rb +21 -0
  186. data/lib/metanorma/document/components/reference_elements/source_origin.rb +28 -0
  187. data/lib/metanorma/document/components/reference_elements.rb +2 -2
  188. data/lib/metanorma/document/components/tables/col_element.rb +18 -0
  189. data/lib/metanorma/document/components/tables/col_group_element.rb +18 -0
  190. data/lib/metanorma/document/components/tables/table_block.rb +0 -22
  191. data/lib/metanorma/document/components/tables/table_body_section.rb +16 -0
  192. data/lib/metanorma/document/components/tables/table_foot_section.rb +16 -0
  193. data/lib/metanorma/document/components/tables/table_head_section.rb +16 -0
  194. data/lib/metanorma/document/components/tables/table_section.rb +0 -25
  195. data/lib/metanorma/document/components/tables.rb +5 -3
  196. data/lib/metanorma/document/relaton/address.rb +0 -27
  197. data/lib/metanorma/document/relaton/bib_item_locality.rb +3 -12
  198. data/lib/metanorma/document/relaton/copyright_association.rb +0 -10
  199. data/lib/metanorma/document/relaton/copyright_owner.rb +16 -0
  200. data/lib/metanorma/document/relaton/edition.rb +4 -7
  201. data/lib/metanorma/document/relaton/formatted_address.rb +29 -0
  202. data/lib/metanorma/document/relaton/logo_element.rb +18 -0
  203. data/lib/metanorma/document/relaton/organization.rb +0 -14
  204. data/lib/metanorma/document/relaton/phone.rb +3 -9
  205. data/lib/metanorma/document/relaton/place_type.rb +0 -13
  206. data/lib/metanorma/document/relaton/price_type.rb +3 -9
  207. data/lib/metanorma/document/relaton/region_element.rb +18 -0
  208. data/lib/metanorma/document/relaton.rb +6 -1
  209. data/lib/metanorma/document/version.rb +1 -1
  210. data/lib/metanorma/document.rb +2 -0
  211. data/lib/metanorma/html/asset_pipeline.rb +1 -0
  212. data/lib/metanorma/html/base_renderer.rb +261 -1008
  213. data/lib/metanorma/html/bipm_renderer.rb +15 -144
  214. data/lib/metanorma/html/cc_renderer.rb +1 -45
  215. data/lib/metanorma/html/component/base.rb +2 -7
  216. data/lib/metanorma/html/component/index_section.rb +41 -43
  217. data/lib/metanorma/html/drops/admonition_drop.rb +1 -4
  218. data/lib/metanorma/html/drops/biblio_entry_drop.rb +50 -0
  219. data/lib/metanorma/html/drops/block_element_drop.rb +7 -2
  220. data/lib/metanorma/html/drops/example_drop.rb +1 -4
  221. data/lib/metanorma/html/drops/figure_drop.rb +31 -22
  222. data/lib/metanorma/html/drops/footnote_drop.rb +1 -1
  223. data/lib/metanorma/html/drops/formula_drop.rb +45 -16
  224. data/lib/metanorma/html/drops/note_drop.rb +9 -7
  225. data/lib/metanorma/html/drops/sourcecode_drop.rb +12 -5
  226. data/lib/metanorma/html/drops.rb +2 -0
  227. data/lib/metanorma/html/generator.rb +2 -2
  228. data/lib/metanorma/html/icc_renderer.rb +0 -39
  229. data/lib/metanorma/html/iec_renderer.rb +1 -44
  230. data/lib/metanorma/html/ieee_renderer.rb +1 -45
  231. data/lib/metanorma/html/ietf_renderer.rb +1 -48
  232. data/lib/metanorma/html/iho_renderer.rb +1 -46
  233. data/lib/metanorma/html/iso_renderer.rb +290 -343
  234. data/lib/metanorma/html/itu_renderer.rb +1 -45
  235. data/lib/metanorma/html/ogc_renderer.rb +15 -76
  236. data/lib/metanorma/html/oiml_renderer.rb +18 -38
  237. data/lib/metanorma/html/pdfa_renderer.rb +0 -39
  238. data/lib/metanorma/html/renderers/block_renderer.rb +372 -0
  239. data/lib/metanorma/html/renderers/inline_renderer.rb +655 -0
  240. data/lib/metanorma/html/renderers/pubid_renderer.rb +69 -0
  241. data/lib/metanorma/html/renderers/section_renderer.rb +193 -0
  242. data/lib/metanorma/html/renderers.rb +8 -0
  243. data/lib/metanorma/html/ribose_renderer.rb +1 -45
  244. data/lib/metanorma/html/standard_renderer.rb +341 -229
  245. data/lib/metanorma/html/templates/_audio.html.liquid +1 -0
  246. data/lib/metanorma/html/templates/_biblio_entry.html.liquid +1 -0
  247. data/lib/metanorma/html/templates/_bipm_cover.html.liquid +27 -0
  248. data/lib/metanorma/html/templates/_boilerplate.html.liquid +1 -0
  249. data/lib/metanorma/html/templates/_bookmark.html.liquid +1 -0
  250. data/lib/metanorma/html/templates/_br.html.liquid +1 -0
  251. data/lib/metanorma/html/templates/_definition_list.html.liquid +6 -0
  252. data/lib/metanorma/html/templates/_element.html.liquid +1 -0
  253. data/lib/metanorma/html/templates/_fn_marker.html.liquid +1 -0
  254. data/lib/metanorma/html/templates/_footnotes.html.liquid +6 -6
  255. data/lib/metanorma/html/templates/_formula.html.liquid +1 -1
  256. data/lib/metanorma/html/templates/_header.html.liquid +1 -1
  257. data/lib/metanorma/html/templates/_heading.html.liquid +1 -0
  258. data/lib/metanorma/html/templates/_image.html.liquid +1 -0
  259. data/lib/metanorma/html/templates/_inline_span.html.liquid +1 -0
  260. data/lib/metanorma/html/templates/_iso_cover.html.liquid +1 -1
  261. data/lib/metanorma/html/templates/_link.html.liquid +1 -0
  262. data/lib/metanorma/html/templates/_list.html.liquid +3 -0
  263. data/lib/metanorma/html/templates/_list_item.html.liquid +1 -0
  264. data/lib/metanorma/html/templates/_main_content.html.liquid +1 -0
  265. data/lib/metanorma/html/templates/_math_container.html.liquid +1 -0
  266. data/lib/metanorma/html/templates/_paragraph.html.liquid +1 -0
  267. data/lib/metanorma/html/templates/_prefatory_section.html.liquid +1 -0
  268. data/lib/metanorma/html/templates/_pubid_identifier.html.liquid +1 -0
  269. data/lib/metanorma/html/templates/_quote.html.liquid +4 -0
  270. data/lib/metanorma/html/templates/_ref_date.html.liquid +1 -0
  271. data/lib/metanorma/html/templates/_ref_title.html.liquid +1 -0
  272. data/lib/metanorma/html/templates/_section.html.liquid +5 -0
  273. data/lib/metanorma/html/templates/_standard_cover.html.liquid +31 -0
  274. data/lib/metanorma/html/templates/_standard_doc_title.html.liquid +3 -0
  275. data/lib/metanorma/html/templates/_stem_span.html.liquid +1 -0
  276. data/lib/metanorma/html/templates/_table.html.liquid +9 -0
  277. data/lib/metanorma/html/templates/_term_domain.html.liquid +1 -0
  278. data/lib/metanorma/html/templates/_term_example.html.liquid +1 -0
  279. data/lib/metanorma/html/templates/_term_note.html.liquid +1 -0
  280. data/lib/metanorma/html/templates/_term_number.html.liquid +1 -0
  281. data/lib/metanorma/html/templates/_term_source.html.liquid +1 -0
  282. data/lib/metanorma/html/templates/_term_text_note.html.liquid +1 -0
  283. data/lib/metanorma/html/templates/_video.html.liquid +1 -0
  284. data/lib/metanorma/html/templates/_wrapped_preface.html.liquid +1 -0
  285. data/lib/metanorma/html/templates/document.html.liquid +4 -0
  286. data/lib/metanorma/html/theme.rb +180 -107
  287. data/lib/metanorma/html.rb +13 -0
  288. data/lib/metanorma/ietf_document/metadata/ietf_bib_data_extension_type.rb +0 -25
  289. data/lib/metanorma/ietf_document/metadata/pi_settings.rb +32 -0
  290. data/lib/metanorma/ietf_document/metadata.rb +2 -0
  291. data/lib/metanorma/iso_document/metadata/doctype_element.rb +20 -0
  292. data/lib/metanorma/iso_document/metadata/iso_bib_data_extension_type.rb +0 -48
  293. data/lib/metanorma/iso_document/metadata/iso_bibliographic_item.rb +0 -72
  294. data/lib/metanorma/iso_document/metadata/iso_document_status.rb +0 -30
  295. data/lib/metanorma/iso_document/metadata/iso_localized_title.rb +4 -1
  296. data/lib/metanorma/iso_document/metadata/language_element.rb +18 -0
  297. data/lib/metanorma/iso_document/metadata/project_number.rb +22 -0
  298. data/lib/metanorma/iso_document/metadata/script_element.rb +18 -0
  299. data/lib/metanorma/iso_document/metadata/stage_element.rb +26 -0
  300. data/lib/metanorma/iso_document/metadata/stagename_element.rb +18 -0
  301. data/lib/metanorma/iso_document/metadata/structured_identifier.rb +0 -17
  302. data/lib/metanorma/iso_document/metadata/title_collection.rb +1 -0
  303. data/lib/metanorma/iso_document/metadata.rb +9 -4
  304. data/lib/metanorma/iso_document/terms/iso_term.rb +0 -13
  305. data/lib/metanorma/iso_document/terms/term_domain_element.rb +18 -0
  306. data/lib/metanorma/iso_document/terms.rb +1 -0
  307. data/lib/metanorma/itu_document/metadata/itu_bib_data_extension_type.rb +0 -37
  308. data/lib/metanorma/itu_document/metadata/meeting_date.rb +18 -0
  309. data/lib/metanorma/itu_document/metadata/meeting_element.rb +18 -0
  310. data/lib/metanorma/itu_document/metadata/study_period.rb +18 -0
  311. data/lib/metanorma/itu_document/metadata.rb +3 -4
  312. data/lib/metanorma/mirror/default_registry.rb +170 -0
  313. data/lib/metanorma/mirror/handler_registry.rb +60 -0
  314. data/lib/metanorma/mirror/handler_result.rb +37 -0
  315. data/lib/metanorma/mirror/handlers/admonition.rb +18 -0
  316. data/lib/metanorma/mirror/handlers/example.rb +21 -0
  317. data/lib/metanorma/mirror/handlers/figure.rb +53 -0
  318. data/lib/metanorma/mirror/handlers/formula.rb +35 -0
  319. data/lib/metanorma/mirror/handlers/inline/rich_html_renderer.rb +159 -0
  320. data/lib/metanorma/mirror/handlers/inline/text_extractor.rb +116 -0
  321. data/lib/metanorma/mirror/handlers/inline.rb +225 -0
  322. data/lib/metanorma/mirror/handlers/list.rb +110 -0
  323. data/lib/metanorma/mirror/handlers/note.rb +26 -0
  324. data/lib/metanorma/mirror/handlers/paragraph.rb +19 -0
  325. data/lib/metanorma/mirror/handlers/quote.rb +16 -0
  326. data/lib/metanorma/mirror/handlers/review.rb +19 -0
  327. data/lib/metanorma/mirror/handlers/section.rb +149 -0
  328. data/lib/metanorma/mirror/handlers/sourcecode.rb +27 -0
  329. data/lib/metanorma/mirror/handlers/structural.rb +68 -0
  330. data/lib/metanorma/mirror/handlers/table.rb +81 -0
  331. data/lib/metanorma/mirror/handlers/term.rb +100 -0
  332. data/lib/metanorma/mirror/handlers.rb +60 -0
  333. data/lib/metanorma/mirror/id_strategy/positional.rb +166 -0
  334. data/lib/metanorma/mirror/id_strategy/preserve.rb +12 -0
  335. data/lib/metanorma/mirror/id_strategy.rb +34 -0
  336. data/lib/metanorma/mirror/math_util.rb +53 -0
  337. data/lib/metanorma/mirror/metadata.rb +37 -0
  338. data/lib/metanorma/mirror/metanorma_to_mirror.rb +101 -0
  339. data/lib/metanorma/mirror/model/container.rb +47 -0
  340. data/lib/metanorma/mirror/model/factory.rb +52 -0
  341. data/lib/metanorma/mirror/model/guide.rb +25 -0
  342. data/lib/metanorma/mirror/model/leaf.rb +17 -0
  343. data/lib/metanorma/mirror/model/mark.rb +53 -0
  344. data/lib/metanorma/mirror/model/node.rb +47 -0
  345. data/lib/metanorma/mirror/model/soft_break.rb +33 -0
  346. data/lib/metanorma/mirror/model/text.rb +34 -0
  347. data/lib/metanorma/mirror/model.rb +16 -0
  348. data/lib/metanorma/mirror/output/builder.rb +39 -0
  349. data/lib/metanorma/mirror/output/formats/base_format.rb +90 -0
  350. data/lib/metanorma/mirror/output/formats/inline_format.rb +81 -0
  351. data/lib/metanorma/mirror/output/formats.rb +53 -0
  352. data/lib/metanorma/mirror/output/html_renderer.rb +95 -0
  353. data/lib/metanorma/mirror/output/html_renderers/block_renderers.rb +178 -0
  354. data/lib/metanorma/mirror/output/html_renderers/inline_renderer.rb +61 -0
  355. data/lib/metanorma/mirror/output/html_renderers/list_renderers.rb +96 -0
  356. data/lib/metanorma/mirror/output/html_renderers/mark_renderers.rb +64 -0
  357. data/lib/metanorma/mirror/output/html_renderers/section_renderers.rb +129 -0
  358. data/lib/metanorma/mirror/output/html_renderers/structural_renderers.rb +80 -0
  359. data/lib/metanorma/mirror/output/html_renderers/table_renderers.rb +87 -0
  360. data/lib/metanorma/mirror/output/html_renderers.rb +76 -0
  361. data/lib/metanorma/mirror/output/pipeline.rb +92 -0
  362. data/lib/metanorma/mirror/output/pipeline_context.rb +22 -0
  363. data/lib/metanorma/mirror/output.rb +14 -0
  364. data/lib/metanorma/mirror/rewriter.rb +121 -0
  365. data/lib/metanorma/mirror/safe_attr.rb +16 -0
  366. data/lib/metanorma/mirror/serialization/json_serializer.rb +25 -0
  367. data/lib/metanorma/mirror/serialization/yaml_serializer.rb +20 -0
  368. data/lib/metanorma/mirror/serialization.rb +10 -0
  369. data/lib/metanorma/mirror/transformer.rb +22 -0
  370. data/lib/metanorma/mirror.rb +32 -0
  371. data/lib/metanorma/standard_document/annotation.rb +37 -0
  372. data/lib/metanorma/standard_document/block_attributes.rb +15 -2
  373. data/lib/metanorma/standard_document/blocks/block_source.rb +0 -23
  374. data/lib/metanorma/standard_document/blocks/source_origin_element.rb +23 -0
  375. data/lib/metanorma/standard_document/blocks.rb +1 -1
  376. data/lib/metanorma/standard_document/terms/term_expression.rb +0 -31
  377. data/lib/metanorma/standard_document/terms/term_name_element.rb +29 -0
  378. data/lib/metanorma/standard_document/terms.rb +1 -0
  379. data/script/render_both.rb +18 -0
  380. metadata +262 -13
  381. data/.github/workflows/rake.yml +0 -21
  382. data/.github/workflows/release.yml +0 -25
  383. data/.github/workflows/roundtrip-samples.yml +0 -132
  384. data/.gitignore +0 -19
  385. data/.rspec +0 -3
  386. data/.rubocop.yml +0 -22
  387. data/Gemfile +0 -28
  388. data/bin/console +0 -15
  389. data/bin/setup +0 -8
  390. data/metanorma-document.gemspec +0 -35
@@ -0,0 +1,655 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Html
5
+ module Renderers
6
+ class InlineRenderer
7
+ def initialize(coordinator)
8
+ @coordinator = coordinator
9
+ end
10
+
11
+ def walk_ordered(node, allow_filter: nil)
12
+ return false unless node.is_a?(Lutaml::Model::Serializable)
13
+ return false unless node.element_order.is_a?(Array) && !node.element_order.empty?
14
+
15
+ xml_mapping = node.class.mappings_for(:xml, node.lutaml_register)
16
+ return false unless xml_mapping
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
28
+
29
+ skip_indices = build_semx_skip_set(node)
30
+
31
+ indices = Hash.new(0)
32
+
33
+ node.element_order.each_with_index do |el, i|
34
+ next if skip_indices.include?(i)
35
+
36
+ if el.text?
37
+ text = el.text_content
38
+ yield :text, text if text && block_given?
39
+ elsif el.element?
40
+ if el.name == "tab"
41
+ yield :tab, nil if block_given?
42
+ next
43
+ end
44
+
45
+ attr_name = element_to_attr[el.name]
46
+ next unless attr_name
47
+
48
+ next if allow_filter && !allow_filter.include?(attr_name)
49
+
50
+ coll = node.public_send(attr_name)
51
+ obj = if coll.is_a?(Array)
52
+ idx = indices[attr_name]
53
+ indices[attr_name] += 1
54
+ coll[idx]
55
+ else
56
+ coll
57
+ end
58
+ yield :element, obj if obj && block_given?
59
+ end
60
+ end
61
+ true
62
+ end
63
+
64
+ def build_semx_skip_set(node)
65
+ skip_after = {
66
+ "link" => "semx",
67
+ "xref" => "semx",
68
+ "eref" => "semx",
69
+ "stem" => nil,
70
+ "concept" => "fmt-concept",
71
+ "refterm" => nil,
72
+ "renderterm" => nil,
73
+ "origin" => "semx",
74
+ }
75
+ skip = {}
76
+ node.element_order.each_with_index do |el, i|
77
+ next unless el.element?
78
+
79
+ next_tag = skip_after[el.name]
80
+ next unless next_tag
81
+
82
+ next_el = node.element_order[i + 1]
83
+ if next_tag.nil?
84
+ skip[i] = true
85
+ elsif next_el&.element? && next_el.name == next_tag
86
+ skip[i] = true
87
+ end
88
+ end
89
+ skip
90
+ end
91
+
92
+ def render_cell_content(cell)
93
+ parts = []
94
+ walked = walk_ordered(cell) do |type, obj|
95
+ case type
96
+ when :text
97
+ parts << escape_html(obj)
98
+ when :tab
99
+ parts << "  "
100
+ when :element
101
+ parts << if coordinator.block_element?(obj)
102
+ coordinator.render(obj) || ""
103
+ else
104
+ render_inline_element(obj) || ""
105
+ end
106
+ end
107
+ end
108
+ unless walked
109
+ parts << (render_mixed_content_in_order(cell) || "")
110
+ end
111
+ parts.join
112
+ end
113
+
114
+ 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
+ if node.is_a?(Lutaml::Model::Serializable) && node.element_order && !node.element_order.empty?
123
+ render_ordered_inline(node)
124
+ elsif node.is_a?(Lutaml::Model::Serializable)
125
+ parts = []
126
+ node.each_mixed_content do |child|
127
+ parts << case child
128
+ when String
129
+ escape_html(child)
130
+ else
131
+ render_inline_element(child) || ""
132
+ end
133
+ end
134
+ parts.join
135
+ else
136
+ render_inline_collections(node)
137
+ end
138
+ end
139
+
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
+ def render_ordered_inline(node)
148
+ parts = []
149
+ walked = walk_ordered(node) do |type, obj|
150
+ case type
151
+ when :text
152
+ parts << escape_html(obj)
153
+ when :tab
154
+ parts << "  "
155
+ when :element
156
+ parts << (render_inline_element(obj) || "")
157
+ end
158
+ end
159
+ unless walked
160
+ node.each_mixed_content do |child|
161
+ parts << case child
162
+ when String
163
+ escape_html(child)
164
+ else
165
+ render_inline_element(child) || ""
166
+ end
167
+ end
168
+ end
169
+ parts.join
170
+ end
171
+
172
+ def render_em(el)
173
+ render_inline_tag("em", el)
174
+ end
175
+
176
+ def render_strong(el)
177
+ render_inline_tag("strong", el)
178
+ end
179
+
180
+ def render_tt(el)
181
+ render_inline_tag("tt", el)
182
+ end
183
+
184
+ def render_sub(el)
185
+ render_inline_tag("sub", el)
186
+ end
187
+
188
+ def render_sup(el)
189
+ render_inline_tag("sup", el)
190
+ end
191
+
192
+ def render_small_caps(el)
193
+ render_inline_tag("span", el, class: "small-caps")
194
+ end
195
+
196
+ def render_underline(el)
197
+ render_inline_tag("u", el)
198
+ end
199
+
200
+ def render_strike(el)
201
+ render_inline_tag("s", el)
202
+ end
203
+
204
+ def render_br(*)
205
+ render_liquid("_br.html.liquid", {})
206
+ end
207
+
208
+ def render_tab(*)
209
+ "  "
210
+ end
211
+
212
+ def render_span(el)
213
+ xml_class = safe_attr(el, :class_attr).to_s
214
+ html_class = html_class_for_span(xml_class) unless xml_class.empty?
215
+ attrs = element_attrs(style: safe_attr(el, :style), class: html_class)
216
+ content = render_mixed_inline(el)
217
+ render_liquid("_inline_span.html.liquid", {
218
+ "attrs" => attrs,
219
+ "content" => content,
220
+ })
221
+ end
222
+
223
+ def render_fn_inline(el)
224
+ render_fn(el)
225
+ end
226
+
227
+ def render_stem(_el)
228
+ nil
229
+ end
230
+
231
+ def render_semx_inline(el)
232
+ render_semx_content(el)
233
+ end
234
+
235
+ def render_fmt_xref(el)
236
+ target = safe_attr(el, :target) || safe_attr(el, :to_attr)
237
+ if target
238
+ attrs = element_attrs(href: "##{escape_html(target)}",
239
+ class: "xref")
240
+ content = render_mixed_inline(el)
241
+ render_liquid("_link.html.liquid", {
242
+ "attrs" => attrs,
243
+ "content" => content,
244
+ })
245
+ else
246
+ render_mixed_inline(el)
247
+ end
248
+ end
249
+
250
+ def render_comma(*)
251
+ ", "
252
+ end
253
+
254
+ def render_math(el)
255
+ el.content.to_s
256
+ end
257
+
258
+ def render_asciimath(el)
259
+ text = escape_html(Array(el.text).join)
260
+ render_liquid("_stem_span.html.liquid", {
261
+ "data_attrs" => "",
262
+ "text" => text,
263
+ })
264
+ end
265
+
266
+ def render_index(el)
267
+ collect_index_term(el)
268
+ nil
269
+ end
270
+
271
+ def render_note_inline(el)
272
+ coordinator.render_note(el)
273
+ end
274
+
275
+ def render_bookmark(bookmark, **)
276
+ coordinator.render_bookmark(bookmark, **)
277
+ end
278
+
279
+ def render_image(image)
280
+ coordinator.render_image(image)
281
+ end
282
+
283
+ def render_noop_inline(*)
284
+ nil
285
+ end
286
+
287
+ def render_inline_collections(node)
288
+ parts = []
289
+ texts = node.text
290
+ if texts.is_a?(Array)
291
+ texts.each do |t|
292
+ parts << if t.is_a?(String)
293
+ escape_html(t)
294
+ else
295
+ render_inline_element(t) || ""
296
+ end
297
+ end
298
+ elsif texts.is_a?(String)
299
+ parts << escape_html(texts)
300
+ end
301
+
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)
309
+ next if values.nil?
310
+
311
+ Array(values).each { |v| parts << (render_inline_element(v) || "") }
312
+ end
313
+ parts.join
314
+ end
315
+
316
+ def render_semx_content(element, **_opts)
317
+ parts = []
318
+ display_attrs = %i[text fmt_xref fmt_link fmt_concept span strong em sup p semx
319
+ asciimath math sub_child tt_child br_child tab_child
320
+ stem_child figure_child formula_child sourcecode_child]
321
+ label_stripped = false
322
+
323
+ walked = walk_ordered(element,
324
+ allow_filter: display_attrs) do |type, obj|
325
+ case type
326
+ when :text
327
+ text = obj
328
+ unless label_stripped
329
+ text = deduplicate_semx_text(text, parts.join)
330
+ label_stripped = true
331
+ end
332
+ parts << escape_html(text)
333
+ when :element
334
+ parts << if obj.is_a?(Metanorma::Document::Components::Paragraphs::ParagraphBlock)
335
+ coordinator.render_paragraph(obj) || ""
336
+ else
337
+ render_inline_element(obj) || ""
338
+ end
339
+ end
340
+ end
341
+
342
+ unless walked
343
+ display_attrs.each do |attr|
344
+ val = safe_attr(element, attr)
345
+ next if val.nil?
346
+
347
+ if val.is_a?(Array)
348
+ val.each do |v|
349
+ parts << if v.is_a?(Metanorma::Document::Components::Paragraphs::ParagraphBlock)
350
+ coordinator.render_paragraph(v) || ""
351
+ else
352
+ render_inline_element(v) || ""
353
+ end
354
+ end
355
+ elsif val.is_a?(String)
356
+ parts << escape_html(val)
357
+ else
358
+ parts << (render_inline_element(val) || "")
359
+ end
360
+ end
361
+ end
362
+ parts.join
363
+ end
364
+
365
+ def deduplicate_semx_text(semx_text, rendered_so_far)
366
+ first_word = semx_text[/\A\s*(\S+)/, 1]
367
+ return semx_text unless first_word
368
+
369
+ tail = rendered_so_far[-200..]
370
+ return semx_text unless tail&.rstrip&.end_with?(first_word)
371
+
372
+ semx_text.sub(/\A\s*#{Regexp.escape(first_word)}\s*/, "")
373
+ end
374
+
375
+ def render_inline_tag(tag_name, element, **extra_attrs)
376
+ content = render_mixed_inline(element)
377
+ render_liquid("_element.html.liquid", {
378
+ "tag" => tag_name,
379
+ "extra_attrs" => element_attrs(**extra_attrs),
380
+ "content" => content,
381
+ })
382
+ end
383
+
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
+ def render_link(link)
444
+ target = safe_attr(link, :target) || safe_attr(link, :href)
445
+ attrs = element_attrs(href: target, id: safe_attr(link, :id))
446
+ content = safe_attr(link, :content)
447
+ if content && !Array(content).join.strip.empty?
448
+ inner = render_mixed_inline(link)
449
+ render_liquid("_link.html.liquid", {
450
+ "attrs" => attrs,
451
+ "content" => inner,
452
+ })
453
+ else
454
+ display_text = escape_html(target.to_s.delete_prefix("mailto:"))
455
+ render_liquid("_link.html.liquid", {
456
+ "attrs" => attrs,
457
+ "display_text" => display_text,
458
+ })
459
+ end
460
+ end
461
+
462
+ def render_xref(xref)
463
+ target = safe_attr(xref, :target) || safe_attr(xref, :to_attr)
464
+ attrs = element_attrs(href: "##{escape_html(target)}",
465
+ id: safe_attr(xref, :id))
466
+ content = render_mixed_inline(xref)
467
+ render_liquid("_link.html.liquid", {
468
+ "attrs" => attrs,
469
+ "content" => content,
470
+ })
471
+ end
472
+
473
+ def render_eref(eref)
474
+ citeas = safe_attr(eref, :citeas)
475
+ if citeas
476
+ escape_html(citeas)
477
+ else
478
+ render_mixed_inline(eref)
479
+ end
480
+ end
481
+
482
+ def render_fn(fn)
483
+ fn_id = safe_attr(fn, :id)
484
+ number = coordinator.footnote_collector.register(fn)
485
+
486
+ label = safe_attr(fn, :fn_label) || safe_attr(fn, :reference)
487
+ return nil unless label
488
+
489
+ popup_parts = Array(fn.p).map do |para|
490
+ render_mixed_inline(para) || ""
491
+ end
492
+ popup_html = popup_parts.join
493
+
494
+ assigns = {
495
+ "attrs" => element_attrs(id: fn_id, class: "fn-marker"),
496
+ "number" => number,
497
+ "label" => escape_html(label.to_s),
498
+ "popup_html" => popup_html.strip.empty? ? nil : popup_html,
499
+ }
500
+ render_liquid("_fn_marker.html.liquid", assigns)
501
+ end
502
+
503
+ def render_concept(concept)
504
+ render_mixed_inline(concept)
505
+ end
506
+
507
+ def render_fmt_stem(fmt_stem)
508
+ semx_items = Array(fmt_stem.semx)
509
+ return nil if semx_items.empty?
510
+
511
+ semx = semx_items.first
512
+ math_items = Array(semx.math)
513
+ ascii_items = Array(semx.asciimath)
514
+
515
+ source_formats = {}
516
+ if ascii_items.any?
517
+ ascii_text = ascii_items.map { |a| a.text.to_s.strip }.join
518
+ source_formats["asciimath"] = ascii_text unless ascii_text.empty?
519
+ end
520
+
521
+ data_attrs = ""
522
+ unless source_formats.empty?
523
+ data_attrs = " data-stem-formats='#{escape_html(source_formats.to_json)}'"
524
+ end
525
+
526
+ if math_items.any?
527
+ content = math_items.map { |m| m.content.to_s }.join
528
+ unless content.empty?
529
+ return render_liquid("_math_container.html.liquid", {
530
+ "data_attrs" => data_attrs,
531
+ "content" => content,
532
+ })
533
+ end
534
+ elsif ascii_items.any?
535
+ text = escape_html(ascii_items.map { |a| a.text.to_s.strip }.join)
536
+ return render_liquid("_stem_span.html.liquid", {
537
+ "data_attrs" => data_attrs,
538
+ "text" => text,
539
+ })
540
+ end
541
+ nil
542
+ end
543
+
544
+ def render_stem_content(stem)
545
+ return nil if stem.nil?
546
+
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
561
+
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))
576
+ return render_liquid("_stem_span.html.liquid", {
577
+ "data_attrs" => "",
578
+ "text" => text,
579
+ })
580
+ end
581
+ end
582
+
583
+ text = coordinator.extract_text_value(stem)
584
+ unless text.empty?
585
+ return render_liquid("_stem_span.html.liquid", {
586
+ "data_attrs" => "",
587
+ "text" => escape_html(text),
588
+ })
589
+ end
590
+ nil
591
+ end
592
+
593
+ def render_inline_element(element, **)
594
+ return nil if element.nil?
595
+
596
+ if element.is_a?(String)
597
+ return escape_html(element)
598
+ end
599
+
600
+ method = coordinator.lookup_dispatch(element.class, :inline_registry)
601
+ if method
602
+ coordinator.public_send(method, element)
603
+ elsif element.is_a?(Lutaml::Model::Serializable) && element.mixed?
604
+ render_mixed_inline(element)
605
+ end
606
+ end
607
+
608
+ def render_mixed_content_in_order(node)
609
+ parts = []
610
+ node.each_mixed_content do |child|
611
+ parts << case child
612
+ when String
613
+ escape_html(child)
614
+ else
615
+ if coordinator.block_element?(child)
616
+ coordinator.render(child) || ""
617
+ else
618
+ render_inline_element(child) || ""
619
+ end
620
+ end
621
+ end
622
+ parts.join
623
+ end
624
+
625
+ private
626
+
627
+ attr_reader :coordinator
628
+
629
+ def safe_attr(obj, method_name)
630
+ coordinator.safe_attr(obj, method_name)
631
+ end
632
+
633
+ def escape_html(text)
634
+ coordinator.escape_html(text)
635
+ end
636
+
637
+ def element_attrs(**attrs)
638
+ coordinator.element_attrs(**attrs)
639
+ end
640
+
641
+ def render_liquid(template_name, assigns)
642
+ coordinator.render_liquid(template_name, assigns)
643
+ end
644
+
645
+ def html_class_for_span(xml_class)
646
+ coordinator.html_class_for_span(xml_class)
647
+ end
648
+
649
+ def collect_index_term(element)
650
+ coordinator.collect_index_term(element)
651
+ end
652
+ end
653
+ end
654
+ end
655
+ end