metanorma-document 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +231 -53
  3. data/README.adoc +59 -18
  4. data/data/stylesheets/components/bibliography.css +2 -2
  5. data/data/stylesheets/components/inline.css +11 -12
  6. data/docs/html-renderer.adoc +261 -0
  7. data/lib/metanorma/document/version.rb +1 -1
  8. data/lib/metanorma/html/base_renderer.rb +210 -257
  9. data/lib/metanorma/html/bipm_renderer.rb +0 -1
  10. data/lib/metanorma/html/cc_renderer.rb +0 -1
  11. data/lib/metanorma/html/drops/admonition_drop.rb +26 -0
  12. data/lib/metanorma/html/drops/block_element_drop.rb +20 -0
  13. data/lib/metanorma/html/drops/example_drop.rb +35 -0
  14. data/lib/metanorma/html/drops/figure_drop.rb +53 -0
  15. data/lib/metanorma/html/drops/formula_drop.rb +44 -0
  16. data/lib/metanorma/html/drops/note_drop.rb +32 -0
  17. data/lib/metanorma/html/drops/sourcecode_drop.rb +37 -0
  18. data/lib/metanorma/html/drops.rb +7 -0
  19. data/lib/metanorma/html/iec_renderer.rb +0 -1
  20. data/lib/metanorma/html/ieee_renderer.rb +0 -1
  21. data/lib/metanorma/html/ietf_renderer.rb +0 -1
  22. data/lib/metanorma/html/iho_renderer.rb +0 -1
  23. data/lib/metanorma/html/iso_renderer.rb +77 -209
  24. data/lib/metanorma/html/itu_renderer.rb +0 -1
  25. data/lib/metanorma/html/ogc_renderer.rb +5 -6
  26. data/lib/metanorma/html/oiml_renderer.rb +0 -1
  27. data/lib/metanorma/html/pdfa_renderer.rb +0 -1
  28. data/lib/metanorma/html/ribose_renderer.rb +0 -1
  29. data/lib/metanorma/html/standard_renderer.rb +63 -82
  30. data/lib/metanorma/html/templates/_admonition.html.liquid +4 -0
  31. data/lib/metanorma/html/templates/_doc_title.html.liquid +1 -1
  32. data/lib/metanorma/html/templates/_example.html.liquid +3 -0
  33. data/lib/metanorma/html/templates/_figure.html.liquid +6 -0
  34. data/lib/metanorma/html/templates/_formula.html.liquid +6 -0
  35. data/lib/metanorma/html/templates/_iso_doc_title.html.liquid +2 -2
  36. data/lib/metanorma/html/templates/_note.html.liquid +3 -0
  37. data/lib/metanorma/html/templates/_sourcecode.html.liquid +4 -0
  38. data/lib/metanorma/html.rb +0 -1
  39. metadata +16 -3
  40. data/lib/metanorma/html/component_registry.rb +0 -37
@@ -0,0 +1,261 @@
1
+ = HTML Renderer Architecture
2
+
3
+ == Overview
4
+
5
+ The HTML renderer converts a Metanorma document model (parsed from presentation XML) into a complete, self-contained HTML document. It produces all body content, header, footer, table of contents, CSS theming, and JavaScript interactivity.
6
+
7
+ == Pipeline
8
+
9
+ ....
10
+ Generator.generate(doc)
11
+ ├── Auto-selects renderer by document class
12
+ ├── Renderer.new
13
+ └── renderer.generate_full_document(doc)
14
+ ├── Header (publisher logos, document title)
15
+ ├── ToC sidebar
16
+ ├── Body content (recursive render)
17
+ ├── Footnotes
18
+ ├── Footer (copyright)
19
+ └── Asset pipeline (inline CSS + JS)
20
+ ....
21
+
22
+ == Renderer Hierarchy
23
+
24
+ [source,ruby]
25
+ BaseRenderer # Core HTML rendering, document assembly, CSS/JS pipeline
26
+ └── StandardRenderer # Terms, definitions, annexes, bibliography
27
+ ├── IsoRenderer # ISO cover page, copyright, title formatting
28
+ │ ├── IccRenderer # ICC publisher styling
29
+ │ └── PdfaRenderer # PDF Association publisher styling
30
+ ├── IecRenderer # IEC-specific formatting
31
+ ├── IeeeRenderer # IEEE-specific formatting
32
+ ├── IetfRenderer # IETF-specific formatting
33
+ ├── IhoRenderer # IHO-specific formatting
34
+ ├── ItuRenderer # ITU-specific formatting
35
+ ├── OgcRenderer # OGC-specific formatting
36
+ ├── OimlRenderer # OIML-specific formatting
37
+ ├── BipmRenderer # BIPM-specific formatting
38
+ ├── CcRenderer # CC-specific formatting
39
+ └── RiboseRenderer # Ribose-specific formatting
40
+
41
+ === Renderer Selection
42
+
43
+ The `Generator` uses a two-tier lookup:
44
+
45
+ 1. **Taste match**: If the document's publisher matches a registered taste, use that renderer.
46
+ 2. **Model class**: Walk the ancestor chain from most specific to `BaseRenderer`.
47
+
48
+ [source,ruby]
49
+ # ICC documents are IsoDocument::Root but use IccRenderer
50
+ Metanorma::Html::Generator.register_taste(
51
+ Metanorma::IsoDocument::Root,
52
+ "ICC",
53
+ Metanorma::Html::IccRenderer
54
+ )
55
+
56
+ == Class Name Ownership
57
+
58
+ The HTML renderer owns its class names entirely. **No XML-originated class names appear in the HTML output.**
59
+
60
+ The XML document model's `class_attr` is read as **input only** to determine semantic role. The renderer maps XML roles to HTML-specific class names via `SPAN_ROLE_CLASSES`:
61
+
62
+ [source,ruby]
63
+ SPAN_ROLE_CLASSES = {
64
+ "boldtitle" => "title-text",
65
+ "citefig" => "xref-fig",
66
+ "citesec" => "xref-section",
67
+ "fmt-element-name" => "element-label",
68
+ "fmt-obligation" => "obligation-text",
69
+ # ...
70
+ }.freeze
71
+
72
+ Block-level classes (`note-block`, `formula`, `figure`, etc.) are assigned by the renderer based on what it's rendering — never carried over from XML.
73
+
74
+ Inline span classes go through `html_class_for_span`:
75
+
76
+ [source,ruby]
77
+ def html_class_for_span(xml_class)
78
+ SPAN_ROLE_CLASSES[xml_class] || "span-#{xml_class}"
79
+ end
80
+
81
+ Raw XML content (e.g., boilerplate) passes through Nokogiri post-processing that remaps any remaining XML class names.
82
+
83
+ == Drop Pattern
84
+
85
+ Block elements (notes, examples, sourcecode, formulas, figures, admonitions) use the Drop pattern to separate data capture from template rendering.
86
+
87
+ === How It Works
88
+
89
+ . A `Drop` class captures rendered content via `RendererContext`
90
+ . The Drop passes pre-rendered HTML strings to a Liquid template
91
+ . The template reads Drop attributes and outputs final HTML
92
+
93
+ [source,ruby]
94
+ # In the renderer:
95
+ def render_note(note, **_opts)
96
+ drop = Drops::NoteDrop.from_model(note, renderer: renderer_context)
97
+ @output << render_liquid("_note.html.liquid", { "block" => drop })
98
+ end
99
+
100
+ # In the Drop:
101
+ class NoteDrop < BlockElementDrop
102
+ def self.from_model(note, renderer:)
103
+ content_html = renderer.capture_output do
104
+ note.content.each { |para| renderer.render_paragraph(para) }
105
+ end
106
+ new(id: renderer.safe_attr(note, :id),
107
+ label_html: renderer.escape_html(label),
108
+ content_html: content_html,
109
+ css_class: "note-block")
110
+ end
111
+ end
112
+
113
+ === BlockElementDrop
114
+
115
+ All block drops inherit from `BlockElementDrop`, which provides common attributes:
116
+
117
+ `id` :: HTML element id
118
+ `type` :: Block type identifier
119
+ `label_html` :: Pre-rendered label (e.g., "NOTE", "EXAMPLE 1")
120
+ `content_html` :: Pre-rendered inner content
121
+ `css_class` :: HTML-specific class name
122
+
123
+ === RendererContext
124
+
125
+ `RendererContext` is a facade inside `BaseRenderer` that exposes only the rendering methods Drops need. Drops call renderer methods through this facade — the renderer's private interface stays encapsulated.
126
+
127
+ [source,ruby]
128
+ class RendererContext
129
+ def safe_attr(obj, method_name)
130
+ def escape_html(text)
131
+ def extract_block_label(block, default)
132
+ def extract_plain_text(node)
133
+ def capture_output(&block)
134
+ def render_paragraph(p)
135
+ def render_mixed_inline(node)
136
+ def render_inline_element(el)
137
+ def render_unordered_list(ul)
138
+ def render_ordered_list(ol)
139
+ def render_definition_list(dl)
140
+ def render_table(table)
141
+ def render_figure(figure)
142
+ end
143
+
144
+ == Liquid Templates
145
+
146
+ HTML structure is defined in `.liquid` templates under `lib/metanorma/html/templates/`.
147
+
148
+ [horizontal]
149
+ `document.html.liquid` :: Full document shell (`<html>`, `<head>`, `<body>`)
150
+ `_header.html.liquid` :: Sticky header with publisher logos
151
+ `_footer.html.liquid` :: Footer with copyright
152
+ `_cover.html.liquid` :: Generic cover page layout
153
+ `_iso_cover.html.liquid` :: ISO-specific cover page
154
+ `_iso_doc_title.html.liquid` :: ISO document title rendering
155
+ `_doc_title.html.liquid` :: Generic document title rendering
156
+ `_footnotes.html.liquid` :: Footnotes section
157
+ `_note.html.liquid` :: Note block
158
+ `_example.html.liquid` :: Example block
159
+ `_sourcecode.html.liquid` :: Source code block
160
+ `_formula.html.liquid` :: Formula block
161
+ `_figure.html.liquid` :: Figure block
162
+ `_admonition.html.liquid` :: Admonition block
163
+
164
+ Templates use `Liquid::LocalFileSystem` for partials (prefixed with `_`). The `render_liquid` method handles template caching.
165
+
166
+ === Template Example
167
+
168
+ `_note.html.liquid`:
169
+
170
+ [source,liquid]
171
+ ----
172
+ <div{% if block.id %} id="{{ block.id }}"{% endif %} class="{{ block.css_class }}">
173
+ {% if block.label_html %}
174
+ <p class="note-label"><strong>{{ block.label_html }}</strong></p>
175
+ {% endif %}
176
+ <div class="note-content">
177
+ {{ block.content_html }}
178
+ </div>
179
+ </div>
180
+ ----
181
+
182
+ == Theming
183
+
184
+ Each renderer has a `Theme` object controlling colors, typography, and layout. Theme properties are emitted as CSS custom properties (`--mn-primary`, `--font-body`, etc.).
185
+
186
+ [source,ruby]
187
+ class MyRenderer < Metanorma::Html::StandardRenderer
188
+ def theme
189
+ @theme ||= begin
190
+ t = Theme.new
191
+ t.primary = "#1a5276"
192
+ t.accent = "#2e86c1"
193
+ t.font_body = '"Charter", serif'
194
+ t
195
+ end
196
+ end
197
+ end
198
+
199
+ === Theme Properties
200
+
201
+ [horizontal]
202
+ `primary` :: Primary brand color
203
+ `accent` :: Accent/highlight color
204
+ `gradient` :: Header gradient
205
+ `font_body` :: Body text font stack
206
+ `font_sans` :: Sans-serif font stack
207
+ `font_mono` :: Monospace font stack
208
+ `font_url` :: Google Fonts URL
209
+ `note_border` :: Note block border color
210
+ `note_bg` :: Note block background
211
+ `example_border` :: Example block border color
212
+ `example_bg` :: Example block background
213
+ `admonition_border` :: Admonition border color
214
+ `admonition_bg` :: Admonition background
215
+ `extra_css` :: Additional CSS string appended after defaults
216
+
217
+ == Presentation XML
218
+
219
+ The HTML renderer expects **presentation XML** (not source XML). Presentation XML contains `fmt-*` display elements alongside semantic elements:
220
+
221
+ - `fmt-title` — formatted section/block titles
222
+ - `fmt-xref` — formatted cross-reference text
223
+ - `fmt-link` — formatted link text
224
+ - `fmt-concept` — formatted concept references
225
+ - `fmt-definition` — formatted term definitions
226
+ - `fmt-preferred` — formatted preferred term names
227
+
228
+ The renderer prioritizes `fmt-*` elements for rendering, falling back to semantic elements when display elements are absent.
229
+
230
+ == Asset Pipeline
231
+
232
+ The `AssetPipeline` compiles CSS and JavaScript from modular source files into inline `<style>` and `<script>` blocks for self-contained output.
233
+
234
+ === CSS
235
+
236
+ [horizontal]
237
+ `data/stylesheets/base/` :: Reset, typography, layout, dark mode, print
238
+ `data/stylesheets/components/` :: Component stylesheets (inline, tables, notes, etc.)
239
+
240
+ === JavaScript
241
+
242
+ [horizontal]
243
+ `data/javascripts/core/` :: Reader, theme, scroll, navigation, reveal
244
+ `data/javascripts/components/` :: ToC, search, lightbox, code copy, glossary, etc.
245
+
246
+ == Extending
247
+
248
+ To add a new flavor renderer:
249
+
250
+ . Subclass the appropriate base (usually `IsoRenderer` or `StandardRenderer`)
251
+ . Override `theme` with brand colors/fonts
252
+ . Override `publisher_logo_map` with logo filenames
253
+ . Register with the Generator:
254
+
255
+ [source,ruby]
256
+ Metanorma::Html::Generator.register(
257
+ Metanorma::MyDocument::Root,
258
+ Metanorma::Html::MyRenderer
259
+ )
260
+
261
+ To customize how a specific block renders, override the `render_*` method and either emit HTML directly or use the Drop pattern with a new template.
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Metanorma
4
4
  module Document
5
- VERSION = "0.2.0"
5
+ VERSION = "0.2.2"
6
6
  Version = VERSION
7
7
  end
8
8
  end