metanorma-document 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/BUGS.sts/08-list-items-duplicate-bullets.md +45 -0
- data/CLAUDE.md +3 -2
- data/Rakefile +30 -5
- data/data/stylesheets/components/header.css +3 -5
- data/data/stylesheets/components/lists.css +14 -0
- data/frontend/dist/app.css +1 -0
- data/frontend/dist/app.iife.js +24 -0
- data/frontend/package-lock.json +7 -505
- data/frontend/tailwind.config.js +5 -0
- data/lib/metanorma/{oiml_document → csa_document}/root.rb +2 -2
- data/lib/metanorma/csa_document.rb +9 -0
- data/lib/metanorma/document/cli.rb +52 -0
- data/lib/metanorma/document/components/ancillary_blocks/sourcecode_body.rb +14 -0
- data/lib/metanorma/document/components/inline/comma_element.rb +3 -0
- data/lib/metanorma/document/components/inline/enum_comma_element.rb +3 -0
- data/lib/metanorma/document/components/inline/eref_element.rb +4 -1
- data/lib/metanorma/document/components/inline/fmt_termsource_element.rb +4 -2
- data/lib/metanorma/document/components/inline/math_element.rb +13 -7
- data/lib/metanorma/document/components/inline/vocabulary.rb +4 -0
- data/lib/metanorma/document/components/multi_paragraph/admonition_block.rb +6 -1
- data/lib/metanorma/document/components/paragraphs/paragraph_block.rb +3 -0
- data/lib/metanorma/document/components/reference_elements/callout.rb +3 -2
- data/lib/metanorma/document/components/tables/table_cell.rb +3 -0
- data/lib/metanorma/document/elements/input.rb +44 -0
- data/lib/metanorma/document/elements.rb +1 -0
- data/lib/metanorma/document/relaton/address.rb +5 -0
- data/lib/metanorma/document/relaton/affiliation.rb +3 -0
- data/lib/metanorma/document/relaton/bib_item_size.rb +8 -9
- data/lib/metanorma/document/relaton/bib_item_type.rb +3 -0
- data/lib/metanorma/document/relaton/bibliographic_date.rb +5 -0
- data/lib/metanorma/document/relaton/contact_method.rb +5 -0
- data/lib/metanorma/document/relaton/contribution_info.rb +6 -2
- data/lib/metanorma/document/relaton/contributor.rb +4 -0
- data/lib/metanorma/document/relaton/contributor_role.rb +3 -0
- data/lib/metanorma/document/relaton/copyright_association.rb +3 -0
- data/lib/metanorma/document/relaton/copyright_owner.rb +3 -0
- data/lib/metanorma/document/relaton/date_time.rb +3 -0
- data/lib/metanorma/document/relaton/document_identifier.rb +4 -0
- data/lib/metanorma/document/relaton/document_relation.rb +8 -0
- data/lib/metanorma/document/relaton/document_status.rb +4 -0
- data/lib/metanorma/document/relaton/formatted_address.rb +4 -0
- data/lib/metanorma/document/relaton/full_name.rb +14 -3
- data/lib/metanorma/document/relaton/keyword_type.rb +3 -0
- data/lib/metanorma/document/relaton/locality_stack.rb +6 -9
- data/lib/metanorma/document/relaton/localized_name.rb +8 -5
- data/lib/metanorma/document/relaton/logo_element.rb +5 -0
- data/lib/metanorma/document/relaton/medium_type.rb +5 -16
- data/lib/metanorma/document/relaton/org_identifier.rb +2 -0
- data/lib/metanorma/document/relaton/org_subdivision.rb +2 -0
- data/lib/metanorma/document/relaton/org_subdivision_identifier.rb +2 -0
- data/lib/metanorma/document/relaton/organization.rb +3 -0
- data/lib/metanorma/document/relaton/person.rb +7 -1
- data/lib/metanorma/document/relaton/person_identifier.rb +3 -0
- data/lib/metanorma/document/relaton/place_type.rb +5 -0
- data/lib/metanorma/document/relaton/region_element.rb +3 -9
- data/lib/metanorma/document/relaton/relaton_collection.rb +2 -0
- data/lib/metanorma/document/relaton/series_type.rb +7 -0
- data/lib/metanorma/document/relaton/typed_note.rb +4 -0
- data/lib/metanorma/document/relaton/typed_title_string.rb +4 -0
- data/lib/metanorma/document/relaton/typed_uri.rb +3 -8
- data/lib/metanorma/document/relaton/validity_type.rb +8 -10
- data/lib/metanorma/document/relaton/variant_full_name.rb +3 -0
- data/lib/metanorma/document/relaton/variant_org_name.rb +3 -0
- data/lib/metanorma/document/relaton/version_info.rb +5 -0
- data/lib/metanorma/document/relaton/vocab_id_type.rb +6 -12
- data/lib/metanorma/document/relaton.rb +0 -14
- data/lib/metanorma/document/version.rb +1 -1
- data/lib/metanorma/document.rb +2 -1
- data/lib/metanorma/html/asset_pipeline.rb +1 -0
- data/lib/metanorma/html/base_renderer.rb +106 -236
- data/lib/metanorma/html/concerns/metadata_extraction.rb +61 -0
- data/lib/metanorma/html/concerns/presentation_validation.rb +61 -0
- data/lib/metanorma/html/concerns/svg_processing.rb +32 -0
- data/lib/metanorma/html/concerns/text_extraction.rb +93 -0
- data/lib/metanorma/html/concerns/toc_registry.rb +47 -0
- data/lib/metanorma/html/csa_renderer.rb +9 -0
- data/lib/metanorma/html/drops/figure_drop.rb +33 -10
- data/lib/metanorma/html/drops/sourcecode_drop.rb +3 -6
- data/lib/metanorma/html/flavor.rb +6 -1
- data/lib/metanorma/html/generator.rb +8 -8
- data/lib/metanorma/html/iso_renderer.rb +0 -142
- data/lib/metanorma/html/renderers/block_renderer.rb +41 -5
- data/lib/metanorma/html/renderers/element_order_traversal.rb +15 -1
- data/lib/metanorma/html/renderers/inline_renderer.rb +16 -76
- data/lib/metanorma/html/standard_renderer.rb +195 -35
- data/lib/metanorma/html/templates/_list_item.html.liquid +1 -1
- data/lib/metanorma/html/theme.rb +38 -11
- data/lib/metanorma/html.rb +1 -52
- data/lib/metanorma/iso_document/sections/iso_preface.rb +27 -13
- data/lib/metanorma/mirror/default_registry.rb +21 -0
- data/lib/metanorma/mirror/handlers/inline/catalog.rb +7 -12
- data/lib/metanorma/mirror/handlers/inline/rich_html_renderer.rb +2 -3
- data/lib/metanorma/mirror/handlers/sourcecode.rb +1 -1
- data/lib/metanorma/mirror/model/guide.rb +3 -2
- data/lib/metanorma/mirror/output/formats/inline_format.rb +64 -3
- data/lib/metanorma/mirror/output/pipeline.rb +1 -0
- data/lib/metanorma/mirror/output.rb +0 -2
- data/lib/metanorma/mirror/rewriter.rb +3 -1
- data/lib/metanorma/registers/setup.rb +6 -2
- data/lib/metanorma/standard_document/annotation_container.rb +2 -0
- data/lib/metanorma/standard_document/elements/input.rb +4 -25
- data/lib/metanorma/standard_document/metadata/metanorma_extension.rb +12 -2
- data/lib/metanorma/standard_document/metadata/presentation_metadata.rb +107 -0
- data/lib/metanorma/standard_document/metadata/semantic_metadata.rb +18 -0
- data/lib/metanorma/standard_document/metadata/unitsml/amount_of_substance.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/base_quantity.rb +34 -0
- data/lib/metanorma/standard_document/metadata/unitsml/dimension.rb +39 -0
- data/lib/metanorma/standard_document/metadata/unitsml/dimension_set.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/electric_current.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/enumerated_root_unit.rb +23 -0
- data/lib/metanorma/standard_document/metadata/unitsml/length.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/luminous_intensity.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/mass.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/namespace.rb +17 -0
- data/lib/metanorma/standard_document/metadata/unitsml/plane_angle.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/prefix.rb +30 -0
- data/lib/metanorma/standard_document/metadata/unitsml/prefix_name.rb +21 -0
- data/lib/metanorma/standard_document/metadata/unitsml/prefix_set.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/prefix_symbol.rb +21 -0
- data/lib/metanorma/standard_document/metadata/unitsml/quantity.rb +28 -0
- data/lib/metanorma/standard_document/metadata/unitsml/quantity_name.rb +21 -0
- data/lib/metanorma/standard_document/metadata/unitsml/quantity_set.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/root_units.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/thermodynamic_temperature.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/time.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/unit.rb +32 -0
- data/lib/metanorma/standard_document/metadata/unitsml/unit_name.rb +21 -0
- data/lib/metanorma/standard_document/metadata/unitsml/unit_set.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/unit_symbol.rb +36 -0
- data/lib/metanorma/standard_document/metadata/unitsml/unit_system.rb +23 -0
- data/lib/metanorma/standard_document/metadata/unitsml/unitsml_root.rb +28 -0
- data/lib/metanorma/standard_document/metadata/unitsml.rb +39 -0
- data/lib/metanorma/standard_document/metadata.rb +4 -0
- data/lib/metanorma/standard_document/sections/misc_container.rb +8 -6
- data/lib/metanorma/standard_document/sections/sections.rb +7 -0
- data/lib/metanorma/un_document/blocks/un_admonition_block.rb +86 -0
- data/lib/metanorma/un_document/blocks.rb +9 -0
- data/lib/metanorma/un_document/root.rb +8 -0
- data/lib/metanorma/un_document/sections/un_abstract_section.rb +48 -0
- data/lib/metanorma/un_document/sections/un_preface.rb +19 -2
- data/lib/metanorma/un_document/sections.rb +1 -0
- data/lib/metanorma/un_document/un_text_element.rb +116 -0
- data/lib/metanorma/un_document.rb +2 -0
- data/script/benchmark_render.rb +35 -0
- data/tasks/roundtrip_samples.rake +2 -2
- metadata +65 -54
- data/.rubocop_todo.yml +0 -220
- data/TODO.finalize/01-split-multi-class-files.md +0 -8
- data/TODO.finalize/02-remove-data-dist-iso-document-frontend.md +0 -6
- data/TODO.finalize/03-align-frontend-iife-and-gha-build.md +0 -11
- data/TODO.finalize/04-theme-per-flavor-config-driven.md +0 -9
- data/TODO.finalize/05-migrate-all-html-to-liquid.md +0 -16
- data/TODO.finalize/06-integrate-pubid-library.md +0 -16
- data/TODO.finalize/07-replace-relaton-models-with-relaton-bib.md +0 -39
- data/TODO.finalize/08-refactor-renderer-architecture.md +0 -25
- data/TODO.finalize/09-eliminate-code-smells.md +0 -14
- data/TODO.finalize/10-comprehensive-spec-coverage.md +0 -24
- data/TODO.finalize/11-config-driven-flavor-metadata.md +0 -20
- data/TODO.finalize/12-add-frozen-string-literal.md +0 -6
- data/TODO.finalize/13-extract-composition-from-god-class.md +0 -96
- data/TODO.finalize/14-config-driven-section-ordering.md +0 -31
- data/TODO.finalize/15-theme-directories-per-flavor.md +0 -46
- data/TODO.finalize/16-theme-lutaml-model-schema.md +0 -44
- data/data/logos/oiml-logo-full-dark.svg +0 -1
- data/data/logos/oiml-logo-full-light.svg +0 -1
- data/data/logos/oiml-logo-icon-dark.svg +0 -1
- data/data/logos/oiml-logo-icon-light.svg +0 -1
- data/data/logos/oiml-logo.svg +0 -1
- data/data/themes/oiml.yaml +0 -56
- data/docs/html-renderer.adoc +0 -261
- data/lib/data/dist/iso_document/frontend/assets/index-mwzbzmnK.js +0 -22
- data/lib/data/dist/iso_document/frontend/assets/index-pGvKTNid.css +0 -1
- data/lib/data/dist/iso_document/frontend/assets/iso-red.svg +0 -53
- data/lib/data/dist/iso_document/frontend/index.html +0 -13
- data/lib/metanorma/document/relaton/bib_item_size_type.rb +0 -21
- data/lib/metanorma/document/relaton/bibliographic_date_type.rb +0 -22
- data/lib/metanorma/document/relaton/document_relation_type.rb +0 -31
- data/lib/metanorma/document/relaton/iso4217_code.rb +0 -17
- data/lib/metanorma/document/relaton/iso8601_date.rb +0 -17
- data/lib/metanorma/document/relaton/personal_identifier_type.rb +0 -21
- data/lib/metanorma/document/relaton/region_type.rb +0 -20
- data/lib/metanorma/document/relaton/series_type_type.rb +0 -21
- data/lib/metanorma/document/relaton/specific_locality_type.rb +0 -25
- data/lib/metanorma/document/relaton/title_type.rb +0 -21
- data/lib/metanorma/html/oiml_renderer.rb +0 -33
- data/lib/metanorma/mirror/output/html_renderer.rb +0 -95
- data/lib/metanorma/mirror/output/html_renderers/block_renderers.rb +0 -178
- data/lib/metanorma/mirror/output/html_renderers/inline_renderer.rb +0 -61
- data/lib/metanorma/mirror/output/html_renderers/list_renderers.rb +0 -96
- data/lib/metanorma/mirror/output/html_renderers/mark_renderers.rb +0 -41
- data/lib/metanorma/mirror/output/html_renderers/section_renderers.rb +0 -129
- data/lib/metanorma/mirror/output/html_renderers/structural_renderers.rb +0 -80
- data/lib/metanorma/mirror/output/html_renderers/table_renderers.rb +0 -87
- data/lib/metanorma/mirror/output/html_renderers.rb +0 -76
- data/lib/metanorma/oiml_document.rb +0 -9
- data/lib/metanorma/standard_document/annotation.rb +0 -37
|
@@ -104,13 +104,6 @@ module Metanorma
|
|
|
104
104
|
end
|
|
105
105
|
|
|
106
106
|
def render_mixed_inline(node)
|
|
107
|
-
if raw_content_node?(node)
|
|
108
|
-
raw = node.content
|
|
109
|
-
if raw.is_a?(String) && !raw.strip.empty?
|
|
110
|
-
return render_raw_content(raw)
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
107
|
if node.is_a?(Lutaml::Model::Serializable) && node.element_order && !node.element_order.empty?
|
|
115
108
|
render_ordered_inline(node)
|
|
116
109
|
elsif node.is_a?(Lutaml::Model::Serializable)
|
|
@@ -129,13 +122,6 @@ module Metanorma
|
|
|
129
122
|
end
|
|
130
123
|
end
|
|
131
124
|
|
|
132
|
-
def raw_content_node?(node)
|
|
133
|
-
node.is_a?(Lutaml::Model::Serializable) &&
|
|
134
|
-
node.content.is_a?(String)
|
|
135
|
-
rescue NoMethodError
|
|
136
|
-
false
|
|
137
|
-
end
|
|
138
|
-
|
|
139
125
|
def render_ordered_inline(node)
|
|
140
126
|
parts = []
|
|
141
127
|
walked = walk_ordered(node) do |type, obj|
|
|
@@ -243,8 +229,19 @@ module Metanorma
|
|
|
243
229
|
", "
|
|
244
230
|
end
|
|
245
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
|
+
|
|
246
243
|
def render_math(el)
|
|
247
|
-
el.
|
|
244
|
+
el.to_xml
|
|
248
245
|
end
|
|
249
246
|
|
|
250
247
|
def render_asciimath(el)
|
|
@@ -374,65 +371,6 @@ module Metanorma
|
|
|
374
371
|
})
|
|
375
372
|
end
|
|
376
373
|
|
|
377
|
-
def render_raw_content(raw_xml)
|
|
378
|
-
doc = Nokogiri::XML.fragment(raw_xml)
|
|
379
|
-
doc.css("fmt-link").each do |el|
|
|
380
|
-
target = el["target"] || el["href"]
|
|
381
|
-
if target
|
|
382
|
-
display_text = target.delete_prefix("mailto:")
|
|
383
|
-
a = doc.document.create_element("a", display_text,
|
|
384
|
-
"href" => target)
|
|
385
|
-
el.replace(a)
|
|
386
|
-
else
|
|
387
|
-
el.replace(el.children)
|
|
388
|
-
end
|
|
389
|
-
end
|
|
390
|
-
doc.traverse do |node|
|
|
391
|
-
next unless node.element?
|
|
392
|
-
next unless %w[xref eref stem link].include?(node.name)
|
|
393
|
-
|
|
394
|
-
next_sib = node.next_sibling
|
|
395
|
-
while next_sib.is_a?(Nokogiri::XML::Text) && next_sib.text.strip.empty?
|
|
396
|
-
next_sib = next_sib.next_sibling
|
|
397
|
-
end
|
|
398
|
-
next unless next_sib&.element? && next_sib.name == "semx"
|
|
399
|
-
|
|
400
|
-
deduplicate_semx_label(node, next_sib)
|
|
401
|
-
node.remove
|
|
402
|
-
end
|
|
403
|
-
%w[semx fmt-xref].each do |tag|
|
|
404
|
-
doc.css(tag).each { |el| el.replace(el.children) }
|
|
405
|
-
end
|
|
406
|
-
doc.css("[class]").each do |el|
|
|
407
|
-
el["class"] = el["class"].split(/\s+/).map do |c|
|
|
408
|
-
html_class_for_span(c)
|
|
409
|
-
end.join(" ")
|
|
410
|
-
end
|
|
411
|
-
doc.inner_html
|
|
412
|
-
end
|
|
413
|
-
|
|
414
|
-
def deduplicate_semx_label(source_node, semx_node)
|
|
415
|
-
first_text = semx_node.children.find do |c|
|
|
416
|
-
c.text? && !c.text.strip.empty?
|
|
417
|
-
end
|
|
418
|
-
return unless first_text
|
|
419
|
-
|
|
420
|
-
semx_prefix = first_text.text[/\A(\s*\S+)/, 1]
|
|
421
|
-
return unless semx_prefix && !semx_prefix.strip.empty?
|
|
422
|
-
|
|
423
|
-
prev = source_node.previous_sibling
|
|
424
|
-
return unless prev.is_a?(Nokogiri::XML::Text)
|
|
425
|
-
|
|
426
|
-
label = semx_prefix.strip
|
|
427
|
-
prev_text = prev.text.rstrip
|
|
428
|
-
return unless prev_text.end_with?(label)
|
|
429
|
-
|
|
430
|
-
prev.content = prev_text.sub(/#{Regexp.escape(label)}\s*\z/, "")
|
|
431
|
-
first_text.content = first_text.text.sub(
|
|
432
|
-
/\A\s*#{Regexp.escape(label)}\s*/, ""
|
|
433
|
-
)
|
|
434
|
-
end
|
|
435
|
-
|
|
436
374
|
def render_link(link)
|
|
437
375
|
target = safe_attr(link, :target) || safe_attr(link, :href)
|
|
438
376
|
attrs = element_attrs(href: target, id: safe_attr(link, :id))
|
|
@@ -517,7 +455,7 @@ module Metanorma
|
|
|
517
455
|
end
|
|
518
456
|
|
|
519
457
|
if math_items.any?
|
|
520
|
-
content = math_items.map
|
|
458
|
+
content = math_items.map(&:to_xml).join
|
|
521
459
|
unless content.empty?
|
|
522
460
|
return render_liquid("_math_container.html.liquid", {
|
|
523
461
|
"data_attrs" => data_attrs,
|
|
@@ -592,9 +530,11 @@ module Metanorma
|
|
|
592
530
|
end
|
|
593
531
|
end
|
|
594
532
|
|
|
595
|
-
def render_mixed_content_in_order(node)
|
|
533
|
+
def render_mixed_content_in_order(node, skip_classes: nil)
|
|
596
534
|
parts = []
|
|
597
535
|
node.each_mixed_content do |child|
|
|
536
|
+
next if skip_classes&.any? { |klass| child.is_a?(klass) }
|
|
537
|
+
|
|
598
538
|
parts << case child
|
|
599
539
|
when String
|
|
600
540
|
escape_html(child)
|
|
@@ -160,57 +160,217 @@ module Metanorma
|
|
|
160
160
|
|
|
161
161
|
# --- Term rendering ---
|
|
162
162
|
|
|
163
|
+
# Unified term entry renderer. Handles both semantic-only term models
|
|
164
|
+
# (StandardDocument::Terms::Term) and presentation-aware models with
|
|
165
|
+
# fmt-* attributes (IsoDocument::Terms::IsoTerm): safe_attr returns nil
|
|
166
|
+
# for attributes a model does not declare, so the fmt-* branches are
|
|
167
|
+
# skipped automatically on semantic-only models.
|
|
163
168
|
def render_term(term, **_opts)
|
|
164
|
-
attrs = element_attrs(id: safe_attr(term, :id))
|
|
169
|
+
attrs = element_attrs(id: safe_attr(term, :id), **term_data_attrs(term))
|
|
170
|
+
fmt_definition = safe_attr(term, :fmt_definition)
|
|
171
|
+
|
|
165
172
|
parts = []
|
|
166
|
-
term
|
|
167
|
-
|
|
173
|
+
parts << (render_term_number(term) || "")
|
|
174
|
+
parts << render_term_designations(term, :fmt_preferred, :preferred,
|
|
175
|
+
"preferred")
|
|
176
|
+
parts << render_term_designations(term, :fmt_admitted, :admitted,
|
|
177
|
+
"admitted")
|
|
178
|
+
parts << render_term_designations(term, :fmt_deprecates, :deprecates,
|
|
179
|
+
"deprecated")
|
|
180
|
+
parts << (render_term_domain(term, fmt_definition) || "")
|
|
181
|
+
parts << render_term_definitions(term, fmt_definition)
|
|
182
|
+
parts << render_term_note_parts(term)
|
|
183
|
+
parts << render_term_example_parts(term)
|
|
184
|
+
parts << render_term_source_parts(term)
|
|
185
|
+
safe_attr(term, :admonition)&.each do |admonition|
|
|
186
|
+
parts << (render_admonition(admonition) || "")
|
|
168
187
|
end
|
|
169
|
-
term
|
|
170
|
-
|
|
188
|
+
safe_attr(term, :term)&.each { |sub| parts << (render_term(sub) || "") }
|
|
189
|
+
render_liquid("_element.html.liquid", {
|
|
190
|
+
"tag" => "div",
|
|
191
|
+
"extra_attrs" => attrs,
|
|
192
|
+
"content" => parts.join,
|
|
193
|
+
})
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def term_data_attrs(term)
|
|
197
|
+
term_name = extract_term_name(term)
|
|
198
|
+
term_definition = extract_term_definition(term)
|
|
199
|
+
data_attrs = {}
|
|
200
|
+
if term_name && !term_name.empty?
|
|
201
|
+
data_attrs["data-term-name"] = term_name
|
|
171
202
|
end
|
|
172
|
-
|
|
173
|
-
|
|
203
|
+
if term_definition && !term_definition.empty?
|
|
204
|
+
data_attrs["data-term-definition"] = term_definition
|
|
174
205
|
end
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
206
|
+
data_attrs
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def render_term_number(term)
|
|
210
|
+
fmt_name = safe_attr(term, :fmt_name)
|
|
211
|
+
term_number = safe_attr(term, :term_number)
|
|
212
|
+
if fmt_name
|
|
213
|
+
render_liquid("_term_number.html.liquid", {
|
|
214
|
+
"content" => render_inline_element(fmt_name),
|
|
215
|
+
})
|
|
216
|
+
elsif term_number
|
|
217
|
+
number_text = if term_number.is_a?(String)
|
|
218
|
+
term_number
|
|
179
219
|
else
|
|
180
|
-
|
|
220
|
+
extract_text_value(term_number)
|
|
181
221
|
end
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
222
|
+
render_liquid("_term_number.html.liquid", {
|
|
223
|
+
"content" => escape_html(number_text),
|
|
224
|
+
})
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Designations (preferred/admitted/deprecated): fmt-* presentation
|
|
229
|
+
# elements win when present; otherwise render semantic designations.
|
|
230
|
+
def render_term_designations(term, fmt_attr, semantic_attr, type)
|
|
231
|
+
fmt = safe_attr(term, fmt_attr)
|
|
232
|
+
fmt_list = fmt.is_a?(Array) ? fmt : [fmt].compact
|
|
233
|
+
parts = []
|
|
234
|
+
if fmt_list.empty?
|
|
235
|
+
term.public_send(semantic_attr)&.each do |designation|
|
|
236
|
+
parts << (render_term_designation(designation, type) || "")
|
|
237
|
+
end
|
|
238
|
+
else
|
|
239
|
+
fmt_list.each do |element|
|
|
240
|
+
element.p&.each { |para| parts << (render_paragraph(para) || "") }
|
|
186
241
|
end
|
|
187
242
|
end
|
|
243
|
+
parts.join
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def render_term_domain(term, fmt_definition)
|
|
247
|
+
return nil if fmt_definition
|
|
248
|
+
|
|
249
|
+
domain = term.domain
|
|
250
|
+
return nil unless domain
|
|
251
|
+
|
|
252
|
+
domain_text = domain.is_a?(String) ? domain : safe_attr(domain, :text).to_s
|
|
253
|
+
return nil if domain_text.empty?
|
|
254
|
+
|
|
255
|
+
render_liquid("_term_domain.html.liquid", {
|
|
256
|
+
"text" => escape_html(domain_text),
|
|
257
|
+
}).to_s
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def render_term_definitions(term, fmt_definition)
|
|
261
|
+
return render_ordered_content(fmt_definition) || "" if fmt_definition
|
|
262
|
+
|
|
263
|
+
parts = []
|
|
264
|
+
safe_attr(term, :p)&.each do |para|
|
|
265
|
+
parts << (render_paragraph(para) || "")
|
|
266
|
+
end
|
|
267
|
+
term.definition&.each do |definition|
|
|
268
|
+
parts << (render_term_definition(definition) || "")
|
|
269
|
+
end
|
|
270
|
+
parts.join
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def render_term_note_parts(term)
|
|
274
|
+
notes = safe_attr(term, :termnote) || Array(safe_attr(term, :note))
|
|
275
|
+
parts = []
|
|
276
|
+
notes.each_with_index do |note, i|
|
|
277
|
+
parts << (render_term_note_item(note, i) || "")
|
|
278
|
+
end
|
|
279
|
+
parts.join
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# A term note can be a raw String (rendered with a "Note N to entry"
|
|
283
|
+
# label), a termnote element (labelled wrapper), or a plain block
|
|
284
|
+
# (rendered as a generic note).
|
|
285
|
+
def render_term_note_item(note, index)
|
|
286
|
+
if note.is_a?(String)
|
|
287
|
+
render_liquid("_term_text_note.html.liquid", {
|
|
288
|
+
"label" => "Note #{index + 1} to entry: ",
|
|
289
|
+
"content" => escape_html(note),
|
|
290
|
+
}).to_s
|
|
291
|
+
elsif term_scoped_block?(note)
|
|
292
|
+
render_term_note(note)
|
|
293
|
+
else
|
|
294
|
+
render_note(note)
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def render_term_example_parts(term)
|
|
299
|
+
examples = safe_attr(term, :termexample) ||
|
|
300
|
+
Array(safe_attr(term, :example))
|
|
301
|
+
examples.map do |example|
|
|
302
|
+
render_term_example_item(example) || ""
|
|
303
|
+
end.join
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
# A term example can be a termexample element (labelled wrapper), a
|
|
307
|
+
# raw String, or a plain paragraph block (both rendered as paragraphs).
|
|
308
|
+
# render_paragraph cannot take a bare String (render_mixed_inline
|
|
309
|
+
# expects a model), so Strings go through the paragraph template
|
|
310
|
+
# directly — same markup render_paragraph would emit.
|
|
311
|
+
def render_term_example_item(example)
|
|
312
|
+
if example.is_a?(String)
|
|
313
|
+
return render_liquid("_paragraph.html.liquid", {
|
|
314
|
+
"attrs" => "",
|
|
315
|
+
"content" => escape_html(example),
|
|
316
|
+
})
|
|
317
|
+
end
|
|
318
|
+
return render_term_example(example) if term_scoped_block?(example)
|
|
319
|
+
|
|
320
|
+
render_paragraph(example)
|
|
321
|
+
end
|
|
188
322
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
323
|
+
# Termnote/termexample elements wrap block children (`p`, lists);
|
|
324
|
+
# plain paragraph blocks and Strings do not declare a `p` attribute.
|
|
325
|
+
def term_scoped_block?(node)
|
|
326
|
+
node.is_a?(Lutaml::Model::Serializable) &&
|
|
327
|
+
node.class.attributes.key?(:p)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def render_term_source_parts(term)
|
|
331
|
+
fmt_termsource = safe_attr(term, :fmt_termsource)
|
|
332
|
+
parts = []
|
|
333
|
+
if fmt_termsource && !fmt_termsource.empty?
|
|
334
|
+
fmt_termsource.each do |source|
|
|
335
|
+
parts << render_liquid("_paragraph.html.liquid", {
|
|
336
|
+
"attrs" => " class=\"term-source\"",
|
|
337
|
+
"content" => render_mixed_inline(source),
|
|
338
|
+
})
|
|
339
|
+
end
|
|
340
|
+
else
|
|
341
|
+
term.source&.each { |src| parts << (render_term_source(src) || "") }
|
|
342
|
+
safe_attr(term, :termsource)&.each do |source|
|
|
343
|
+
parts << (render_term_source_element(source) || "")
|
|
192
344
|
end
|
|
193
345
|
end
|
|
346
|
+
parts.join
|
|
347
|
+
end
|
|
194
348
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}).to_s
|
|
202
|
-
else
|
|
203
|
-
parts << (render_note(note) || "")
|
|
349
|
+
def extract_term_name(term)
|
|
350
|
+
fmt_pref = safe_attr(term, :fmt_preferred)
|
|
351
|
+
if fmt_pref && !fmt_pref.empty?
|
|
352
|
+
fp = fmt_pref.first
|
|
353
|
+
if fp.p && !fp.p.empty?
|
|
354
|
+
return extract_plain_text(fp.p.first)
|
|
204
355
|
end
|
|
205
356
|
end
|
|
357
|
+
if term.preferred && !term.preferred.empty?
|
|
358
|
+
return extract_designation_name(term.preferred.first).to_s
|
|
359
|
+
end
|
|
206
360
|
|
|
207
|
-
term.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
361
|
+
safe_attr(term, :id).to_s.delete_prefix("term-")
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def extract_term_definition(term)
|
|
365
|
+
fmt_def = safe_attr(term, :fmt_definition)
|
|
366
|
+
return extract_plain_text(fmt_def) if fmt_def
|
|
367
|
+
|
|
368
|
+
term_p = safe_attr(term, :p)
|
|
369
|
+
if term_p && !term_p.empty?
|
|
370
|
+
text = term_p.map { |para| extract_plain_text(para) }.join(" ")
|
|
371
|
+
return text.strip unless text.strip.empty?
|
|
372
|
+
end
|
|
373
|
+
nil
|
|
214
374
|
end
|
|
215
375
|
|
|
216
376
|
def render_term_designation(designation, _type)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<li{{ attrs }}>{{ content }}</li>
|
|
1
|
+
<li{{ attrs }}>{% if label %}<span class="li-label">{{ label }}</span>{% endif %}{{ content }}</li>
|
data/lib/metanorma/html/theme.rb
CHANGED
|
@@ -120,26 +120,53 @@ module Metanorma
|
|
|
120
120
|
# --- Non-YAML state (set programmatically) ---
|
|
121
121
|
attr_accessor :theme_dir
|
|
122
122
|
|
|
123
|
+
# Additional theme directories registered by flavor gems (e.g.
|
|
124
|
+
# metanorma-oiml). Searched before the built-in THEMES_DIR so a
|
|
125
|
+
# flavor can ship its own `themes/<flavor>/theme.yaml` (directory
|
|
126
|
+
# form, with assets/templates/custom.css alongside) outside this gem.
|
|
127
|
+
@extra_themes_dirs = []
|
|
128
|
+
|
|
129
|
+
class << self
|
|
130
|
+
attr_reader :extra_themes_dirs
|
|
131
|
+
|
|
132
|
+
def register_themes_dir(dir)
|
|
133
|
+
@extra_themes_dirs.unshift(File.expand_path(dir))
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def themes_dirs
|
|
137
|
+
@extra_themes_dirs + [THEMES_DIR]
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
123
141
|
def self.load(flavor)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
from_directory(dir_theme, flavor)
|
|
129
|
-
|
|
130
|
-
from_file(flat_theme)
|
|
131
|
-
else
|
|
132
|
-
new
|
|
142
|
+
themes_dirs.each do |themes_dir|
|
|
143
|
+
dir_theme = File.join(themes_dir, flavor.to_s, "theme.yaml")
|
|
144
|
+
flat_theme = File.join(themes_dir, "#{flavor}.yaml")
|
|
145
|
+
|
|
146
|
+
return from_directory(dir_theme, flavor, themes_dir) if File.exist?(dir_theme)
|
|
147
|
+
return from_file(flat_theme) if File.exist?(flat_theme)
|
|
133
148
|
end
|
|
149
|
+
|
|
150
|
+
new
|
|
134
151
|
end
|
|
135
152
|
|
|
136
153
|
def self.from_file(path)
|
|
137
154
|
from_yaml(File.read(path))
|
|
138
155
|
end
|
|
139
156
|
|
|
140
|
-
def self.from_directory(path, flavor)
|
|
157
|
+
def self.from_directory(path, flavor, themes_dir = THEMES_DIR)
|
|
141
158
|
theme = from_yaml(File.read(path))
|
|
142
|
-
theme.theme_dir = File.join(
|
|
159
|
+
theme.theme_dir = File.join(themes_dir, flavor.to_s)
|
|
160
|
+
theme
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Load a theme from an external theme directory: `dir/theme.yaml`
|
|
164
|
+
# with optional `assets/`, `templates/` and `custom.css` resolved
|
|
165
|
+
# relative to `dir`. This is the entry point for organization-local
|
|
166
|
+
# themes living outside any gem.
|
|
167
|
+
def self.from_theme_dir(dir)
|
|
168
|
+
theme = from_yaml(File.read(File.join(dir, "theme.yaml")))
|
|
169
|
+
theme.theme_dir = dir
|
|
143
170
|
theme
|
|
144
171
|
end
|
|
145
172
|
|
data/lib/metanorma/html.rb
CHANGED
|
@@ -11,57 +11,6 @@ module Metanorma
|
|
|
11
11
|
Liquid::Environment.default.file_system = Liquid::LocalFileSystem.new(
|
|
12
12
|
TEMPLATES_ROOT, "_%s.html.liquid"
|
|
13
13
|
)
|
|
14
|
-
|
|
15
|
-
Moxml::Adapter::Nokogiri.class_eval do
|
|
16
|
-
class << self
|
|
17
|
-
alias_method :_original_children_patched, :children
|
|
18
|
-
remove_method :children
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def self.children(node)
|
|
22
|
-
node.children.to_a
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# Patch missing Moxml module method used by lutaml-model XML serializer
|
|
28
|
-
::Moxml.class_eval do
|
|
29
|
-
def self.preprocess_entities(text)
|
|
30
|
-
if block_given?
|
|
31
|
-
yield text
|
|
32
|
-
else
|
|
33
|
-
text
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
module Html
|
|
39
|
-
Lutaml::Xml::XmlElement.class_eval do
|
|
40
|
-
remove_method :order
|
|
41
|
-
|
|
42
|
-
def order
|
|
43
|
-
return @order_cache if @order_cache
|
|
44
|
-
|
|
45
|
-
@order_cache = children.filter_map do |child|
|
|
46
|
-
if child.text?
|
|
47
|
-
Lutaml::Xml::Element.new("Text", "text",
|
|
48
|
-
text_content: child.text,
|
|
49
|
-
node_type: :text)
|
|
50
|
-
elsif child.cdata?
|
|
51
|
-
Lutaml::Xml::Element.new("Text", "#cdata-section",
|
|
52
|
-
text_content: child.text,
|
|
53
|
-
node_type: :cdata)
|
|
54
|
-
elsif child.comment?
|
|
55
|
-
nil
|
|
56
|
-
else
|
|
57
|
-
Lutaml::Xml::Element.new("Element", child.unprefixed_name,
|
|
58
|
-
node_type: :element,
|
|
59
|
-
namespace_uri: child.namespace_uri,
|
|
60
|
-
namespace_prefix: child.namespace_prefix)
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
14
|
end
|
|
66
15
|
|
|
67
16
|
autoload :BaseRenderer, "metanorma/html/base_renderer"
|
|
@@ -77,6 +26,7 @@ module Metanorma
|
|
|
77
26
|
autoload :IsoRenderer, "metanorma/html/iso_renderer"
|
|
78
27
|
autoload :BipmRenderer, "metanorma/html/bipm_renderer"
|
|
79
28
|
autoload :CcRenderer, "metanorma/html/cc_renderer"
|
|
29
|
+
autoload :CsaRenderer, "metanorma/html/csa_renderer"
|
|
80
30
|
autoload :IccRenderer, "metanorma/html/icc_renderer"
|
|
81
31
|
autoload :PdfaRenderer, "metanorma/html/pdfa_renderer"
|
|
82
32
|
autoload :IecRenderer, "metanorma/html/iec_renderer"
|
|
@@ -85,7 +35,6 @@ module Metanorma
|
|
|
85
35
|
autoload :IhoRenderer, "metanorma/html/iho_renderer"
|
|
86
36
|
autoload :ItuRenderer, "metanorma/html/itu_renderer"
|
|
87
37
|
autoload :OgcRenderer, "metanorma/html/ogc_renderer"
|
|
88
|
-
autoload :OimlRenderer, "metanorma/html/oiml_renderer"
|
|
89
38
|
autoload :RiboseRenderer, "metanorma/html/ribose_renderer"
|
|
90
39
|
end
|
|
91
40
|
end
|
|
@@ -4,30 +4,44 @@ module Metanorma
|
|
|
4
4
|
module IsoDocument
|
|
5
5
|
module Sections
|
|
6
6
|
# Prefatory clauses in an ISO/IEC document.
|
|
7
|
-
#
|
|
8
|
-
# abstract
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
# Corresponds to isostandard.rng:
|
|
8
|
+
# preface = element preface { abstract?, foreword, introduction? }
|
|
9
|
+
#
|
|
10
|
+
# This class deliberately does NOT inherit StandardDocument::Preface:
|
|
11
|
+
# lutaml-model deep-duplicates a parent's XML mappings into subclasses,
|
|
12
|
+
# so inheriting would keep the isodoc-level acknowledgements and
|
|
13
|
+
# executivesummary mappings that the ISO grammar forbids. Attributes
|
|
14
|
+
# are composed directly instead.
|
|
15
|
+
#
|
|
16
|
+
# The `clause` mapping is a documented extension required by real ISO
|
|
17
|
+
# presentation output, which emits front-matter clauses such as
|
|
18
|
+
# `<clause type="toc">` ahead of the foreword. `content` mirrors
|
|
19
|
+
# `clause` for the generic preface-content consumers (e.g. the mirror
|
|
20
|
+
# renderer), matching the runtime behavior of the previous inherited
|
|
21
|
+
# dual mapping.
|
|
22
|
+
class IsoPreface < Lutaml::Model::Serializable
|
|
14
23
|
attribute :abstract, IsoAbstractSection
|
|
15
24
|
attribute :foreword, IsoForewordSection
|
|
16
25
|
attribute :introduction, IsoClauseSection
|
|
17
26
|
|
|
18
|
-
#
|
|
27
|
+
# Presentation front-matter clauses (e.g. table of contents placeholder)
|
|
19
28
|
attribute :clause, IsoClauseSection, collection: true
|
|
29
|
+
attribute :content, Metanorma::StandardDocument::Sections::ContentSection,
|
|
30
|
+
collection: true
|
|
20
31
|
|
|
21
|
-
#
|
|
22
|
-
attribute :
|
|
23
|
-
attribute :
|
|
32
|
+
# Presentation-specific attributes
|
|
33
|
+
attribute :semx_id, :string
|
|
34
|
+
attribute :displayorder, :integer
|
|
24
35
|
|
|
25
36
|
xml do
|
|
26
37
|
element "preface"
|
|
27
38
|
ordered
|
|
28
39
|
|
|
29
|
-
|
|
30
|
-
map_element "
|
|
40
|
+
map_element "abstract", to: :abstract
|
|
41
|
+
map_element "foreword", to: :foreword
|
|
42
|
+
map_element "introduction", to: :introduction
|
|
43
|
+
map_element "clause", to: :clause
|
|
44
|
+
map_element "clause", to: :content
|
|
31
45
|
|
|
32
46
|
Metanorma::StandardDocument::SectionXmlMapping.apply_preface_attributes(self)
|
|
33
47
|
end
|
|
@@ -153,6 +153,27 @@ module Metanorma
|
|
|
153
153
|
Handlers::Structural,
|
|
154
154
|
method_name: :preface,
|
|
155
155
|
)
|
|
156
|
+
# IsoPreface and UnPreface deliberately do not inherit
|
|
157
|
+
# StandardDocument::Preface (grammar-strict classes compose from
|
|
158
|
+
# mixins), so they need explicit registrations — the registry
|
|
159
|
+
# resolves handlers through class ancestry.
|
|
160
|
+
registry.register(
|
|
161
|
+
Metanorma::IsoDocument::Sections::IsoPreface,
|
|
162
|
+
Handlers::Structural,
|
|
163
|
+
method_name: :preface,
|
|
164
|
+
)
|
|
165
|
+
registry.register(
|
|
166
|
+
Metanorma::UnDocument::Sections::UnPreface,
|
|
167
|
+
Handlers::Structural,
|
|
168
|
+
method_name: :preface,
|
|
169
|
+
)
|
|
170
|
+
# UnAbstractSection likewise composes instead of inheriting
|
|
171
|
+
# ContentSection.
|
|
172
|
+
registry.register(
|
|
173
|
+
Metanorma::UnDocument::Sections::UnAbstractSection,
|
|
174
|
+
Handlers::Section,
|
|
175
|
+
method_name: :content_section,
|
|
176
|
+
)
|
|
156
177
|
registry.register(
|
|
157
178
|
Metanorma::StandardDocument::Sections::Sections,
|
|
158
179
|
Handlers::Structural,
|
|
@@ -5,19 +5,14 @@ module Metanorma
|
|
|
5
5
|
module Handlers
|
|
6
6
|
module Inline
|
|
7
7
|
# Shared declarative table of inline marks whose HTML rendering is
|
|
8
|
-
# a fixed tag with optional static attrs.
|
|
8
|
+
# a fixed tag with optional static attrs. It is consumed by
|
|
9
|
+
# RichHtmlRenderer, which renders Metanorma XML elements to HTML
|
|
10
|
+
# directly (the fallback / attribute-value path) during the
|
|
11
|
+
# forward transform into the mirror IR.
|
|
9
12
|
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# to HTML (the primary SSR path).
|
|
14
|
-
#
|
|
15
|
-
# Both adapters must produce visually equivalent HTML for the same
|
|
16
|
-
# mark type — the table is the single source of truth for the
|
|
17
|
-
# mark-name to tag-and-attrs mapping. Marks whose attrs vary per
|
|
18
|
-
# instance (link, xref, eref, span) carry data in mark.attrs and
|
|
19
|
-
# are not in this table; each adapter keeps custom handlers for
|
|
20
|
-
# those.
|
|
13
|
+
# Marks whose attrs vary per instance (link, xref, eref, span)
|
|
14
|
+
# carry data in mark.attrs and are not in this table; each
|
|
15
|
+
# consumer keeps custom handlers for those.
|
|
21
16
|
module Catalog
|
|
22
17
|
SIMPLE_WRAPS = {
|
|
23
18
|
"emphasis" => { tag: :em },
|
|
@@ -12,9 +12,8 @@ module Metanorma
|
|
|
12
12
|
# Nokogiri::HTML5::Builder to guarantee well-formed, escaped output.
|
|
13
13
|
#
|
|
14
14
|
# Simple-wrap elements (em, strong, sub, sup, code, u, s, smallcap,
|
|
15
|
-
# bcp14, concept)
|
|
16
|
-
#
|
|
17
|
-
# produce visually equivalent output for the same mark type.
|
|
15
|
+
# bcp14, concept) take their tag-and-attrs mapping from the shared
|
|
16
|
+
# Inline::Catalog table.
|
|
18
17
|
module RichHtmlRenderer
|
|
19
18
|
# Complex element handlers — these have per-instance attrs or
|
|
20
19
|
# multi-step rendering and bypass the shared Catalog.
|