docbook 0.1.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 +7 -0
- data/CHANGELOG.md +5 -0
- data/CLAUDE.md +19 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/README.adoc +335 -0
- data/Rakefile +12 -0
- data/docs/.lycheeignore +33 -0
- data/docs/Gemfile +10 -0
- data/docs/INDEX.adoc +67 -0
- data/docs/_config.yml +186 -0
- data/docs/advanced/element-classes.adoc +185 -0
- data/docs/advanced/frontend-customization.adoc +193 -0
- data/docs/advanced/index.adoc +14 -0
- data/docs/advanced/templates.adoc +123 -0
- data/docs/features/element-coverage.adoc +373 -0
- data/docs/features/html-output/data-model.adoc +285 -0
- data/docs/features/html-output/directory-mode.adoc +180 -0
- data/docs/features/html-output/index.adoc +90 -0
- data/docs/features/html-output/single-file-mode.adoc +125 -0
- data/docs/features/index-generation.adoc +197 -0
- data/docs/features/index.adoc +63 -0
- data/docs/features/numbering.adoc +183 -0
- data/docs/features/toc-generation.adoc +150 -0
- data/docs/features/xinclude/fragid-schemes.adoc +287 -0
- data/docs/features/xinclude/index.adoc +119 -0
- data/docs/features/xinclude/text-includes.adoc +123 -0
- data/docs/features/xinclude/xml-includes.adoc +167 -0
- data/docs/getting-started/index.adoc +50 -0
- data/docs/getting-started/installation.adoc +113 -0
- data/docs/getting-started/quick-start.adoc +161 -0
- data/docs/guides/converting-article.adoc +188 -0
- data/docs/guides/converting-book.adoc +192 -0
- data/docs/guides/index.adoc +12 -0
- data/docs/guides/roundtrip-testing.adoc +129 -0
- data/docs/interfaces/cli/format-command.adoc +109 -0
- data/docs/interfaces/cli/index.adoc +73 -0
- data/docs/interfaces/cli/roundtrip-command.adoc +125 -0
- data/docs/interfaces/cli/to-html-command.adoc +178 -0
- data/docs/interfaces/cli/validate-command.adoc +104 -0
- data/docs/interfaces/index.adoc +101 -0
- data/docs/interfaces/ruby-api/html-output.adoc +186 -0
- data/docs/interfaces/ruby-api/index.adoc +111 -0
- data/docs/interfaces/ruby-api/parsing.adoc +202 -0
- data/docs/interfaces/ruby-api/xinclude.adoc +162 -0
- data/docs/interfaces/ruby-api/xref-resolution.adoc +156 -0
- data/docs/lychee.toml +42 -0
- data/docs/reference/cli-options.adoc +155 -0
- data/docs/reference/content-block-types.adoc +243 -0
- data/docs/reference/glossary.adoc +119 -0
- data/docs/reference/index.adoc +12 -0
- data/docs/reference/supported-elements.adoc +749 -0
- data/docs/understanding/architecture.adoc +145 -0
- data/docs/understanding/content-pipeline.adoc +102 -0
- data/docs/understanding/data-models.adoc +156 -0
- data/docs/understanding/index.adoc +34 -0
- data/exe/docbook +7 -0
- data/frontend/dist/app.css +1 -0
- data/frontend/dist/app.iife.js +24 -0
- data/frontend/package-lock.json +1445 -0
- data/frontend/package.json +22 -0
- data/frontend/src/App.vue +230 -0
- data/frontend/src/app.ts +8 -0
- data/frontend/src/components/AppSidebar.vue +116 -0
- data/frontend/src/components/AppendixSection.vue +39 -0
- data/frontend/src/components/BlockRenderer.vue +358 -0
- data/frontend/src/components/ChapterSection.vue +32 -0
- data/frontend/src/components/ContentRenderer.vue +13 -0
- data/frontend/src/components/EbookContainer.vue +147 -0
- data/frontend/src/components/EbookTopBar.vue +116 -0
- data/frontend/src/components/PartSection.vue +44 -0
- data/frontend/src/components/ReferenceEntry.vue +80 -0
- data/frontend/src/components/SearchModal.vue +286 -0
- data/frontend/src/components/SectionContent.vue +31 -0
- data/frontend/src/components/SettingsPanel.vue +236 -0
- data/frontend/src/components/TocTreeItem.vue +135 -0
- data/frontend/src/composables/useEbookStore.ts +191 -0
- data/frontend/src/composables/useSearch.ts +249 -0
- data/frontend/src/env.d.ts +7 -0
- data/frontend/src/stores/documentStore.ts +221 -0
- data/frontend/src/stores/uiStore.ts +98 -0
- data/frontend/src/styles.css +253 -0
- data/frontend/tsconfig.json +24 -0
- data/frontend/tsconfig.node.json +11 -0
- data/frontend/vite.config.ts +30 -0
- data/lib/docbook/cli.rb +123 -0
- data/lib/docbook/document.rb +67 -0
- data/lib/docbook/elements/abbrev.rb +16 -0
- data/lib/docbook/elements/acknowledgements.rb +22 -0
- data/lib/docbook/elements/address.rb +18 -0
- data/lib/docbook/elements/alt.rb +16 -0
- data/lib/docbook/elements/annotation.rb +18 -0
- data/lib/docbook/elements/appendix.rb +34 -0
- data/lib/docbook/elements/article.rb +31 -0
- data/lib/docbook/elements/att.rb +15 -0
- data/lib/docbook/elements/attribution.rb +20 -0
- data/lib/docbook/elements/audioobject.rb +18 -0
- data/lib/docbook/elements/author.rb +18 -0
- data/lib/docbook/elements/bibliography.rb +24 -0
- data/lib/docbook/elements/bibliomixed.rb +40 -0
- data/lib/docbook/elements/biblioref.rb +20 -0
- data/lib/docbook/elements/blockquote.rb +26 -0
- data/lib/docbook/elements/book.rb +36 -0
- data/lib/docbook/elements/buildtarget.rb +16 -0
- data/lib/docbook/elements/callout.rb +22 -0
- data/lib/docbook/elements/calloutlist.rb +22 -0
- data/lib/docbook/elements/caution.rb +30 -0
- data/lib/docbook/elements/chapter.rb +62 -0
- data/lib/docbook/elements/citation.rb +16 -0
- data/lib/docbook/elements/citerefentry.rb +26 -0
- data/lib/docbook/elements/citetitle.rb +20 -0
- data/lib/docbook/elements/classname.rb +16 -0
- data/lib/docbook/elements/code.rb +16 -0
- data/lib/docbook/elements/colophon.rb +22 -0
- data/lib/docbook/elements/computeroutput.rb +18 -0
- data/lib/docbook/elements/copyright.rb +17 -0
- data/lib/docbook/elements/danger.rb +28 -0
- data/lib/docbook/elements/date.rb +16 -0
- data/lib/docbook/elements/dedication.rb +22 -0
- data/lib/docbook/elements/dir.rb +16 -0
- data/lib/docbook/elements/emphasis.rb +18 -0
- data/lib/docbook/elements/entry.rb +30 -0
- data/lib/docbook/elements/entrytbl.rb +22 -0
- data/lib/docbook/elements/equation.rb +26 -0
- data/lib/docbook/elements/example.rb +30 -0
- data/lib/docbook/elements/fieldsynopsis.rb +21 -0
- data/lib/docbook/elements/figure.rb +28 -0
- data/lib/docbook/elements/filename.rb +16 -0
- data/lib/docbook/elements/firstname.rb +16 -0
- data/lib/docbook/elements/firstterm.rb +18 -0
- data/lib/docbook/elements/footnote.rb +22 -0
- data/lib/docbook/elements/footnoteref.rb +21 -0
- data/lib/docbook/elements/foreignphrase.rb +18 -0
- data/lib/docbook/elements/formalpara.rb +20 -0
- data/lib/docbook/elements/function.rb +16 -0
- data/lib/docbook/elements/glossary.rb +24 -0
- data/lib/docbook/elements/glossdef.rb +18 -0
- data/lib/docbook/elements/glossentry.rb +26 -0
- data/lib/docbook/elements/glosssee.rb +18 -0
- data/lib/docbook/elements/glossseealso.rb +18 -0
- data/lib/docbook/elements/glossterm.rb +18 -0
- data/lib/docbook/elements/holder.rb +16 -0
- data/lib/docbook/elements/honorific.rb +16 -0
- data/lib/docbook/elements/imagedata.rb +29 -0
- data/lib/docbook/elements/imageobject.rb +22 -0
- data/lib/docbook/elements/important.rb +30 -0
- data/lib/docbook/elements/index.rb +26 -0
- data/lib/docbook/elements/indexdiv.rb +22 -0
- data/lib/docbook/elements/indexentry.rb +22 -0
- data/lib/docbook/elements/indexterm.rb +34 -0
- data/lib/docbook/elements/info.rb +25 -0
- data/lib/docbook/elements/informalexample.rb +24 -0
- data/lib/docbook/elements/informalfigure.rb +20 -0
- data/lib/docbook/elements/inlinemediaobject.rb +22 -0
- data/lib/docbook/elements/itemizedlist.rb +21 -0
- data/lib/docbook/elements/legalnotice.rb +22 -0
- data/lib/docbook/elements/link.rb +26 -0
- data/lib/docbook/elements/listitem.rb +32 -0
- data/lib/docbook/elements/literal.rb +16 -0
- data/lib/docbook/elements/literallayout.rb +22 -0
- data/lib/docbook/elements/mediaobject.rb +26 -0
- data/lib/docbook/elements/msg.rb +20 -0
- data/lib/docbook/elements/msgexplan.rb +22 -0
- data/lib/docbook/elements/msgset.rb +22 -0
- data/lib/docbook/elements/note.rb +30 -0
- data/lib/docbook/elements/orderedlist.rb +23 -0
- data/lib/docbook/elements/orgname.rb +16 -0
- data/lib/docbook/elements/para.rb +61 -0
- data/lib/docbook/elements/paragraph_like.rb +18 -0
- data/lib/docbook/elements/parameter.rb +16 -0
- data/lib/docbook/elements/part.rb +38 -0
- data/lib/docbook/elements/personname.rb +22 -0
- data/lib/docbook/elements/phrase.rb +20 -0
- data/lib/docbook/elements/preface.rb +58 -0
- data/lib/docbook/elements/primary.rb +16 -0
- data/lib/docbook/elements/procedure.rb +24 -0
- data/lib/docbook/elements/productname.rb +18 -0
- data/lib/docbook/elements/productnumber.rb +16 -0
- data/lib/docbook/elements/programlisting.rb +28 -0
- data/lib/docbook/elements/property.rb +16 -0
- data/lib/docbook/elements/pubdate.rb +16 -0
- data/lib/docbook/elements/publishername.rb +16 -0
- data/lib/docbook/elements/quotation.rb +24 -0
- data/lib/docbook/elements/quote.rb +18 -0
- data/lib/docbook/elements/refentry.rb +32 -0
- data/lib/docbook/elements/refentrytitle.rb +16 -0
- data/lib/docbook/elements/reference.rb +26 -0
- data/lib/docbook/elements/refmeta.rb +29 -0
- data/lib/docbook/elements/refmiscinfo.rb +16 -0
- data/lib/docbook/elements/refname.rb +16 -0
- data/lib/docbook/elements/refnamediv.rb +22 -0
- data/lib/docbook/elements/refpurpose.rb +16 -0
- data/lib/docbook/elements/refsect1.rb +22 -0
- data/lib/docbook/elements/refsect2.rb +22 -0
- data/lib/docbook/elements/refsect3.rb +22 -0
- data/lib/docbook/elements/refsection.rb +32 -0
- data/lib/docbook/elements/releaseinfo.rb +16 -0
- data/lib/docbook/elements/remark.rb +20 -0
- data/lib/docbook/elements/replaceable.rb +16 -0
- data/lib/docbook/elements/row.rb +15 -0
- data/lib/docbook/elements/screen.rb +28 -0
- data/lib/docbook/elements/secondary.rb +16 -0
- data/lib/docbook/elements/sect1.rb +26 -0
- data/lib/docbook/elements/sect2.rb +24 -0
- data/lib/docbook/elements/sect3.rb +24 -0
- data/lib/docbook/elements/sect4.rb +24 -0
- data/lib/docbook/elements/sect5.rb +22 -0
- data/lib/docbook/elements/section.rb +66 -0
- data/lib/docbook/elements/see.rb +16 -0
- data/lib/docbook/elements/seealso.rb +18 -0
- data/lib/docbook/elements/set.rb +26 -0
- data/lib/docbook/elements/setindex.rb +24 -0
- data/lib/docbook/elements/sidebar.rb +22 -0
- data/lib/docbook/elements/simplesect.rb +32 -0
- data/lib/docbook/elements/step.rb +26 -0
- data/lib/docbook/elements/substeps.rb +18 -0
- data/lib/docbook/elements/subtitle.rb +16 -0
- data/lib/docbook/elements/surname.rb +16 -0
- data/lib/docbook/elements/table.rb +24 -0
- data/lib/docbook/elements/tag.rb +20 -0
- data/lib/docbook/elements/tbody.rb +15 -0
- data/lib/docbook/elements/term.rb +37 -0
- data/lib/docbook/elements/tertiary.rb +16 -0
- data/lib/docbook/elements/textobject.rb +18 -0
- data/lib/docbook/elements/tfoot.rb +15 -0
- data/lib/docbook/elements/tgroup.rb +21 -0
- data/lib/docbook/elements/thead.rb +15 -0
- data/lib/docbook/elements/tip.rb +30 -0
- data/lib/docbook/elements/title.rb +16 -0
- data/lib/docbook/elements/toc.rb +24 -0
- data/lib/docbook/elements/tocdiv.rb +22 -0
- data/lib/docbook/elements/tocentry.rb +20 -0
- data/lib/docbook/elements/topic.rb +26 -0
- data/lib/docbook/elements/type.rb +16 -0
- data/lib/docbook/elements/uri.rb +16 -0
- data/lib/docbook/elements/userinput.rb +18 -0
- data/lib/docbook/elements/variable.rb +16 -0
- data/lib/docbook/elements/variablelist.rb +19 -0
- data/lib/docbook/elements/varlistentry.rb +17 -0
- data/lib/docbook/elements/version.rb +16 -0
- data/lib/docbook/elements/videoobject.rb +18 -0
- data/lib/docbook/elements/warning.rb +30 -0
- data/lib/docbook/elements/xref.rb +18 -0
- data/lib/docbook/elements/year.rb +16 -0
- data/lib/docbook/elements.rb +204 -0
- data/lib/docbook/models/document_metadata.rb +30 -0
- data/lib/docbook/models/document_root.rb +33 -0
- data/lib/docbook/models/index_entry.rb +28 -0
- data/lib/docbook/models/reading_position.rb +22 -0
- data/lib/docbook/models/section_number.rb +18 -0
- data/lib/docbook/models/section_root.rb +29 -0
- data/lib/docbook/models/toc_node.rb +24 -0
- data/lib/docbook/models.rb +16 -0
- data/lib/docbook/output/data.rb +196 -0
- data/lib/docbook/output/html.rb +1450 -0
- data/lib/docbook/output/index_generator.rb +281 -0
- data/lib/docbook/output.rb +8 -0
- data/lib/docbook/services/document_builder.rb +258 -0
- data/lib/docbook/services/element_to_hash.rb +287 -0
- data/lib/docbook/services/index_generator.rb +134 -0
- data/lib/docbook/services/numbering_service.rb +186 -0
- data/lib/docbook/services/toc_generator.rb +138 -0
- data/lib/docbook/services.rb +14 -0
- data/lib/docbook/templates/document.html.liquid +20 -0
- data/lib/docbook/templates/partials/_head.liquid +39 -0
- data/lib/docbook/templates/partials/_scripts.liquid +10 -0
- data/lib/docbook/version.rb +5 -0
- data/lib/docbook/xinclude_resolver.rb +217 -0
- data/lib/docbook/xref_resolver.rb +78 -0
- data/lib/docbook.rb +17 -0
- data/sig/docbook.rbs +4 -0
- metadata +385 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Directory Mode
|
|
4
|
+
parent: HTML Output
|
|
5
|
+
grand_parent: Features
|
|
6
|
+
nav_order: 2
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Directory Mode
|
|
10
|
+
|
|
11
|
+
Directory mode (`output_mode: :directory`) produces a directory of files suitable for serving over HTTP. Instead of inlining everything into a single HTML file, assets are separated into their own files and the Vue SPA fetches data at runtime.
|
|
12
|
+
|
|
13
|
+
## Output Structure
|
|
14
|
+
|
|
15
|
+
When directory mode is active, the output directory contains:
|
|
16
|
+
|
|
17
|
+
[source]
|
|
18
|
+
----
|
|
19
|
+
output_dir/
|
|
20
|
+
index.html # HTML shell with external asset references
|
|
21
|
+
docbook.data.json # Full document data (TOC, content, index) as JSON
|
|
22
|
+
assets/
|
|
23
|
+
app.css # Compiled Vue SPA stylesheet
|
|
24
|
+
app.iife.js # Compiled Vue SPA JavaScript bundle
|
|
25
|
+
----
|
|
26
|
+
|
|
27
|
+
Images are **not** copied to the output directory. Instead, they are referenced by their resolved file paths relative to the source document. This means the source image directories must remain accessible at their original locations (or be served by the web server).
|
|
28
|
+
|
|
29
|
+
## How It Works
|
|
30
|
+
|
|
31
|
+
In directory mode, the `Output::Html` class performs these steps:
|
|
32
|
+
|
|
33
|
+
. **Serialize data** -- The full `DocbookOutput` model is serialized to JSON and written to `docbook.data.json`
|
|
34
|
+
. **Render template** -- The Liquid template is rendered with `assets_inline: false`, producing external `<link>` and `<script>` references
|
|
35
|
+
. **Replace placeholders** -- The `[[DOCBOOK_DATA]]` placeholders are replaced with `null` comments since data is loaded separately
|
|
36
|
+
. **Write files** -- The CLI copies frontend assets to `assets/` and writes the HTML to `index.html`
|
|
37
|
+
|
|
38
|
+
## Asset References
|
|
39
|
+
|
|
40
|
+
The template partials use the `assets_inline` flag to switch between inline and external references:
|
|
41
|
+
|
|
42
|
+
**Head partial (`_head.liquid`):**
|
|
43
|
+
|
|
44
|
+
[source,html]
|
|
45
|
+
----
|
|
46
|
+
<!-- Directory mode: external CSS -->
|
|
47
|
+
{% if assets_inline %}
|
|
48
|
+
<style>{{ app_css }}</style>
|
|
49
|
+
{% else %}
|
|
50
|
+
<link rel="stylesheet" href="{{ base_url }}/assets/app.css">
|
|
51
|
+
{% endif %}
|
|
52
|
+
----
|
|
53
|
+
|
|
54
|
+
**Scripts partial (`_scripts.liquid`):**
|
|
55
|
+
|
|
56
|
+
[source,html]
|
|
57
|
+
----
|
|
58
|
+
<!-- Directory mode: external JS -->
|
|
59
|
+
{% if assets_inline %}
|
|
60
|
+
<script>{{ app_js }}</script>
|
|
61
|
+
{% else %}
|
|
62
|
+
<script src="{{ base_url }}/assets/app.iife.js"></script>
|
|
63
|
+
{% endif %}
|
|
64
|
+
----
|
|
65
|
+
|
|
66
|
+
## Data Loading
|
|
67
|
+
|
|
68
|
+
In directory mode, the Vue SPA's `documentStore` does not find `window.DOCBOOK_DATA` and falls back to fetching `docbook.data.json` via HTTP:
|
|
69
|
+
|
|
70
|
+
[source,typescript]
|
|
71
|
+
----
|
|
72
|
+
// From documentStore.ts
|
|
73
|
+
function loadFromWindow(): Promise<void> {
|
|
74
|
+
const inlineData = (window as any).DOCBOOK_DATA
|
|
75
|
+
if (inlineData && inlineData !== null) {
|
|
76
|
+
// Single file mode: data is already in window
|
|
77
|
+
documentData.value = data as DocumentData
|
|
78
|
+
return Promise.resolve()
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Directory mode: fetch from JSON file
|
|
82
|
+
return fetch('docbook.data.json')
|
|
83
|
+
.then(res => res.json())
|
|
84
|
+
.then(data => {
|
|
85
|
+
documentData.value = data as DocumentData
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
----
|
|
89
|
+
|
|
90
|
+
The `docbook.data.json` file contains the complete serialized `DocbookOutput` model, including the TOC tree, numbering map, all section content, and the generated index.
|
|
91
|
+
|
|
92
|
+
## Image Handling
|
|
93
|
+
|
|
94
|
+
In directory mode, images are referenced by file path rather than base64:
|
|
95
|
+
|
|
96
|
+
[source,ruby]
|
|
97
|
+
----
|
|
98
|
+
def process_image(fileref)
|
|
99
|
+
if @output_mode == :single_file
|
|
100
|
+
embed_image_base64(fileref)
|
|
101
|
+
else
|
|
102
|
+
find_file_path(fileref) || fileref
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
----
|
|
106
|
+
|
|
107
|
+
The `find_file_path` method searches the document's base path and parent directories to resolve image file paths. It tries common prefixes (`""`, `"resources/"`, `"../resources/"`) to accommodate various project structures.
|
|
108
|
+
|
|
109
|
+
## Use Case
|
|
110
|
+
|
|
111
|
+
Directory mode is designed for:
|
|
112
|
+
|
|
113
|
+
- **Web serving** -- Deploy to any static file server (nginx, Apache, S3, GitHub Pages)
|
|
114
|
+
- **Large documents** -- Avoids the size overhead of base64-encoded images
|
|
115
|
+
- **CDN delivery** -- Assets can be cached independently by browsers
|
|
116
|
+
- **Development** -- Faster rebuilds since only `docbook.data.json` changes when content changes
|
|
117
|
+
|
|
118
|
+
## CLI Usage
|
|
119
|
+
|
|
120
|
+
[source,bash]
|
|
121
|
+
----
|
|
122
|
+
# Directory mode requires an output directory
|
|
123
|
+
docbook to-html document.xml -o ./output_dir --output-type directory
|
|
124
|
+
----
|
|
125
|
+
|
|
126
|
+
The CLI copies frontend assets automatically:
|
|
127
|
+
|
|
128
|
+
[source,ruby]
|
|
129
|
+
----
|
|
130
|
+
# From cli.rb
|
|
131
|
+
def write_output(content, output_path, output_type)
|
|
132
|
+
if output_type == :directory
|
|
133
|
+
FileUtils.mkdir_p(output_path)
|
|
134
|
+
File.write(File.join(output_path, "index.html"), content)
|
|
135
|
+
|
|
136
|
+
assets_dir = File.join(output_path, "assets")
|
|
137
|
+
FileUtils.mkdir_p(assets_dir)
|
|
138
|
+
FileUtils.cp(File.join(FRONTEND_ROOT, "app.css"), File.join(assets_dir, "app.css"))
|
|
139
|
+
FileUtils.cp(File.join(FRONTEND_ROOT, "app.iife.js"), File.join(assets_dir, "app.iife.js"))
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
----
|
|
143
|
+
|
|
144
|
+
## Programmatic Usage
|
|
145
|
+
|
|
146
|
+
[source,ruby]
|
|
147
|
+
----
|
|
148
|
+
require "docbook"
|
|
149
|
+
|
|
150
|
+
document = Docbook::Document.from_xml(File.read("book.xml"))
|
|
151
|
+
xref_resolver = Docbook::XrefResolver.new(document).resolve!
|
|
152
|
+
base_path = File.dirname(File.expand_path("book.xml"))
|
|
153
|
+
output_dir = "/path/to/output"
|
|
154
|
+
|
|
155
|
+
html = Docbook::Output::Html.new(
|
|
156
|
+
document,
|
|
157
|
+
xref_resolver: xref_resolver,
|
|
158
|
+
output_mode: :directory,
|
|
159
|
+
base_path: base_path,
|
|
160
|
+
output_path: output_dir
|
|
161
|
+
).to_html
|
|
162
|
+
|
|
163
|
+
File.write(File.join(output_dir, "index.html"), html)
|
|
164
|
+
----
|
|
165
|
+
|
|
166
|
+
## Template Rendering Details
|
|
167
|
+
|
|
168
|
+
The Liquid template is rendered with these variables in directory mode:
|
|
169
|
+
|
|
170
|
+
[cols="1,2,3"]
|
|
171
|
+
|===
|
|
172
|
+
| Variable | Value | Purpose
|
|
173
|
+
|
|
174
|
+
| `docbook_title` | Document title | Page `<title>` element
|
|
175
|
+
| `base_url` | `"."` (current directory) | Relative URL base for asset references
|
|
176
|
+
| `assets_inline` | `false` | Controls whether CSS/JS are inlined or linked
|
|
177
|
+
| `app_css` | Contents of `frontend/dist/app.css` | Used only for template rendering (file is also copied to `assets/`)
|
|
178
|
+
| `app_js` | Contents of `frontend/dist/app.iife.js` | Used only for template rendering (file is also copied to `assets/`)
|
|
179
|
+
| `data_url` | `"docbook.data.json"` | URL the SPA fetches for document data
|
|
180
|
+
|===
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: HTML Output
|
|
4
|
+
parent: Features
|
|
5
|
+
nav_order: 1
|
|
6
|
+
has_children: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# HTML Output
|
|
10
|
+
|
|
11
|
+
The HTML output system converts parsed DocBook XML into an interactive web publication. It uses a two-stage rendering approach: a Ruby-based data extraction layer that builds structured JSON data, and a Vue 3 single-page application (SPA) that renders the content client-side.
|
|
12
|
+
|
|
13
|
+
## How It Works
|
|
14
|
+
|
|
15
|
+
The `Docbook::Output::Html` class orchestrates the entire output pipeline:
|
|
16
|
+
|
|
17
|
+
. **Section Collection** -- Traverses the document tree to build a `SectionData` hierarchy (the TOC)
|
|
18
|
+
. **Numbering** -- `NumberingBuilder` assigns formatted numbers to each section
|
|
19
|
+
. **Content Extraction** -- For each section, the element tree is walked to produce `ContentBlock` trees
|
|
20
|
+
. **Index Collection** -- `IndexCollector` gathers all `indexterm` elements
|
|
21
|
+
. **Data Assembly** -- Everything is packaged into a `DocbookOutput` model
|
|
22
|
+
. **Template Rendering** -- A Liquid template produces the HTML shell with placeholders
|
|
23
|
+
|
|
24
|
+
## Template System
|
|
25
|
+
|
|
26
|
+
The HTML shell is generated using https://github.com/Shopify/liquid[Liquid templates] stored in `lib/docbook/templates/`. The main template (`document.html.liquid`) includes two partials:
|
|
27
|
+
|
|
28
|
+
- `_head.liquid` -- Prism.js CSS for syntax highlighting, Google Fonts (Inter, Merriweather, JetBrains Mono), Tailwind CSS, and the compiled app CSS
|
|
29
|
+
- `_scripts.liquid` -- Prism.js core with autoloader for additional languages, and the compiled Vue SPA JavaScript
|
|
30
|
+
|
|
31
|
+
The template uses four placeholder tokens that are replaced during rendering:
|
|
32
|
+
|
|
33
|
+
- `[[DOCBOOK_DATA]]` -- Document title and metadata
|
|
34
|
+
- `[[DOCBOOK_TOC]]` -- TOC tree and numbering map
|
|
35
|
+
- `[[DOCBOOK_CONTENT]]` -- Section content blocks
|
|
36
|
+
- `[[DOCBOOK_INDEX]]` -- Generated index data
|
|
37
|
+
|
|
38
|
+
## Vue 3 SPA Frontend
|
|
39
|
+
|
|
40
|
+
The frontend is a Vue 3 application built with Vite and TypeScript, located in `frontend/`. It is compiled to `frontend/dist/` as a single IIFE bundle (`app.iife.js`) and a stylesheet (`app.css`).
|
|
41
|
+
|
|
42
|
+
### Key Features
|
|
43
|
+
|
|
44
|
+
- **Table of Contents** -- Recursive sidebar navigation with collapsible tree items, type badges (Pt, Ch, App, Gl, Bib, Idx, Pref, Ref), and section numbering
|
|
45
|
+
- **Full-Text Search** -- Powered by https://github.com/nextapps-de/flexsearch[FlexSearch] with forward tokenization, persisted to IndexedDB for instant reloads
|
|
46
|
+
- **Four Themes** -- Day (white), Sepia (warm amber), Night (dark gray), and OLED (pure black) -- each with proper dark mode Tailwind classes
|
|
47
|
+
- **Reading Modes** -- Scroll (continuous), Page (paginated), Chapter (one chapter at a time), and Cards (reference entry cards)
|
|
48
|
+
- **Syntax Highlighting** -- Prism.js with the Tomorrow Night theme and autoloader for on-demand language support
|
|
49
|
+
- **Display Settings** -- Configurable font size (12-32px), font weight (300-700), line height (1.2-2.0), and margins (16-96px), persisted to localStorage
|
|
50
|
+
- **Responsive Design** -- Collapsible sidebar, mobile-friendly navigation, and adaptive content width
|
|
51
|
+
|
|
52
|
+
### Frontend Components
|
|
53
|
+
|
|
54
|
+
[cols="1,3"]
|
|
55
|
+
|===
|
|
56
|
+
| Component | Purpose
|
|
57
|
+
|
|
58
|
+
| `App.vue` | Root component, loads document data and initializes stores
|
|
59
|
+
| `EbookContainer.vue` | Main layout container with theme application and CSS variables
|
|
60
|
+
| `AppSidebar.vue` | Table of contents sidebar with recursive tree
|
|
61
|
+
| `TocTreeItem.vue` | Recursive TOC item with expand/collapse and type badges
|
|
62
|
+
| `ContentRenderer.vue` | Renders `ContentBlock` trees into HTML
|
|
63
|
+
| `BlockRenderer.vue` | Renders individual `ContentBlock` items (paragraphs, code, lists, etc.)
|
|
64
|
+
| `SectionContent.vue` | Section wrapper with heading and numbering
|
|
65
|
+
| `PartSection.vue` | Part-specific rendering with Roman numeral prefix
|
|
66
|
+
| `ChapterSection.vue` | Chapter-specific rendering with Arabic numeral prefix
|
|
67
|
+
| `AppendixSection.vue` | Appendix-specific rendering with Alpha prefix
|
|
68
|
+
| `ReferenceEntry.vue` | Reference page entry with badge, name, and description sections
|
|
69
|
+
| `EbookTopBar.vue` | Top navigation bar with search and settings toggles
|
|
70
|
+
| `SearchModal.vue` | Full-text search modal with FlexSearch integration
|
|
71
|
+
| `SettingsPanel.vue` | Display settings panel (theme, font, size, margins)
|
|
72
|
+
|===
|
|
73
|
+
|
|
74
|
+
## Output Modes
|
|
75
|
+
|
|
76
|
+
The gem supports two output modes, chosen by the `output_mode` parameter:
|
|
77
|
+
|
|
78
|
+
### Single File Mode (`:single_file`)
|
|
79
|
+
|
|
80
|
+
All assets are inlined into one self-contained HTML file. See <<single-file-mode,Single File Mode>> for details.
|
|
81
|
+
|
|
82
|
+
### Directory Mode (`:directory`)
|
|
83
|
+
|
|
84
|
+
A directory of files suitable for web serving. See <<directory-mode,Directory Mode>> for details.
|
|
85
|
+
|
|
86
|
+
## Child Pages
|
|
87
|
+
|
|
88
|
+
- <<single-file-mode,Single File Mode>> -- Self-contained HTML with base64 images
|
|
89
|
+
- <<directory-mode,Directory Mode>> -- Multi-file output for web serving
|
|
90
|
+
- <<data-model,Output Data Model>> -- JSON data structures and ContentBlock types
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Single File Mode
|
|
4
|
+
parent: HTML Output
|
|
5
|
+
grand_parent: Features
|
|
6
|
+
nav_order: 1
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Single File Mode
|
|
10
|
+
|
|
11
|
+
Single file mode (`output_mode: :single_file`) produces a single, self-contained HTML file with all assets inlined. This is the default output mode and is ideal for distributing documents that can be opened directly in any browser, including via the `file://` protocol.
|
|
12
|
+
|
|
13
|
+
## How It Works
|
|
14
|
+
|
|
15
|
+
When single file mode is active, the `Output::Html` class inlines every asset directly into the HTML:
|
|
16
|
+
|
|
17
|
+
. **CSS** -- The compiled `app.css` from `frontend/dist/` is injected inline via a `<style>` tag
|
|
18
|
+
. **JavaScript** -- The compiled `app.iife.js` from `frontend/dist/` is injected inline via a `<script>` tag
|
|
19
|
+
. **Fonts** -- Google Fonts (Inter, Merriweather, JetBrains Mono) are loaded from CDN in `_head.liquid`
|
|
20
|
+
. **JSON Data** -- All document data (TOC, content, index) is serialized to JSON and injected via `[[DOCBOOK_DATA]]` placeholders, with `</script>` tags escaped to `<\/script>`
|
|
21
|
+
|
|
22
|
+
The Liquid template is rendered with `assets_inline: true`, which causes the partials to inline assets rather than reference external files.
|
|
23
|
+
|
|
24
|
+
## Image Embedding
|
|
25
|
+
|
|
26
|
+
Images are embedded as base64 data URIs. The `process_image` method in `Output::Html` handles this:
|
|
27
|
+
|
|
28
|
+
[source,ruby]
|
|
29
|
+
----
|
|
30
|
+
# When output_mode is :single_file, images are base64-encoded
|
|
31
|
+
def process_image(fileref)
|
|
32
|
+
if @output_mode == :single_file
|
|
33
|
+
embed_image_base64(fileref)
|
|
34
|
+
else
|
|
35
|
+
find_file_path(fileref) || fileref
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def embed_image_base64(fileref)
|
|
40
|
+
full_path = find_file_path(fileref)
|
|
41
|
+
data = File.binread(full_path)
|
|
42
|
+
mime = Marcel::MimeType.for(data) # MIME detection via Marcel
|
|
43
|
+
encoded = Base64.strict_encode64(data)
|
|
44
|
+
"data:#{mime};base64,#{encoded}"
|
|
45
|
+
end
|
|
46
|
+
----
|
|
47
|
+
|
|
48
|
+
The MIME type is detected automatically using the https://github.com/rails/marcel[Marcel] gem, which examines the file's magic bytes rather than relying on file extensions. This ensures correct MIME types even when file extensions are missing or incorrect.
|
|
49
|
+
|
|
50
|
+
Image paths are resolved by searching the document's base path and its parent directories, trying common prefixes like `resources/` and `../resources/`. This accommodates the various directory structures used in DocBook projects.
|
|
51
|
+
|
|
52
|
+
## Data Injection
|
|
53
|
+
|
|
54
|
+
The template contains four placeholder tokens that are replaced with inline JSON:
|
|
55
|
+
|
|
56
|
+
[source,html]
|
|
57
|
+
----
|
|
58
|
+
<script>
|
|
59
|
+
window.DOCBOOK_DATA = Object.assign([[DOCBOOK_DATA]], {
|
|
60
|
+
toc: [[DOCBOOK_TOC]],
|
|
61
|
+
content: [[DOCBOOK_CONTENT]],
|
|
62
|
+
index: [[DOCBOOK_INDEX]]
|
|
63
|
+
});
|
|
64
|
+
</script>
|
|
65
|
+
----
|
|
66
|
+
|
|
67
|
+
In single file mode, the placeholders are replaced with actual JSON data. The Vue SPA's `documentStore` detects `window.DOCBOOK_DATA` and loads the data synchronously without any network requests.
|
|
68
|
+
|
|
69
|
+
## Use Case
|
|
70
|
+
|
|
71
|
+
Single file mode is designed for:
|
|
72
|
+
|
|
73
|
+
- **Document distribution** -- Send a single HTML file via email or file share
|
|
74
|
+
- **Offline reading** -- Works without a web server; open directly from the filesystem
|
|
75
|
+
- **Archival** -- Self-contained documents with no external dependencies (except CDN fonts)
|
|
76
|
+
- **Email attachments** -- One file to attach, no directory structures to manage
|
|
77
|
+
|
|
78
|
+
## CLI Usage
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Default: single file mode, output to stdout
|
|
82
|
+
docbook to-html document.xml
|
|
83
|
+
|
|
84
|
+
# Write to a file
|
|
85
|
+
docbook to-html document.xml -o output.html
|
|
86
|
+
|
|
87
|
+
# Explicit single file mode
|
|
88
|
+
docbook to-html document.xml -o output.html --output-type single_file
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Programmatic Usage
|
|
92
|
+
|
|
93
|
+
[source,ruby]
|
|
94
|
+
----
|
|
95
|
+
require "docbook"
|
|
96
|
+
|
|
97
|
+
document = Docbook::Document.from_xml(File.read("book.xml"))
|
|
98
|
+
xref_resolver = Docbook::XrefResolver.new(document).resolve!
|
|
99
|
+
base_path = File.dirname(File.expand_path("book.xml"))
|
|
100
|
+
|
|
101
|
+
html = Docbook::Output::Html.new(
|
|
102
|
+
document,
|
|
103
|
+
xref_resolver: xref_resolver,
|
|
104
|
+
output_mode: :single_file,
|
|
105
|
+
base_path: base_path
|
|
106
|
+
).to_html
|
|
107
|
+
|
|
108
|
+
File.write("book.html", html)
|
|
109
|
+
----
|
|
110
|
+
|
|
111
|
+
## Template Rendering Details
|
|
112
|
+
|
|
113
|
+
The Liquid template is rendered with these variables in single file mode:
|
|
114
|
+
|
|
115
|
+
[cols="1,2,3"]
|
|
116
|
+
|===
|
|
117
|
+
| Variable | Value | Purpose
|
|
118
|
+
|
|
119
|
+
| `docbook_title` | Document title | Page `<title>` element
|
|
120
|
+
| `base_url` | `""` (empty string) | Relative URL base (not needed for single file)
|
|
121
|
+
| `assets_inline` | `true` | Controls whether CSS/JS are inlined or linked
|
|
122
|
+
| `app_css` | Contents of `frontend/dist/app.css` | Inlined as `<style>` tag
|
|
123
|
+
| `app_js` | Contents of `frontend/dist/app.iife.js` | Inlined as `<script>` tag
|
|
124
|
+
| `data_url` | Not used | Only relevant for directory mode
|
|
125
|
+
|===
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Index Generation
|
|
4
|
+
parent: Features
|
|
5
|
+
nav_order: 5
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Index Generation
|
|
9
|
+
|
|
10
|
+
The index generation system collects `indexterm` elements from throughout the document, groups them by first letter, sorts them, and produces a structured index that the Vue SPA renders as a navigable back-of-book index.
|
|
11
|
+
|
|
12
|
+
## Architecture
|
|
13
|
+
|
|
14
|
+
Index generation uses two classes working in sequence:
|
|
15
|
+
|
|
16
|
+
- **`IndexCollector`** -- Traverses the entire document tree to collect `indexterm` elements
|
|
17
|
+
- **`IndexGenerator`** -- Groups collected terms by letter, sorts them, and builds the final index structure
|
|
18
|
+
|
|
19
|
+
## IndexCollector
|
|
20
|
+
|
|
21
|
+
The `IndexCollector` performs a recursive traversal of the document, visiting every element type that can contain `indexterm` elements.
|
|
22
|
+
|
|
23
|
+
### Traversal Scope
|
|
24
|
+
|
|
25
|
+
The collector traverses all major structural elements:
|
|
26
|
+
|
|
27
|
+
[cols="1,2"]
|
|
28
|
+
|===
|
|
29
|
+
| Element | Traversed Children
|
|
30
|
+
|
|
31
|
+
| `Book` | parts, chapters, appendices, prefaces, glossary, bibliography, index, setindex
|
|
32
|
+
| `Part` | parts, chapters, appendices, references, prefaces, glossary, bibliography, index
|
|
33
|
+
| `Article` | sections, glossary, bibliography, index
|
|
34
|
+
| `Chapter` | sections, simplesects, paras, indexterms
|
|
35
|
+
| `Appendix` | sections, simplesects, paras, indexterms
|
|
36
|
+
| `Section` | sections, simplesects, paras, indexterms
|
|
37
|
+
| `SimpleSect` | paras, indexterms
|
|
38
|
+
| `RefEntry` | refsections
|
|
39
|
+
| `RefSection` | paras, indexterms
|
|
40
|
+
| `ListItem` | paras, simplesects, indexterms
|
|
41
|
+
| `Entry` (table) | paras, indexterms
|
|
42
|
+
| `Para` | mixed content (handles inline indexterms)
|
|
43
|
+
|===
|
|
44
|
+
|
|
45
|
+
### Term Extraction
|
|
46
|
+
|
|
47
|
+
For each `indexterm` found, the collector extracts:
|
|
48
|
+
|
|
49
|
+
[source,ruby]
|
|
50
|
+
----
|
|
51
|
+
term_info = {
|
|
52
|
+
primary: primary_text, # Required: primary term text
|
|
53
|
+
primary_sort: sort_key, # Sort key (lowercased or "SYMBOLS")
|
|
54
|
+
secondary: secondaries.first, # Optional: secondary term
|
|
55
|
+
tertiary: tertiaries.first, # Optional: tertiary term
|
|
56
|
+
sees: sees, # "see" cross-references
|
|
57
|
+
see_alsos: see_alsos, # "see also" cross-references
|
|
58
|
+
type: indexterm.type, # Optional type filter
|
|
59
|
+
section_id: section_info[:id], # xml:id of containing section
|
|
60
|
+
section_title: section_info[:title] # Title of containing section
|
|
61
|
+
}
|
|
62
|
+
----
|
|
63
|
+
----
|
|
64
|
+
|
|
65
|
+
### Sort Keys
|
|
66
|
+
|
|
67
|
+
Sort keys determine grouping and ordering:
|
|
68
|
+
|
|
69
|
+
- **Non-alphabetic terms** -- Terms starting with symbols or having `class="token"` are grouped under `SYMBOLS`
|
|
70
|
+
- **Alphabetic terms** -- Leading punctuation is stripped and the text is lowercased
|
|
71
|
+
|
|
72
|
+
[source,ruby]
|
|
73
|
+
----
|
|
74
|
+
def sort_key(text, indexterm)
|
|
75
|
+
return "SYMBOLS" if indexterm.class_value == "token" || text.start_with?("@")
|
|
76
|
+
text.gsub(/^[^a-zA-Z]+/, "").downcase
|
|
77
|
+
end
|
|
78
|
+
----
|
|
79
|
+
----
|
|
80
|
+
|
|
81
|
+
## IndexGenerator
|
|
82
|
+
|
|
83
|
+
The `IndexGenerator` takes the collected terms and groups them:
|
|
84
|
+
|
|
85
|
+
### Grouping by Letter
|
|
86
|
+
|
|
87
|
+
Terms are grouped by the first letter of their sort key:
|
|
88
|
+
|
|
89
|
+
[source,ruby]
|
|
90
|
+
----
|
|
91
|
+
def group_by_letter
|
|
92
|
+
result = {}
|
|
93
|
+
@index_terms.each do |term|
|
|
94
|
+
letter = letter_for(term[:primary_sort])
|
|
95
|
+
result[letter] ||= []
|
|
96
|
+
result[letter] << term
|
|
97
|
+
end
|
|
98
|
+
result
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def letter_for(sort_key)
|
|
102
|
+
return "SYMBOLS" if sort_key == "SYMBOLS" || sort_key.start_with?("@")
|
|
103
|
+
first_char = sort_key.chars.find(&:letter?) || sort_key[0] || ""
|
|
104
|
+
first_char.upcase
|
|
105
|
+
end
|
|
106
|
+
----
|
|
107
|
+
----
|
|
108
|
+
|
|
109
|
+
### Sorting
|
|
110
|
+
|
|
111
|
+
Within each letter group, terms are sorted by primary sort key and then by secondary term:
|
|
112
|
+
|
|
113
|
+
[source,ruby]
|
|
114
|
+
----
|
|
115
|
+
def sort_entries(terms)
|
|
116
|
+
terms.sort_by { |t| [t[:primary_sort], t[:secondary].to_s] }
|
|
117
|
+
end
|
|
118
|
+
----
|
|
119
|
+
----
|
|
120
|
+
|
|
121
|
+
The `SYMBOLS` group sorts first by using `"{"` (ASCII after "Z") as its sort key:
|
|
122
|
+
|
|
123
|
+
[source,ruby]
|
|
124
|
+
----
|
|
125
|
+
by_letter.sort_by { |letter, _| letter == "SYMBOLS" ? "{" : letter.downcase }
|
|
126
|
+
----
|
|
127
|
+
----
|
|
128
|
+
|
|
129
|
+
## Index Model
|
|
130
|
+
|
|
131
|
+
The final index is structured as:
|
|
132
|
+
|
|
133
|
+
[source]
|
|
134
|
+
----
|
|
135
|
+
Index
|
|
136
|
+
title: "Index"
|
|
137
|
+
type: nil (or type filter)
|
|
138
|
+
groups:
|
|
139
|
+
- IndexGroup (letter: "A")
|
|
140
|
+
entries:
|
|
141
|
+
- IndexTerm (primary: "Apple", section_id: "fruit-sec", ...)
|
|
142
|
+
- IndexTerm (primary: "Application", secondary: "web", ...)
|
|
143
|
+
- IndexGroup (letter: "B")
|
|
144
|
+
entries: [...]
|
|
145
|
+
- IndexGroup (letter: "SYMBOLS")
|
|
146
|
+
entries:
|
|
147
|
+
- IndexTerm (primary: "@example", sort_as: "SYMBOLS", ...)
|
|
148
|
+
----
|
|
149
|
+
----
|
|
150
|
+
|
|
151
|
+
## Type Filtering
|
|
152
|
+
|
|
153
|
+
The DocBook `index` element supports a `type` attribute for creating multiple specialized indexes. When an `index` element has a `type`, the builder filters `indexterm` elements to only include those with a matching `type`:
|
|
154
|
+
|
|
155
|
+
[source,ruby]
|
|
156
|
+
----
|
|
157
|
+
def build_index_content(index_element, all_index_terms)
|
|
158
|
+
index_type = index_element.type
|
|
159
|
+
filtered_terms = all_index_terms.select { |t| t[:type] == index_type }
|
|
160
|
+
# ...
|
|
161
|
+
end
|
|
162
|
+
----
|
|
163
|
+
----
|
|
164
|
+
|
|
165
|
+
## Cross-References
|
|
166
|
+
|
|
167
|
+
Index terms support two cross-reference mechanisms:
|
|
168
|
+
|
|
169
|
+
- **`see`** -- Directs the reader to a different primary term ("see [term]")
|
|
170
|
+
- **`seealso`** -- Suggests additional related terms ("see also [term]")
|
|
171
|
+
|
|
172
|
+
These are collected from `see` and `seealso` child elements within `indexterm`:
|
|
173
|
+
|
|
174
|
+
[source,xml]
|
|
175
|
+
----
|
|
176
|
+
<indexterm>
|
|
177
|
+
<primary>cars</primary>
|
|
178
|
+
<see>automobiles</see>
|
|
179
|
+
</indexterm>
|
|
180
|
+
|
|
181
|
+
<indexterm>
|
|
182
|
+
<primary>automobiles</primary>
|
|
183
|
+
<secondary>electric</secondary>
|
|
184
|
+
<seealso>hybrid vehicles</seealso>
|
|
185
|
+
</indexterm>
|
|
186
|
+
----
|
|
187
|
+
|
|
188
|
+
## Index Content Rendering
|
|
189
|
+
|
|
190
|
+
The index is rendered in the Vue SPA using `ContentBlock` trees with dedicated block types:
|
|
191
|
+
|
|
192
|
+
- `index_section` -- Container for an index section
|
|
193
|
+
- `index_letter` -- Letter group heading with child entries
|
|
194
|
+
- `index_entry` -- Individual term with primary text
|
|
195
|
+
- `index_reference` -- Link to the section where the term appears
|
|
196
|
+
- `index_see` -- "see" cross-reference
|
|
197
|
+
- `index_see_also` -- "see also" cross-reference
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Features
|
|
4
|
+
nav_order: 4
|
|
5
|
+
has_children: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Features
|
|
9
|
+
|
|
10
|
+
The Metanorma DocBook gem provides a complete pipeline for converting DocBook XML documents into modern, interactive HTML publications. It parses DocBook XML through a typed element model, resolves cross-references and XIncludes, and produces structured data consumed by a Vue 3 single-page application frontend.
|
|
11
|
+
|
|
12
|
+
## Feature Overview
|
|
13
|
+
|
|
14
|
+
[cols="3,4,5"]
|
|
15
|
+
|===
|
|
16
|
+
| Feature | Description | Details
|
|
17
|
+
|
|
18
|
+
| <<html-output/index,HTML Output>>
|
|
19
|
+
| Converts DocBook XML to interactive HTML with a Vue 3 SPA frontend, supporting both single-file and directory output modes.
|
|
20
|
+
| Two modes: *single file* (self-contained, base64 images) and *directory* (multi-file, web-serving ready)
|
|
21
|
+
|
|
22
|
+
| <<xinclude/index,XInclude Resolution>>
|
|
23
|
+
| Resolves `xi:include` elements for modular document composition, supporting both XML and text parsing modes with advanced filtering.
|
|
24
|
+
| Custom iterative resolver with `search=`, `line=`, and `char=` fragid schemes
|
|
25
|
+
|
|
26
|
+
| <<numbering,Section Numbering>>
|
|
27
|
+
| Automatic numbering of Parts (Roman), Chapters (Arabic), Sections (hierarchical), and Appendices (Alpha) with proper scoping.
|
|
28
|
+
| `NumberingBuilder` with per-part chapter scoping and hierarchical dot notation
|
|
29
|
+
|
|
30
|
+
| <<toc-generation,TOC Generation>>
|
|
31
|
+
| Builds a recursive tree of document sections with type metadata, numbering, and navigation badges.
|
|
32
|
+
| `SectionData` tree with type badges (Pt, Ch, App, Gl, Bib, Idx, Pref, Ref)
|
|
33
|
+
|
|
34
|
+
| <<index-generation,Index Generation>>
|
|
35
|
+
| Collects `indexterm` elements throughout the document and generates a grouped, sorted index with cross-references.
|
|
36
|
+
| `IndexCollector` + `IndexGenerator` with `see`/`seealso` support and SYMBOLS grouping
|
|
37
|
+
|
|
38
|
+
| <<element-coverage,Element Coverage>>
|
|
39
|
+
| Comprehensive support for 157 DocBook element classes organized across 20+ categories.
|
|
40
|
+
| Structural, metadata, block, list, link, inline, media, table, admonition, bibliography, glossary, index, and more
|
|
41
|
+
|===
|
|
42
|
+
|
|
43
|
+
## Architecture
|
|
44
|
+
|
|
45
|
+
The processing pipeline follows these stages:
|
|
46
|
+
|
|
47
|
+
. **Parse** -- DocBook XML is parsed into Lutaml::Model-based element classes (`Docbook::Document.from_xml`)
|
|
48
|
+
. **Resolve XIncludes** -- `XIncludeResolver` replaces `xi:include` elements iteratively, handling nested includes
|
|
49
|
+
. **Resolve XRefs** -- `XrefResolver` builds an O(1) lookup map of `xml:id` to element titles
|
|
50
|
+
. **Build Output Data** -- `Output::Html` traverses the element tree to produce a `DocbookOutput` model containing:
|
|
51
|
+
* `Toc` -- section tree with numbering
|
|
52
|
+
* `ContentData` -- section content as `ContentBlock` trees
|
|
53
|
+
* `Index` -- grouped index entries
|
|
54
|
+
. **Render** -- A Liquid template produces the HTML shell, and the Vue 3 SPA renders the content client-side
|
|
55
|
+
|
|
56
|
+
## Child Pages
|
|
57
|
+
|
|
58
|
+
- <<html-output/index,HTML Output>> -- Single-file and directory output modes, data model
|
|
59
|
+
- <<xinclude/index,XInclude Resolution>> -- XML includes, text includes, fragid schemes
|
|
60
|
+
- <<numbering,Section Numbering>> -- Roman, Arabic, hierarchical, and Alpha numbering
|
|
61
|
+
- <<toc-generation,TOC Generation>> -- Table of contents tree structure and rendering
|
|
62
|
+
- <<index-generation,Index Generation>> -- Index collection, grouping, and cross-references
|
|
63
|
+
- <<element-coverage,Element Coverage>> -- Full list of supported DocBook element classes
|