coradoc-html 1.1.16 → 1.1.17
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/lib/coradoc/html/converter_base.rb +1 -1
- data/lib/coradoc/html/drop/block_drop.rb +22 -2
- data/lib/coradoc/html/drop/drop_factory.rb +19 -19
- data/lib/coradoc/html/drop.rb +2 -2
- data/lib/coradoc/html/frontmatter_meta.rb +159 -0
- data/lib/coradoc/html/input.rb +1 -1
- data/lib/coradoc/html/layout_renderer.rb +33 -2
- data/lib/coradoc/html/output.rb +1 -1
- data/lib/coradoc/html/spa.rb +1 -1
- data/lib/coradoc/html/static.rb +1 -1
- data/lib/coradoc/html/transform/from_core_model.rb +1 -1
- data/lib/coradoc/html/transform/to_core_model.rb +1 -1
- data/lib/coradoc/html/version.rb +1 -1
- data/lib/coradoc/html.rb +7 -4
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d5c1e5cd6e38250709afed5441270974421958870420434743ec2dcc2080ef5d
|
|
4
|
+
data.tar.gz: 1b9c0d24cc15f6b535c85c993c0d8498ccaa572bec23be5e7f0bed4cd8661c93
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 86c7504af66e3a2933bc595eb1d6f6f628cfd07377a290927460ba94b96b44f4b2adf3b52bb26a2915c93527f6414ef0a35809810bfa2b1f8bd208633ea4c257
|
|
7
|
+
data.tar.gz: e0bcaf88a1d89d6b9e23ed71a7b7e8bd4f0a467780051db981e8d833a6e43fa3cf002d96efb5e7e6cdc17f368e0f8e5773f7df4af2d06f40bb85c94fde1c53b0
|
|
@@ -49,7 +49,7 @@ module Coradoc
|
|
|
49
49
|
|
|
50
50
|
def initialize(**options)
|
|
51
51
|
self.class.configuration_attributes.each do |name, default|
|
|
52
|
-
value = options.fetch(name) { default.
|
|
52
|
+
value = options.fetch(name) { default.is_a?(Proc) ? default.call : default }
|
|
53
53
|
public_send(:"#{name}=", value)
|
|
54
54
|
end
|
|
55
55
|
end
|
|
@@ -26,13 +26,25 @@ module Coradoc
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def text
|
|
29
|
-
if
|
|
30
|
-
Escape.escape_html(
|
|
29
|
+
if verbatim?
|
|
30
|
+
Escape.escape_html(stripped_text)
|
|
31
31
|
elsif resolved_semantic_type == :pass
|
|
32
32
|
@model.flat_text.to_s
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
def callouts
|
|
37
|
+
return [] unless verbatim?
|
|
38
|
+
|
|
39
|
+
@callouts ||= CoreModel::CalloutText.ordered(@model.callouts).map do |callout|
|
|
40
|
+
{ 'index' => callout.index, 'content' => Escape.escape_html(callout.content.to_s) }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def callouts?
|
|
45
|
+
!callouts.empty?
|
|
46
|
+
end
|
|
47
|
+
|
|
36
48
|
def hidden?
|
|
37
49
|
%i[comment reviewer].include?(resolved_semantic_type)
|
|
38
50
|
end
|
|
@@ -50,6 +62,14 @@ module Coradoc
|
|
|
50
62
|
def resolved_semantic_type
|
|
51
63
|
@resolved_semantic_type ||= @model.resolve_semantic_type || :paragraph
|
|
52
64
|
end
|
|
65
|
+
|
|
66
|
+
def verbatim?
|
|
67
|
+
%i[source_code literal listing].include?(resolved_semantic_type)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def stripped_text
|
|
71
|
+
CoreModel::CalloutText.strip_markers(@model.flat_text.to_s, @model.callouts)
|
|
72
|
+
end
|
|
53
73
|
end
|
|
54
74
|
|
|
55
75
|
DropFactory.register(CoreModel::Block, BlockDrop)
|
|
@@ -51,22 +51,22 @@ end
|
|
|
51
51
|
|
|
52
52
|
# Load all drops — each self-registers with DropFactory.
|
|
53
53
|
# Registration order doesn't matter (sorted by ancestor depth).
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
54
|
+
require_relative 'annotation_drop'
|
|
55
|
+
require_relative 'block_drop'
|
|
56
|
+
require_relative 'list_block_drop'
|
|
57
|
+
require_relative 'list_item_drop'
|
|
58
|
+
require_relative 'table_drop'
|
|
59
|
+
require_relative 'table_row_drop'
|
|
60
|
+
require_relative 'table_cell_drop'
|
|
61
|
+
require_relative 'image_drop'
|
|
62
|
+
require_relative 'inline_element_drop'
|
|
63
|
+
require_relative 'bibliography_entry_drop'
|
|
64
|
+
require_relative 'bibliography_drop'
|
|
65
|
+
require_relative 'toc_entry_drop'
|
|
66
|
+
require_relative 'toc_drop'
|
|
67
|
+
require_relative 'definition_item_drop'
|
|
68
|
+
require_relative 'definition_list_drop'
|
|
69
|
+
require_relative 'term_drop'
|
|
70
|
+
require_relative 'footnote_drop'
|
|
71
|
+
require_relative 'text_content_drop'
|
|
72
|
+
require_relative 'document_drop'
|
data/lib/coradoc/html/drop.rb
CHANGED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'nokogiri'
|
|
4
|
+
|
|
5
|
+
module Coradoc
|
|
6
|
+
module Html
|
|
7
|
+
# Single source of truth for FrontmatterBlock -> HTML `<meta>` and
|
|
8
|
+
# `<link>` tag mapping. (MECE: HTML-specific concerns live in the
|
|
9
|
+
# HTML gem; CoreModel has no knowledge of HTML.)
|
|
10
|
+
#
|
|
11
|
+
# The module produces a small data structure that layout templates
|
|
12
|
+
# and Nokogiri::HTML::Builder fallbacks both consume, so we never
|
|
13
|
+
# duplicate the mapping rule across output paths (DRY).
|
|
14
|
+
#
|
|
15
|
+
# Mapping table (single source of truth — extend here only):
|
|
16
|
+
#
|
|
17
|
+
# | Frontmatter key | Output |
|
|
18
|
+
# |-----------------------|-----------------------------------------|
|
|
19
|
+
# | title | <title> (caller decides title priority) |
|
|
20
|
+
# | author | <meta name="author"> |
|
|
21
|
+
# | description, excerpt | <meta name="description"> |
|
|
22
|
+
# | date | <meta name="date"> (ISO 8601) |
|
|
23
|
+
# | subject | <meta name="subject"> |
|
|
24
|
+
# | tags, categories | <meta name="keywords"> (comma-joined) |
|
|
25
|
+
# | $schema | <link rel="schema.X" href="..."> |
|
|
26
|
+
# | (any other scalar) | <meta name="<key>" content="<value>"> |
|
|
27
|
+
module FrontmatterMeta
|
|
28
|
+
Meta = Struct.new(:name, :content, keyword_init: true)
|
|
29
|
+
LinkTag = Struct.new(:rel, :href, keyword_init: true)
|
|
30
|
+
|
|
31
|
+
DESCRIPTION_KEYS = %w[description excerpt].freeze
|
|
32
|
+
KEYWORDS_KEYS = %w[tags categories].freeze
|
|
33
|
+
|
|
34
|
+
class << self
|
|
35
|
+
# Extract a meta-tag list and link-tag list from a
|
|
36
|
+
# FrontmatterBlock. `title` is returned separately so the caller
|
|
37
|
+
# can decide precedence (e.g., document title vs. frontmatter).
|
|
38
|
+
#
|
|
39
|
+
# @param block [Coradoc::CoreModel::FrontmatterBlock, nil]
|
|
40
|
+
# @return [Hash{Symbol=>Array<Meta>,Array<LinkTag>,String,nil}]
|
|
41
|
+
# { metas:, links:, title: }
|
|
42
|
+
def extract(block)
|
|
43
|
+
return empty_result unless block.is_a?(Coradoc::CoreModel::FrontmatterBlock)
|
|
44
|
+
|
|
45
|
+
data = block.data || {}
|
|
46
|
+
{
|
|
47
|
+
metas: build_metas(data),
|
|
48
|
+
links: build_links(block.schema),
|
|
49
|
+
title: scalar_value(data['title'])
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Emit meta + link tags into a Nokogiri head builder context.
|
|
54
|
+
def emit_into_builder(builder_doc, block)
|
|
55
|
+
data = extract(block)
|
|
56
|
+
Array(data[:metas]).each do |meta|
|
|
57
|
+
builder_doc.meta(name: meta.name, content: meta.content)
|
|
58
|
+
end
|
|
59
|
+
Array(data[:links]).each do |link|
|
|
60
|
+
builder_doc.link(rel: link.rel, href: link.href)
|
|
61
|
+
end
|
|
62
|
+
data
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def empty_result
|
|
68
|
+
{ metas: [], links: [], title: nil }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def build_metas(data)
|
|
72
|
+
metas = []
|
|
73
|
+
consumed = []
|
|
74
|
+
|
|
75
|
+
if (v = find_first_scalar(data, DESCRIPTION_KEYS))
|
|
76
|
+
metas << Meta.new(name: 'description', content: v)
|
|
77
|
+
consumed += DESCRIPTION_KEYS
|
|
78
|
+
end
|
|
79
|
+
if (v = find_first_array_as_csv(data, KEYWORDS_KEYS))
|
|
80
|
+
metas << Meta.new(name: 'keywords', content: v)
|
|
81
|
+
consumed += KEYWORDS_KEYS
|
|
82
|
+
end
|
|
83
|
+
if (v = find_first_scalar(data, %w[date]))
|
|
84
|
+
metas << Meta.new(name: 'date', content: v)
|
|
85
|
+
consumed << 'date'
|
|
86
|
+
end
|
|
87
|
+
if (v = find_first_scalar(data, %w[author]))
|
|
88
|
+
metas << Meta.new(name: 'author', content: v)
|
|
89
|
+
consumed << 'author'
|
|
90
|
+
end
|
|
91
|
+
if (v = find_first_scalar(data, %w[subject]))
|
|
92
|
+
metas << Meta.new(name: 'subject', content: v)
|
|
93
|
+
consumed << 'subject'
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
data.each do |key, value|
|
|
97
|
+
next if consumed.include?(key) || key == 'title'
|
|
98
|
+
|
|
99
|
+
content = scalar_value(value)
|
|
100
|
+
next if content.nil? || content.empty?
|
|
101
|
+
|
|
102
|
+
metas << Meta.new(name: key, content: content)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
metas
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def build_links(schema)
|
|
109
|
+
return [] unless schema && !schema.to_s.strip.empty?
|
|
110
|
+
|
|
111
|
+
[LinkTag.new(rel: 'schema.dublin_core', href: schema.to_s)]
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def find_first_scalar(data, keys)
|
|
115
|
+
keys.each do |k|
|
|
116
|
+
value = data[k]
|
|
117
|
+
next if value.nil?
|
|
118
|
+
|
|
119
|
+
str = scalar_value(value)
|
|
120
|
+
return str if str && !str.empty?
|
|
121
|
+
end
|
|
122
|
+
nil
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def find_first_array_as_csv(data, keys)
|
|
126
|
+
keys.each do |k|
|
|
127
|
+
value = data[k]
|
|
128
|
+
next if value.nil?
|
|
129
|
+
|
|
130
|
+
csv = array_to_csv(value)
|
|
131
|
+
return csv if csv && !csv.empty?
|
|
132
|
+
end
|
|
133
|
+
nil
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def scalar_value(value)
|
|
137
|
+
return nil if value.nil?
|
|
138
|
+
|
|
139
|
+
case value
|
|
140
|
+
when String then value
|
|
141
|
+
when Integer, Float, TrueClass, FalseClass then value.to_s
|
|
142
|
+
when Date, Time, DateTime then value.iso8601
|
|
143
|
+
when Symbol then value.to_s
|
|
144
|
+
when Array then array_to_csv(value)
|
|
145
|
+
when Hash then nil
|
|
146
|
+
else value.to_s
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def array_to_csv(value)
|
|
151
|
+
return nil unless value.is_a?(Array)
|
|
152
|
+
|
|
153
|
+
strings = value.map { |i| scalar_value(i) }.compact
|
|
154
|
+
strings.any? ? strings.join(', ') : nil
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
data/lib/coradoc/html/input.rb
CHANGED
|
@@ -53,7 +53,28 @@ module Coradoc
|
|
|
53
53
|
opts.lang || Config::DEFAULT_LANG
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
+
# Pull a leading FrontmatterBlock out of the document's children,
|
|
57
|
+
# if present. Returns nil when there isn't one.
|
|
58
|
+
def extract_frontmatter(document)
|
|
59
|
+
return nil unless document.is_a?(Coradoc::CoreModel::DocumentElement)
|
|
60
|
+
|
|
61
|
+
Array(document.children).find { |c| c.is_a?(Coradoc::CoreModel::FrontmatterBlock) }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Filter meta_tags so caller-supplied opts (author/description)
|
|
65
|
+
# take precedence and we never emit two <meta> tags with the same
|
|
66
|
+
# name. Single source of truth for the dedup rule (DRY): both the
|
|
67
|
+
# static and SPA layout paths route through here.
|
|
68
|
+
def dedup_meta_tags(metas, opts)
|
|
69
|
+
overridden = %w[author description].each_with_object([]) do |name, acc|
|
|
70
|
+
acc << name if opts.public_send(name)
|
|
71
|
+
end
|
|
72
|
+
metas.reject { |m| overridden.include?(m.name) }
|
|
73
|
+
end
|
|
74
|
+
|
|
56
75
|
def build_static_layout_data(document, body_html, opts)
|
|
76
|
+
frontmatter = extract_frontmatter(document)
|
|
77
|
+
fm_metas, fm_links = FrontmatterMeta.extract(frontmatter).values_at(:metas, :links)
|
|
57
78
|
{
|
|
58
79
|
'lang' => resolve_lang(opts),
|
|
59
80
|
'title' => resolve_escaped_title(document),
|
|
@@ -61,17 +82,21 @@ module Coradoc
|
|
|
61
82
|
'description' => opts.description,
|
|
62
83
|
'generator_version' => Coradoc::VERSION.to_s,
|
|
63
84
|
'body' => body_html,
|
|
64
|
-
'custom_css' => opts.custom_css
|
|
85
|
+
'custom_css' => opts.custom_css,
|
|
86
|
+
'meta_tags' => dedup_meta_tags(fm_metas, opts).map { |m| { 'name' => m.name, 'content' => m.content } },
|
|
87
|
+
'link_tags' => fm_links.map { |l| { 'rel' => l.rel, 'href' => l.href } }
|
|
65
88
|
}
|
|
66
89
|
end
|
|
67
90
|
|
|
68
91
|
def build_static_fallback(document, body_html, opts)
|
|
92
|
+
frontmatter = extract_frontmatter(document)
|
|
69
93
|
Nokogiri::HTML::Builder.new do |doc|
|
|
70
94
|
doc.html(lang: resolve_lang(opts)) do
|
|
71
95
|
doc.head do
|
|
72
96
|
doc.meta(charset: 'UTF-8')
|
|
73
97
|
doc.meta(name: 'viewport', content: 'width=device-width, initial-scale=1.0')
|
|
74
98
|
doc.title resolve_title(document)
|
|
99
|
+
FrontmatterMeta.emit_into_builder(doc, frontmatter)
|
|
75
100
|
end
|
|
76
101
|
doc.body { doc << body_html }
|
|
77
102
|
end
|
|
@@ -109,6 +134,8 @@ module Coradoc
|
|
|
109
134
|
end
|
|
110
135
|
|
|
111
136
|
def build_spa_layout_data(document, opts, assets, safe_json)
|
|
137
|
+
frontmatter = extract_frontmatter(document)
|
|
138
|
+
fm_metas, fm_links = FrontmatterMeta.extract(frontmatter).values_at(:metas, :links)
|
|
112
139
|
{
|
|
113
140
|
'lang' => resolve_lang(opts),
|
|
114
141
|
'title' => resolve_escaped_title(document),
|
|
@@ -117,11 +144,14 @@ module Coradoc
|
|
|
117
144
|
'generator_version' => Coradoc::VERSION.to_s,
|
|
118
145
|
'css' => assets[:css],
|
|
119
146
|
'js' => assets[:js],
|
|
120
|
-
'data' => safe_json
|
|
147
|
+
'data' => safe_json,
|
|
148
|
+
'meta_tags' => dedup_meta_tags(fm_metas, opts).map { |m| { 'name' => m.name, 'content' => m.content } },
|
|
149
|
+
'link_tags' => fm_links.map { |l| { 'rel' => l.rel, 'href' => l.href } }
|
|
121
150
|
}
|
|
122
151
|
end
|
|
123
152
|
|
|
124
153
|
def build_spa_fallback(document, opts, assets, safe_json)
|
|
154
|
+
frontmatter = extract_frontmatter(document)
|
|
125
155
|
Nokogiri::HTML::Builder.new do |doc|
|
|
126
156
|
doc.html(lang: resolve_lang(opts)) do
|
|
127
157
|
doc.head do
|
|
@@ -129,6 +159,7 @@ module Coradoc
|
|
|
129
159
|
doc.meta(name: 'viewport', content: 'width=device-width, initial-scale=1.0')
|
|
130
160
|
doc.meta(name: 'generator', content: "Coradoc #{Coradoc::VERSION}")
|
|
131
161
|
doc.title resolve_title(document)
|
|
162
|
+
FrontmatterMeta.emit_into_builder(doc, frontmatter)
|
|
132
163
|
doc.style { doc.text assets[:css] } if assets[:css]
|
|
133
164
|
end
|
|
134
165
|
doc.body do
|
data/lib/coradoc/html/output.rb
CHANGED
data/lib/coradoc/html/spa.rb
CHANGED
data/lib/coradoc/html/static.rb
CHANGED
data/lib/coradoc/html/version.rb
CHANGED
data/lib/coradoc/html.rb
CHANGED
|
@@ -13,9 +13,9 @@ module Coradoc
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
# Load HTML input module to register with Coradoc::Input
|
|
16
|
-
|
|
16
|
+
require_relative 'html/input'
|
|
17
17
|
# Load HTML output module to register with Coradoc::Output
|
|
18
|
-
|
|
18
|
+
require_relative 'html/output'
|
|
19
19
|
|
|
20
20
|
module Coradoc
|
|
21
21
|
module Html
|
|
@@ -29,7 +29,10 @@ module Coradoc
|
|
|
29
29
|
autoload :TitleText, 'coradoc/html/title_text'
|
|
30
30
|
|
|
31
31
|
# Drop layer — self-registering drops loaded via parent namespace file
|
|
32
|
-
|
|
32
|
+
require_relative 'html/drop'
|
|
33
|
+
|
|
34
|
+
# FrontmatterBlock -> <meta> tag mapping (HTML-specific concern)
|
|
35
|
+
autoload :FrontmatterMeta, 'coradoc/html/frontmatter_meta'
|
|
33
36
|
|
|
34
37
|
# Autoload HTML output converters
|
|
35
38
|
autoload :ConverterBase, 'coradoc/html/converter_base'
|
|
@@ -42,7 +45,7 @@ module Coradoc
|
|
|
42
45
|
autoload :TemplateLocator, 'coradoc/html/template_locator'
|
|
43
46
|
autoload :TemplateConfig, 'coradoc/html/template_config'
|
|
44
47
|
# Side-effect: registers Liquid filters on load
|
|
45
|
-
|
|
48
|
+
require_relative 'html/template_helpers'
|
|
46
49
|
autoload :Renderer, 'coradoc/html/renderer'
|
|
47
50
|
autoload :LayoutRenderer, 'coradoc/html/layout_renderer'
|
|
48
51
|
autoload :RenderOptions, 'coradoc/html/render_options'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: coradoc-html
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.17
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -143,6 +143,7 @@ files:
|
|
|
143
143
|
- lib/coradoc/html/drop/toc_drop.rb
|
|
144
144
|
- lib/coradoc/html/drop/toc_entry_drop.rb
|
|
145
145
|
- lib/coradoc/html/escape.rb
|
|
146
|
+
- lib/coradoc/html/frontmatter_meta.rb
|
|
146
147
|
- lib/coradoc/html/input.rb
|
|
147
148
|
- lib/coradoc/html/input/cleaner.rb
|
|
148
149
|
- lib/coradoc/html/input/config.rb
|