coradoc-html 1.1.7 → 1.1.13
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/config.rb +36 -12
- data/lib/coradoc/html/converter_base.rb +26 -68
- data/lib/coradoc/html/drop/annotation_drop.rb +31 -0
- data/lib/coradoc/html/drop/base.rb +77 -0
- data/lib/coradoc/html/drop/bibliography_drop.rb +15 -0
- data/lib/coradoc/html/drop/bibliography_entry_drop.rb +24 -0
- data/lib/coradoc/html/drop/block_drop.rb +69 -0
- data/lib/coradoc/html/drop/definition_item_drop.rb +36 -0
- data/lib/coradoc/html/drop/definition_list_drop.rb +15 -0
- data/lib/coradoc/html/drop/document_drop.rb +52 -0
- data/lib/coradoc/html/drop/drop_factory.rb +73 -0
- data/lib/coradoc/html/drop/footnote_drop.rb +24 -0
- data/lib/coradoc/html/drop/image_drop.rb +35 -0
- data/lib/coradoc/html/drop/inline_element_drop.rb +64 -0
- data/lib/coradoc/html/drop/list_block_drop.rb +23 -0
- data/lib/coradoc/html/drop/list_item_drop.rb +20 -0
- data/lib/coradoc/html/drop/table_cell_drop.rb +35 -0
- data/lib/coradoc/html/drop/table_drop.rb +15 -0
- data/lib/coradoc/html/drop/table_row_drop.rb +23 -0
- data/lib/coradoc/html/drop/term_drop.rb +24 -0
- data/lib/coradoc/html/drop/text_content_drop.rb +15 -0
- data/lib/coradoc/html/drop/toc_drop.rb +15 -0
- data/lib/coradoc/html/drop/toc_entry_drop.rb +32 -0
- data/lib/coradoc/html/escape.rb +29 -0
- data/lib/coradoc/html/input/cleaner.rb +4 -33
- data/lib/coradoc/html/input/config.rb +4 -3
- data/lib/coradoc/html/input/converters/a.rb +8 -19
- data/lib/coradoc/html/input/converters/aside.rb +4 -5
- data/lib/coradoc/html/input/converters/audio.rb +8 -35
- data/lib/coradoc/html/input/converters/base.rb +29 -27
- data/lib/coradoc/html/input/converters/blockquote.rb +4 -2
- data/lib/coradoc/html/input/converters/br.rb +4 -4
- data/lib/coradoc/html/input/converters/bypass.rb +68 -67
- data/lib/coradoc/html/input/converters/code.rb +7 -5
- data/lib/coradoc/html/input/converters/div.rb +4 -4
- data/lib/coradoc/html/input/converters/dl.rb +3 -25
- data/lib/coradoc/html/input/converters/drop.rb +13 -13
- data/lib/coradoc/html/input/converters/em.rb +5 -3
- data/lib/coradoc/html/input/converters/figure.rb +3 -26
- data/lib/coradoc/html/input/converters/h.rb +9 -11
- data/lib/coradoc/html/input/converters/head.rb +5 -4
- data/lib/coradoc/html/input/converters/hr.rb +4 -5
- data/lib/coradoc/html/input/converters/img.rb +4 -9
- data/lib/coradoc/html/input/converters/li.rb +3 -1
- data/lib/coradoc/html/input/converters/mark.rb +3 -1
- data/lib/coradoc/html/input/converters/markup.rb +4 -8
- data/lib/coradoc/html/input/converters/math.rb +7 -14
- data/lib/coradoc/html/input/converters/media_base.rb +50 -0
- data/lib/coradoc/html/input/converters/ol.rb +6 -8
- data/lib/coradoc/html/input/converters/p.rb +43 -34
- data/lib/coradoc/html/input/converters/pass_through.rb +2 -4
- data/lib/coradoc/html/input/converters/positional_formatting.rb +37 -0
- data/lib/coradoc/html/input/converters/pre.rb +3 -3
- data/lib/coradoc/html/input/converters/q.rb +6 -3
- data/lib/coradoc/html/input/converters/strong.rb +4 -2
- data/lib/coradoc/html/input/converters/sub.rb +7 -23
- data/lib/coradoc/html/input/converters/sup.rb +7 -23
- data/lib/coradoc/html/input/converters/table.rb +3 -1
- data/lib/coradoc/html/input/converters/td.rb +4 -30
- data/lib/coradoc/html/input/converters/text.rb +4 -3
- data/lib/coradoc/html/input/converters/tr.rb +3 -2
- data/lib/coradoc/html/input/converters/video.rb +14 -36
- data/lib/coradoc/html/input/converters.rb +17 -35
- data/lib/coradoc/html/input/html_converter.rb +2 -74
- data/lib/coradoc/html/input/plugin.rb +8 -50
- data/lib/coradoc/html/input/plugins/plateau.rb +4 -19
- data/lib/coradoc/html/input/postprocessor.rb +3 -9
- data/lib/coradoc/html/input.rb +26 -8
- data/lib/coradoc/html/layout_renderer.rb +163 -0
- data/lib/coradoc/html/output.rb +6 -12
- data/lib/coradoc/html/renderer.rb +84 -350
- data/lib/coradoc/html/section_numberable.rb +9 -0
- data/lib/coradoc/html/spa.rb +29 -270
- data/lib/coradoc/html/static.rb +29 -238
- data/lib/coradoc/html/template_caching.rb +31 -0
- data/lib/coradoc/html/template_config.rb +11 -70
- data/lib/coradoc/html/template_helpers.rb +39 -31
- data/lib/coradoc/html/template_locator.rb +17 -11
- data/lib/coradoc/html/theme.rb +1 -7
- data/lib/coradoc/html/title_text.rb +57 -0
- data/lib/coradoc/html/toc_builder.rb +105 -0
- data/lib/coradoc/html/toc_serializer.rb +33 -0
- data/lib/coradoc/html/transform/from_core_model.rb +13 -12
- data/lib/coradoc/html/transform/to_core_model.rb +10 -12
- data/lib/coradoc/html/version.rb +1 -1
- data/lib/coradoc/html.rb +43 -88
- metadata +37 -70
- data/lib/coradoc/html/base.rb +0 -157
- data/lib/coradoc/html/converters/admonition.rb +0 -180
- data/lib/coradoc/html/converters/attribute.rb +0 -68
- data/lib/coradoc/html/converters/attribute_reference.rb +0 -60
- data/lib/coradoc/html/converters/audio.rb +0 -165
- data/lib/coradoc/html/converters/base.rb +0 -615
- data/lib/coradoc/html/converters/bibliography.rb +0 -82
- data/lib/coradoc/html/converters/bibliography_entry.rb +0 -108
- data/lib/coradoc/html/converters/block_image.rb +0 -72
- data/lib/coradoc/html/converters/bold.rb +0 -34
- data/lib/coradoc/html/converters/break.rb +0 -32
- data/lib/coradoc/html/converters/comment_block.rb +0 -42
- data/lib/coradoc/html/converters/comment_line.rb +0 -54
- data/lib/coradoc/html/converters/cross_reference.rb +0 -59
- data/lib/coradoc/html/converters/document.rb +0 -108
- data/lib/coradoc/html/converters/example.rb +0 -114
- data/lib/coradoc/html/converters/highlight.rb +0 -34
- data/lib/coradoc/html/converters/include.rb +0 -68
- data/lib/coradoc/html/converters/inline_image.rb +0 -41
- data/lib/coradoc/html/converters/italic.rb +0 -34
- data/lib/coradoc/html/converters/line_break.rb +0 -31
- data/lib/coradoc/html/converters/link.rb +0 -46
- data/lib/coradoc/html/converters/list_item.rb +0 -75
- data/lib/coradoc/html/converters/listing.rb +0 -99
- data/lib/coradoc/html/converters/literal.rb +0 -102
- data/lib/coradoc/html/converters/monospace.rb +0 -34
- data/lib/coradoc/html/converters/open.rb +0 -78
- data/lib/coradoc/html/converters/ordered.rb +0 -53
- data/lib/coradoc/html/converters/paragraph.rb +0 -46
- data/lib/coradoc/html/converters/quote.rb +0 -113
- data/lib/coradoc/html/converters/reviewer_comment.rb +0 -74
- data/lib/coradoc/html/converters/reviewer_note.rb +0 -134
- data/lib/coradoc/html/converters/section.rb +0 -90
- data/lib/coradoc/html/converters/sidebar.rb +0 -113
- data/lib/coradoc/html/converters/source.rb +0 -137
- data/lib/coradoc/html/converters/source_code.rb +0 -16
- data/lib/coradoc/html/converters/span.rb +0 -61
- data/lib/coradoc/html/converters/strikethrough.rb +0 -34
- data/lib/coradoc/html/converters/subscript.rb +0 -34
- data/lib/coradoc/html/converters/superscript.rb +0 -34
- data/lib/coradoc/html/converters/table.rb +0 -85
- data/lib/coradoc/html/converters/table_cell.rb +0 -203
- data/lib/coradoc/html/converters/table_row.rb +0 -45
- data/lib/coradoc/html/converters/template_html_converter.rb +0 -105
- data/lib/coradoc/html/converters/term.rb +0 -58
- data/lib/coradoc/html/converters/text_element.rb +0 -44
- data/lib/coradoc/html/converters/underline.rb +0 -34
- data/lib/coradoc/html/converters/unordered.rb +0 -47
- data/lib/coradoc/html/converters/verse.rb +0 -105
- data/lib/coradoc/html/converters/video.rb +0 -179
- data/lib/coradoc/html/element_mapping.rb +0 -210
- data/lib/coradoc/html/entity.rb +0 -137
- data/lib/coradoc/html/input/converters/ignore.rb +0 -22
- data/lib/coradoc/html/input/converters/th.rb +0 -20
- data/lib/coradoc/html/theme/base.rb +0 -231
- data/lib/coradoc/html/theme/classic_renderer.rb +0 -390
- data/lib/coradoc/html/theme/modern/components/ui_components.rb +0 -344
- data/lib/coradoc/html/theme/modern/css_generator.rb +0 -311
- data/lib/coradoc/html/theme/modern/javascript_generator.rb +0 -314
- data/lib/coradoc/html/theme/modern/serializers/document_serializer.rb +0 -382
- data/lib/coradoc/html/theme/modern/tailwind_config_builder.rb +0 -164
- data/lib/coradoc/html/theme/modern/vue_template_generator.rb +0 -374
- data/lib/coradoc/html/theme/modern_renderer.rb +0 -250
- data/lib/coradoc/html/theme/registry.rb +0 -153
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Coradoc
|
|
4
|
-
module Html
|
|
5
|
-
# Element mapping between CoreModel and HTML elements
|
|
6
|
-
#
|
|
7
|
-
# This module provides bidirectional mapping between CoreModel types
|
|
8
|
-
# and HTML elements for conversion purposes.
|
|
9
|
-
module ElementMapping
|
|
10
|
-
class << self
|
|
11
|
-
# Map CoreModel class to HTML element
|
|
12
|
-
def model_to_html_element(model_class)
|
|
13
|
-
model_name = model_class.name.split('::').last.downcase.to_sym
|
|
14
|
-
MODEL_TO_HTML[model_name] || default_element_for(model_class)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# Map HTML element to CoreModel class
|
|
18
|
-
def html_element_to_model(tag_name, context = {})
|
|
19
|
-
tag = tag_name.to_s.downcase.to_sym
|
|
20
|
-
HTML_TO_MODEL[tag] || default_model_for(tag, context)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# Get default element for a model class
|
|
24
|
-
def default_element_for(model_class)
|
|
25
|
-
if model_class.ancestors.any? { |a| a.name&.include?('InlineElement') }
|
|
26
|
-
{ tag: 'span', semantic: false }
|
|
27
|
-
else
|
|
28
|
-
{ tag: 'div', semantic: false }
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Get default model for an HTML element
|
|
33
|
-
def default_model_for(tag, _context)
|
|
34
|
-
# Return CoreModel types
|
|
35
|
-
case tag
|
|
36
|
-
when :p, :div, :section, :article
|
|
37
|
-
'Coradoc::CoreModel::Block'
|
|
38
|
-
when :strong, :b, :em, :i, :code
|
|
39
|
-
'Coradoc::CoreModel::InlineElement'
|
|
40
|
-
else
|
|
41
|
-
'Coradoc::CoreModel::InlineElement'
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Mapping from CoreModel types to HTML elements
|
|
46
|
-
MODEL_TO_HTML = {
|
|
47
|
-
# Document structure
|
|
48
|
-
document: { tag: 'article', semantic: true },
|
|
49
|
-
section: { tag: 'section', semantic: true },
|
|
50
|
-
header: { tag: 'header', semantic: true },
|
|
51
|
-
title: { tag: 'h1', semantic: true },
|
|
52
|
-
structuralelement: { tag: 'section', semantic: true },
|
|
53
|
-
|
|
54
|
-
# Block elements
|
|
55
|
-
paragraph: { tag: 'p', semantic: true },
|
|
56
|
-
block: { tag: 'div', semantic: true },
|
|
57
|
-
example: { tag: 'div', class: 'example', semantic: false },
|
|
58
|
-
annotationblock: { tag: 'aside', semantic: true },
|
|
59
|
-
quote: { tag: 'blockquote', semantic: true },
|
|
60
|
-
verse: { tag: 'div', class: 'verse', semantic: false },
|
|
61
|
-
listing: { tag: 'pre', semantic: true },
|
|
62
|
-
literal: { tag: 'pre', semantic: true },
|
|
63
|
-
source: { tag: 'pre', semantic: true },
|
|
64
|
-
open: { tag: 'div', semantic: false },
|
|
65
|
-
pass: { tag: 'div', class: 'pass', semantic: false },
|
|
66
|
-
|
|
67
|
-
# Inline elements
|
|
68
|
-
inlineelement: { tag: 'span', semantic: false },
|
|
69
|
-
bold: { tag: 'strong', semantic: true },
|
|
70
|
-
italic: { tag: 'em', semantic: true },
|
|
71
|
-
monospace: { tag: 'code', semantic: true },
|
|
72
|
-
highlight: { tag: 'mark', semantic: true },
|
|
73
|
-
superscript: { tag: 'sup', semantic: true },
|
|
74
|
-
subscript: { tag: 'sub', semantic: true },
|
|
75
|
-
underline: { tag: 'u', semantic: false },
|
|
76
|
-
strikethrough: { tag: 'del', semantic: true },
|
|
77
|
-
smallcaps: { tag: 'span', class: 'small-caps', semantic: false },
|
|
78
|
-
link: { tag: 'a', semantic: true },
|
|
79
|
-
anchor: { tag: 'a', semantic: true },
|
|
80
|
-
xref: { tag: 'a', class: 'xref', semantic: true },
|
|
81
|
-
quotation: { tag: 'q', semantic: true },
|
|
82
|
-
|
|
83
|
-
# Lists
|
|
84
|
-
listblock: { tag: 'ul', semantic: true },
|
|
85
|
-
listitem: { tag: 'li', semantic: true },
|
|
86
|
-
orderedlist: { tag: 'ol', semantic: true },
|
|
87
|
-
unorderedlist: { tag: 'ul', semantic: true },
|
|
88
|
-
|
|
89
|
-
# Tables
|
|
90
|
-
table: { tag: 'table', semantic: true },
|
|
91
|
-
tablerow: { tag: 'tr', semantic: true },
|
|
92
|
-
tablecell: { tag: 'td', semantic: true },
|
|
93
|
-
|
|
94
|
-
# Media
|
|
95
|
-
image: { tag: 'img', semantic: true, self_closing: true },
|
|
96
|
-
video: { tag: 'video', semantic: true },
|
|
97
|
-
audio: { tag: 'audio', semantic: true },
|
|
98
|
-
|
|
99
|
-
# Other
|
|
100
|
-
break: { tag: 'hr', semantic: true, self_closing: true },
|
|
101
|
-
linebreak: { tag: 'br', semantic: true, self_closing: true },
|
|
102
|
-
|
|
103
|
-
# Text
|
|
104
|
-
textelement: { tag: 'text', semantic: false }
|
|
105
|
-
}.freeze
|
|
106
|
-
|
|
107
|
-
# Mapping from HTML elements to CoreModel types
|
|
108
|
-
HTML_TO_MODEL = {
|
|
109
|
-
# Block elements
|
|
110
|
-
p: 'Coradoc::CoreModel::Block',
|
|
111
|
-
div: 'Coradoc::CoreModel::Block',
|
|
112
|
-
section: 'Coradoc::CoreModel::StructuralElement',
|
|
113
|
-
article: 'Coradoc::CoreModel::StructuralElement',
|
|
114
|
-
header: 'Coradoc::CoreModel::StructuralElement',
|
|
115
|
-
aside: 'Coradoc::CoreModel::AnnotationBlock',
|
|
116
|
-
blockquote: 'Coradoc::CoreModel::Block',
|
|
117
|
-
pre: 'Coradoc::CoreModel::Block',
|
|
118
|
-
|
|
119
|
-
# Inline elements
|
|
120
|
-
strong: 'Coradoc::CoreModel::InlineElement',
|
|
121
|
-
b: 'Coradoc::CoreModel::InlineElement',
|
|
122
|
-
em: 'Coradoc::CoreModel::InlineElement',
|
|
123
|
-
i: 'Coradoc::CoreModel::InlineElement',
|
|
124
|
-
code: 'Coradoc::CoreModel::InlineElement',
|
|
125
|
-
mark: 'Coradoc::CoreModel::InlineElement',
|
|
126
|
-
sup: 'Coradoc::CoreModel::InlineElement',
|
|
127
|
-
sub: 'Coradoc::CoreModel::InlineElement',
|
|
128
|
-
u: 'Coradoc::CoreModel::InlineElement',
|
|
129
|
-
del: 'Coradoc::CoreModel::InlineElement',
|
|
130
|
-
s: 'Coradoc::CoreModel::InlineElement',
|
|
131
|
-
strike: 'Coradoc::CoreModel::InlineElement',
|
|
132
|
-
|
|
133
|
-
# Links
|
|
134
|
-
a: 'Coradoc::CoreModel::InlineElement',
|
|
135
|
-
|
|
136
|
-
# Lists
|
|
137
|
-
ul: 'Coradoc::CoreModel::ListBlock',
|
|
138
|
-
ol: 'Coradoc::CoreModel::ListBlock',
|
|
139
|
-
li: 'Coradoc::CoreModel::ListItem',
|
|
140
|
-
dl: 'Coradoc::CoreModel::ListBlock',
|
|
141
|
-
dt: 'Coradoc::CoreModel::ListItem',
|
|
142
|
-
dd: 'Coradoc::CoreModel::ListItem',
|
|
143
|
-
|
|
144
|
-
# Tables
|
|
145
|
-
table: 'Coradoc::CoreModel::Table',
|
|
146
|
-
tr: 'Coradoc::CoreModel::TableRow',
|
|
147
|
-
td: 'Coradoc::CoreModel::TableCell',
|
|
148
|
-
th: 'Coradoc::CoreModel::TableCell',
|
|
149
|
-
|
|
150
|
-
# Media
|
|
151
|
-
img: 'Coradoc::CoreModel::Image',
|
|
152
|
-
video: 'Coradoc::CoreModel::Block',
|
|
153
|
-
audio: 'Coradoc::CoreModel::Block',
|
|
154
|
-
|
|
155
|
-
# Other
|
|
156
|
-
hr: 'Coradoc::CoreModel::Block',
|
|
157
|
-
br: 'Coradoc::CoreModel::InlineElement',
|
|
158
|
-
|
|
159
|
-
# Headings
|
|
160
|
-
h1: 'Coradoc::CoreModel::StructuralElement',
|
|
161
|
-
h2: 'Coradoc::CoreModel::StructuralElement',
|
|
162
|
-
h3: 'Coradoc::CoreModel::StructuralElement',
|
|
163
|
-
h4: 'Coradoc::CoreModel::StructuralElement',
|
|
164
|
-
h5: 'Coradoc::CoreModel::StructuralElement',
|
|
165
|
-
h6: 'Coradoc::CoreModel::StructuralElement'
|
|
166
|
-
}.freeze
|
|
167
|
-
|
|
168
|
-
# Check if HTML element is block-level
|
|
169
|
-
def block_element?(tag)
|
|
170
|
-
BLOCK_ELEMENTS.include?(tag.to_sym)
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
# Check if HTML element is inline-level
|
|
174
|
-
def inline_element?(tag)
|
|
175
|
-
INLINE_ELEMENTS.include?(tag.to_sym)
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
# Check if HTML element is self-closing
|
|
179
|
-
def self_closing?(tag)
|
|
180
|
-
SELF_CLOSING_ELEMENTS.include?(tag.to_sym)
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
# Block-level HTML elements
|
|
184
|
-
BLOCK_ELEMENTS = %i[
|
|
185
|
-
div p section article aside header footer main nav
|
|
186
|
-
blockquote pre ul ol li dl dt dd
|
|
187
|
-
table tr td th thead tbody tfoot
|
|
188
|
-
h1 h2 h3 h4 h5 h6
|
|
189
|
-
hr
|
|
190
|
-
figure figcaption
|
|
191
|
-
].freeze
|
|
192
|
-
|
|
193
|
-
# Inline-level HTML elements
|
|
194
|
-
INLINE_ELEMENTS = %i[
|
|
195
|
-
span strong em b i u s del ins mark small
|
|
196
|
-
code kbd samp var
|
|
197
|
-
a abbr cite dfn q
|
|
198
|
-
sub sup
|
|
199
|
-
time
|
|
200
|
-
br wbr
|
|
201
|
-
].freeze
|
|
202
|
-
|
|
203
|
-
# Self-closing HTML elements
|
|
204
|
-
SELF_CLOSING_ELEMENTS = %i[
|
|
205
|
-
area base br col embed hr img input link meta param source track wbr
|
|
206
|
-
].freeze
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
end
|
|
210
|
-
end
|
data/lib/coradoc/html/entity.rb
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Coradoc
|
|
4
|
-
module Html
|
|
5
|
-
# HTML entity handling
|
|
6
|
-
module Entity
|
|
7
|
-
# Named HTML entities
|
|
8
|
-
NAMED_ENTITIES = {
|
|
9
|
-
'nbsp' => "\u00A0",
|
|
10
|
-
'lt' => '<',
|
|
11
|
-
'gt' => '>',
|
|
12
|
-
'amp' => '&',
|
|
13
|
-
'quot' => '"',
|
|
14
|
-
'apos' => "'",
|
|
15
|
-
'cent' => "\u00A2",
|
|
16
|
-
'pound' => "\u00A3",
|
|
17
|
-
'yen' => "\u00A5",
|
|
18
|
-
'euro' => "\u20AC",
|
|
19
|
-
'copy' => "\u00A9",
|
|
20
|
-
'reg' => "\u00AE",
|
|
21
|
-
'trade' => "\u2122",
|
|
22
|
-
'mdash' => "\u2014",
|
|
23
|
-
'ndash' => "\u2013",
|
|
24
|
-
'hellip' => "\u2026",
|
|
25
|
-
'laquo' => "\u00AB",
|
|
26
|
-
'raquo' => "\u00BB",
|
|
27
|
-
'ldquo' => "\u201C",
|
|
28
|
-
'rdquo' => "\u201D",
|
|
29
|
-
'lsquo' => "\u2018",
|
|
30
|
-
'rsquo' => "\u2019"
|
|
31
|
-
}.freeze
|
|
32
|
-
|
|
33
|
-
class << self
|
|
34
|
-
# Encode text to HTML entities
|
|
35
|
-
def encode(text, options = {})
|
|
36
|
-
return '' if text.nil?
|
|
37
|
-
return text unless text.is_a?(String)
|
|
38
|
-
|
|
39
|
-
encoded = text.dup
|
|
40
|
-
|
|
41
|
-
# Basic HTML entities
|
|
42
|
-
encoded = encoded
|
|
43
|
-
.gsub('&', '&')
|
|
44
|
-
.gsub('<', '<')
|
|
45
|
-
.gsub('>', '>')
|
|
46
|
-
.gsub('"', '"')
|
|
47
|
-
|
|
48
|
-
# Optionally encode additional characters
|
|
49
|
-
encoded = encoded.gsub("'", ''') if options[:encode_quotes]
|
|
50
|
-
|
|
51
|
-
encoded = encoded.gsub("\u00A0", ' ') if options[:encode_nbsp]
|
|
52
|
-
|
|
53
|
-
encoded
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# Decode HTML entities to text
|
|
57
|
-
def decode(text)
|
|
58
|
-
return '' if text.nil?
|
|
59
|
-
return text unless text.is_a?(String)
|
|
60
|
-
|
|
61
|
-
decoded = text.dup
|
|
62
|
-
|
|
63
|
-
# Decode named entities
|
|
64
|
-
NAMED_ENTITIES.each do |name, char|
|
|
65
|
-
decoded = decoded.gsub("&#{name};", char)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# Decode numeric entities (decimal)
|
|
69
|
-
decoded = decoded.gsub(/&#(\d+);/) do
|
|
70
|
-
[::Regexp.last_match(1).to_i].pack('U')
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# Decode numeric entities (hexadecimal)
|
|
74
|
-
decoded = decoded.gsub(/&#x([0-9a-fA-F]+);/) do
|
|
75
|
-
[::Regexp.last_match(1).to_i(16)].pack('U')
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# Decode basic entities last
|
|
79
|
-
decoded
|
|
80
|
-
.gsub('"', '"')
|
|
81
|
-
.gsub(''', "'")
|
|
82
|
-
.gsub(''', "'")
|
|
83
|
-
.gsub('<', '<')
|
|
84
|
-
.gsub('>', '>')
|
|
85
|
-
.gsub('&', '&')
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
# Convert character to named entity if available
|
|
89
|
-
def to_named_entity(char)
|
|
90
|
-
entity_name = NAMED_ENTITIES.key(char)
|
|
91
|
-
entity_name ? "&#{entity_name};" : char
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
# Convert character to numeric entity
|
|
95
|
-
def to_numeric_entity(char, format: :decimal)
|
|
96
|
-
codepoint = char.ord
|
|
97
|
-
|
|
98
|
-
case format
|
|
99
|
-
when :decimal
|
|
100
|
-
"&##{codepoint};"
|
|
101
|
-
when :hex, :hexadecimal
|
|
102
|
-
"&#x#{codepoint.to_s(16)};"
|
|
103
|
-
else
|
|
104
|
-
char
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
# Check if text contains HTML entities
|
|
109
|
-
def has_entities?(text)
|
|
110
|
-
return false unless text.is_a?(String)
|
|
111
|
-
|
|
112
|
-
text.match?(/&[a-zA-Z]+;|&#\d+;|&#x[0-9a-fA-F]+;/)
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
# Normalize entities (convert all to named where possible, numeric otherwise)
|
|
116
|
-
def normalize(text)
|
|
117
|
-
return '' if text.nil?
|
|
118
|
-
return text unless text.is_a?(String)
|
|
119
|
-
|
|
120
|
-
# First decode to get actual characters
|
|
121
|
-
decoded = decode(text)
|
|
122
|
-
|
|
123
|
-
# Then encode back using named entities where possible
|
|
124
|
-
decoded.chars.map do |char|
|
|
125
|
-
case char
|
|
126
|
-
when '&', '<', '>', '"', "'"
|
|
127
|
-
encode(char)
|
|
128
|
-
else
|
|
129
|
-
named = to_named_entity(char)
|
|
130
|
-
named == char ? char : named
|
|
131
|
-
end
|
|
132
|
-
end.join
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
end
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Coradoc
|
|
4
|
-
module Input
|
|
5
|
-
module Html
|
|
6
|
-
module Converters
|
|
7
|
-
class Ignore < Base
|
|
8
|
-
def to_coradoc(node, state = {})
|
|
9
|
-
convert(node, state)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def convert(_node, _state = {})
|
|
13
|
-
'' # noop
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
register :colgroup, Ignore.new
|
|
18
|
-
register :col, Ignore.new
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Coradoc
|
|
4
|
-
module Input
|
|
5
|
-
module Html
|
|
6
|
-
module Converters
|
|
7
|
-
class Th < Td
|
|
8
|
-
def cellstyle(node)
|
|
9
|
-
# this is the header row
|
|
10
|
-
return '' if node.parent.previous_element.nil?
|
|
11
|
-
|
|
12
|
-
'h'
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
register :th, Th.new
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'coradoc/html/base'
|
|
4
|
-
|
|
5
|
-
module Coradoc
|
|
6
|
-
module Html
|
|
7
|
-
module Theme
|
|
8
|
-
# Abstract base class for all HTML themes
|
|
9
|
-
#
|
|
10
|
-
# This class defines the interface that all theme renderers must implement.
|
|
11
|
-
# Themes are responsible for converting Coradoc document models to HTML output.
|
|
12
|
-
#
|
|
13
|
-
# @abstract Subclass and implement {#render} to create a custom theme
|
|
14
|
-
class Base
|
|
15
|
-
attr_reader :document, :options
|
|
16
|
-
|
|
17
|
-
# Initialize a new theme instance
|
|
18
|
-
#
|
|
19
|
-
# @param document [Coradoc::CoreModel::StructuralElement] The document to render
|
|
20
|
-
# @param options [Hash] Rendering options
|
|
21
|
-
def initialize(document, options = {})
|
|
22
|
-
@document = document
|
|
23
|
-
@options = options
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Render the document to HTML
|
|
27
|
-
#
|
|
28
|
-
# This method must be implemented by subclasses.
|
|
29
|
-
#
|
|
30
|
-
# @abstract
|
|
31
|
-
# @return [String] The rendered HTML content
|
|
32
|
-
def render
|
|
33
|
-
raise NotImplementedError,
|
|
34
|
-
"#{self.class.name} must implement #render method"
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Render the complete HTML5 document
|
|
38
|
-
#
|
|
39
|
-
# @return [String] Complete HTML5 document
|
|
40
|
-
def render_html5
|
|
41
|
-
html_body = render
|
|
42
|
-
build_html5_document(html_body)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Get the theme name
|
|
46
|
-
#
|
|
47
|
-
# @return [Symbol] Theme name (e.g., :classic, :modern)
|
|
48
|
-
def theme_name
|
|
49
|
-
@theme_name ||= self.class.name.split('::').last
|
|
50
|
-
.gsub(/Renderer$/, '')
|
|
51
|
-
.downcase
|
|
52
|
-
.to_sym
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Check if this theme supports a specific feature
|
|
56
|
-
#
|
|
57
|
-
# @param feature [Symbol] Feature to check (e.g., :dark_mode, :interactive_toc)
|
|
58
|
-
# @return [Boolean] true if the feature is supported
|
|
59
|
-
def supports?(feature)
|
|
60
|
-
supported_features.include?(feature)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# List of features supported by this theme
|
|
64
|
-
#
|
|
65
|
-
# Subclasses can override to declare supported features.
|
|
66
|
-
#
|
|
67
|
-
# @return [Array<Symbol>] List of supported features
|
|
68
|
-
def supported_features
|
|
69
|
-
[]
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
protected
|
|
73
|
-
|
|
74
|
-
# Build complete HTML5 document
|
|
75
|
-
#
|
|
76
|
-
# @param body_html [String] HTML body content
|
|
77
|
-
# @return [String] Complete HTML5 document
|
|
78
|
-
def build_html5_document(body_html)
|
|
79
|
-
lang = @options[:lang] || 'en'
|
|
80
|
-
body_classes = build_body_classes
|
|
81
|
-
|
|
82
|
-
<<~HTML
|
|
83
|
-
<!DOCTYPE html>
|
|
84
|
-
<html lang="#{lang}">
|
|
85
|
-
<head>
|
|
86
|
-
#{build_head_content}
|
|
87
|
-
</head>
|
|
88
|
-
<body#{body_classes}>
|
|
89
|
-
#{body_html}
|
|
90
|
-
</body>
|
|
91
|
-
</html>
|
|
92
|
-
HTML
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
# Build HTML head content
|
|
96
|
-
#
|
|
97
|
-
# @return [String] Head section HTML
|
|
98
|
-
def build_head_content
|
|
99
|
-
parts = []
|
|
100
|
-
parts << build_meta_tags
|
|
101
|
-
parts << build_title_tag
|
|
102
|
-
parts << build_css_tags
|
|
103
|
-
parts << build_script_tags
|
|
104
|
-
parts.compact.reject(&:empty?).join("\n")
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
# Build meta tags
|
|
108
|
-
#
|
|
109
|
-
# @return [String] Meta tags HTML
|
|
110
|
-
def build_meta_tags
|
|
111
|
-
meta = []
|
|
112
|
-
meta << ' <meta charset="UTF-8">'
|
|
113
|
-
meta << ' <meta name="viewport" content="width=device-width, initial-scale=1.0">'
|
|
114
|
-
|
|
115
|
-
# Author meta tag
|
|
116
|
-
if @options[:author]
|
|
117
|
-
author = escape_attr(@options[:author])
|
|
118
|
-
meta << %( <meta name="author" content="#{author}">)
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
# Description meta tag
|
|
122
|
-
if @options[:description]
|
|
123
|
-
description = escape_attr(@options[:description])
|
|
124
|
-
meta << %( <meta name="description" content="#{description}">)
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
# Keywords meta tag
|
|
128
|
-
if @options[:keywords]
|
|
129
|
-
keywords = escape_attr(@options[:keywords])
|
|
130
|
-
meta << %( <meta name="keywords" content="#{keywords}">)
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
# Generator meta tag with version
|
|
134
|
-
meta << %( <meta name="generator" content="Coradoc #{Coradoc::VERSION}">)
|
|
135
|
-
|
|
136
|
-
# Generation timestamp
|
|
137
|
-
meta << %( <meta name="generated" content="#{Time.now.utc.iso8601}">)
|
|
138
|
-
|
|
139
|
-
# Custom meta tags
|
|
140
|
-
if @options[:meta_tags].is_a?(Hash)
|
|
141
|
-
@options[:meta_tags].each do |name, content|
|
|
142
|
-
meta << %( <meta name="#{escape_attr(name)}" content="#{escape_attr(content)}">)
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
meta.join("\n")
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# Build title tag
|
|
150
|
-
#
|
|
151
|
-
# @return [String] Title tag HTML
|
|
152
|
-
def build_title_tag
|
|
153
|
-
title = extract_document_title
|
|
154
|
-
" <title>#{escape_html(title)}</title>"
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
# Extract document title
|
|
158
|
-
#
|
|
159
|
-
# @return [String] Document title
|
|
160
|
-
def extract_document_title
|
|
161
|
-
if @document.is_a?(Coradoc::CoreModel::StructuralElement) && @document.title
|
|
162
|
-
title = @document.title
|
|
163
|
-
return title if title.is_a?(String)
|
|
164
|
-
return title.text if title.is_a?(Coradoc::CoreModel::Base) && title.text
|
|
165
|
-
|
|
166
|
-
return title.to_s
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
'Untitled Document'
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
# Extract text from content (array of inline elements)
|
|
173
|
-
#
|
|
174
|
-
# @param content [Array] Content elements
|
|
175
|
-
# @return [String] Extracted text
|
|
176
|
-
def extract_text_from_content(content)
|
|
177
|
-
case content
|
|
178
|
-
when Array
|
|
179
|
-
content.map { |item| extract_text_from_content(item) }.join
|
|
180
|
-
when String
|
|
181
|
-
content
|
|
182
|
-
when Coradoc::CoreModel::InlineElement
|
|
183
|
-
content.text
|
|
184
|
-
else
|
|
185
|
-
content.to_s
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
# Build body classes
|
|
190
|
-
#
|
|
191
|
-
# @return [String] Body class attribute
|
|
192
|
-
def build_body_classes
|
|
193
|
-
classes = []
|
|
194
|
-
classes << "theme-#{theme_name}"
|
|
195
|
-
|
|
196
|
-
classes.empty? ? '' : %( class="#{classes.join(' ')}")
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
# Build CSS tags
|
|
200
|
-
#
|
|
201
|
-
# @return [String] CSS link or style tags
|
|
202
|
-
def build_css_tags
|
|
203
|
-
''
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
# Build script tags
|
|
207
|
-
#
|
|
208
|
-
# @return [String] Script tags
|
|
209
|
-
def build_script_tags
|
|
210
|
-
''
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
# Escape HTML content
|
|
214
|
-
#
|
|
215
|
-
# @param text [String] Text to escape
|
|
216
|
-
# @return [String] Escaped text
|
|
217
|
-
def escape_html(text)
|
|
218
|
-
Coradoc::Html::Base.escape_html(text.to_s)
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
# Escape HTML attribute value
|
|
222
|
-
#
|
|
223
|
-
# @param value [String] Value to escape
|
|
224
|
-
# @return [String] Escaped value
|
|
225
|
-
def escape_attr(value)
|
|
226
|
-
value.to_s.gsub('"', '"').gsub('<', '<').gsub('>', '>')
|
|
227
|
-
end
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
end
|
|
231
|
-
end
|