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.
Files changed (152) hide show
  1. checksums.yaml +4 -4
  2. data/lib/coradoc/html/config.rb +36 -12
  3. data/lib/coradoc/html/converter_base.rb +26 -68
  4. data/lib/coradoc/html/drop/annotation_drop.rb +31 -0
  5. data/lib/coradoc/html/drop/base.rb +77 -0
  6. data/lib/coradoc/html/drop/bibliography_drop.rb +15 -0
  7. data/lib/coradoc/html/drop/bibliography_entry_drop.rb +24 -0
  8. data/lib/coradoc/html/drop/block_drop.rb +69 -0
  9. data/lib/coradoc/html/drop/definition_item_drop.rb +36 -0
  10. data/lib/coradoc/html/drop/definition_list_drop.rb +15 -0
  11. data/lib/coradoc/html/drop/document_drop.rb +52 -0
  12. data/lib/coradoc/html/drop/drop_factory.rb +73 -0
  13. data/lib/coradoc/html/drop/footnote_drop.rb +24 -0
  14. data/lib/coradoc/html/drop/image_drop.rb +35 -0
  15. data/lib/coradoc/html/drop/inline_element_drop.rb +64 -0
  16. data/lib/coradoc/html/drop/list_block_drop.rb +23 -0
  17. data/lib/coradoc/html/drop/list_item_drop.rb +20 -0
  18. data/lib/coradoc/html/drop/table_cell_drop.rb +35 -0
  19. data/lib/coradoc/html/drop/table_drop.rb +15 -0
  20. data/lib/coradoc/html/drop/table_row_drop.rb +23 -0
  21. data/lib/coradoc/html/drop/term_drop.rb +24 -0
  22. data/lib/coradoc/html/drop/text_content_drop.rb +15 -0
  23. data/lib/coradoc/html/drop/toc_drop.rb +15 -0
  24. data/lib/coradoc/html/drop/toc_entry_drop.rb +32 -0
  25. data/lib/coradoc/html/escape.rb +29 -0
  26. data/lib/coradoc/html/input/cleaner.rb +4 -33
  27. data/lib/coradoc/html/input/config.rb +4 -3
  28. data/lib/coradoc/html/input/converters/a.rb +8 -19
  29. data/lib/coradoc/html/input/converters/aside.rb +4 -5
  30. data/lib/coradoc/html/input/converters/audio.rb +8 -35
  31. data/lib/coradoc/html/input/converters/base.rb +29 -27
  32. data/lib/coradoc/html/input/converters/blockquote.rb +4 -2
  33. data/lib/coradoc/html/input/converters/br.rb +4 -4
  34. data/lib/coradoc/html/input/converters/bypass.rb +68 -67
  35. data/lib/coradoc/html/input/converters/code.rb +7 -5
  36. data/lib/coradoc/html/input/converters/div.rb +4 -4
  37. data/lib/coradoc/html/input/converters/dl.rb +3 -25
  38. data/lib/coradoc/html/input/converters/drop.rb +13 -13
  39. data/lib/coradoc/html/input/converters/em.rb +5 -3
  40. data/lib/coradoc/html/input/converters/figure.rb +3 -26
  41. data/lib/coradoc/html/input/converters/h.rb +9 -11
  42. data/lib/coradoc/html/input/converters/head.rb +5 -4
  43. data/lib/coradoc/html/input/converters/hr.rb +4 -5
  44. data/lib/coradoc/html/input/converters/img.rb +4 -9
  45. data/lib/coradoc/html/input/converters/li.rb +3 -1
  46. data/lib/coradoc/html/input/converters/mark.rb +3 -1
  47. data/lib/coradoc/html/input/converters/markup.rb +4 -8
  48. data/lib/coradoc/html/input/converters/math.rb +7 -14
  49. data/lib/coradoc/html/input/converters/media_base.rb +50 -0
  50. data/lib/coradoc/html/input/converters/ol.rb +6 -8
  51. data/lib/coradoc/html/input/converters/p.rb +43 -34
  52. data/lib/coradoc/html/input/converters/pass_through.rb +2 -4
  53. data/lib/coradoc/html/input/converters/positional_formatting.rb +37 -0
  54. data/lib/coradoc/html/input/converters/pre.rb +3 -3
  55. data/lib/coradoc/html/input/converters/q.rb +6 -3
  56. data/lib/coradoc/html/input/converters/strong.rb +4 -2
  57. data/lib/coradoc/html/input/converters/sub.rb +7 -23
  58. data/lib/coradoc/html/input/converters/sup.rb +7 -23
  59. data/lib/coradoc/html/input/converters/table.rb +3 -1
  60. data/lib/coradoc/html/input/converters/td.rb +4 -30
  61. data/lib/coradoc/html/input/converters/text.rb +4 -3
  62. data/lib/coradoc/html/input/converters/tr.rb +3 -2
  63. data/lib/coradoc/html/input/converters/video.rb +14 -36
  64. data/lib/coradoc/html/input/converters.rb +17 -35
  65. data/lib/coradoc/html/input/html_converter.rb +2 -74
  66. data/lib/coradoc/html/input/plugin.rb +8 -50
  67. data/lib/coradoc/html/input/plugins/plateau.rb +4 -19
  68. data/lib/coradoc/html/input/postprocessor.rb +3 -9
  69. data/lib/coradoc/html/input.rb +26 -8
  70. data/lib/coradoc/html/layout_renderer.rb +163 -0
  71. data/lib/coradoc/html/output.rb +6 -12
  72. data/lib/coradoc/html/renderer.rb +84 -350
  73. data/lib/coradoc/html/section_numberable.rb +9 -0
  74. data/lib/coradoc/html/spa.rb +29 -270
  75. data/lib/coradoc/html/static.rb +29 -238
  76. data/lib/coradoc/html/template_caching.rb +31 -0
  77. data/lib/coradoc/html/template_config.rb +11 -70
  78. data/lib/coradoc/html/template_helpers.rb +39 -31
  79. data/lib/coradoc/html/template_locator.rb +17 -11
  80. data/lib/coradoc/html/theme.rb +1 -7
  81. data/lib/coradoc/html/title_text.rb +57 -0
  82. data/lib/coradoc/html/toc_builder.rb +105 -0
  83. data/lib/coradoc/html/toc_serializer.rb +33 -0
  84. data/lib/coradoc/html/transform/from_core_model.rb +13 -12
  85. data/lib/coradoc/html/transform/to_core_model.rb +10 -12
  86. data/lib/coradoc/html/version.rb +1 -1
  87. data/lib/coradoc/html.rb +43 -88
  88. metadata +37 -70
  89. data/lib/coradoc/html/base.rb +0 -157
  90. data/lib/coradoc/html/converters/admonition.rb +0 -180
  91. data/lib/coradoc/html/converters/attribute.rb +0 -68
  92. data/lib/coradoc/html/converters/attribute_reference.rb +0 -60
  93. data/lib/coradoc/html/converters/audio.rb +0 -165
  94. data/lib/coradoc/html/converters/base.rb +0 -615
  95. data/lib/coradoc/html/converters/bibliography.rb +0 -82
  96. data/lib/coradoc/html/converters/bibliography_entry.rb +0 -108
  97. data/lib/coradoc/html/converters/block_image.rb +0 -72
  98. data/lib/coradoc/html/converters/bold.rb +0 -34
  99. data/lib/coradoc/html/converters/break.rb +0 -32
  100. data/lib/coradoc/html/converters/comment_block.rb +0 -42
  101. data/lib/coradoc/html/converters/comment_line.rb +0 -54
  102. data/lib/coradoc/html/converters/cross_reference.rb +0 -59
  103. data/lib/coradoc/html/converters/document.rb +0 -108
  104. data/lib/coradoc/html/converters/example.rb +0 -114
  105. data/lib/coradoc/html/converters/highlight.rb +0 -34
  106. data/lib/coradoc/html/converters/include.rb +0 -68
  107. data/lib/coradoc/html/converters/inline_image.rb +0 -41
  108. data/lib/coradoc/html/converters/italic.rb +0 -34
  109. data/lib/coradoc/html/converters/line_break.rb +0 -31
  110. data/lib/coradoc/html/converters/link.rb +0 -46
  111. data/lib/coradoc/html/converters/list_item.rb +0 -75
  112. data/lib/coradoc/html/converters/listing.rb +0 -99
  113. data/lib/coradoc/html/converters/literal.rb +0 -102
  114. data/lib/coradoc/html/converters/monospace.rb +0 -34
  115. data/lib/coradoc/html/converters/open.rb +0 -78
  116. data/lib/coradoc/html/converters/ordered.rb +0 -53
  117. data/lib/coradoc/html/converters/paragraph.rb +0 -46
  118. data/lib/coradoc/html/converters/quote.rb +0 -113
  119. data/lib/coradoc/html/converters/reviewer_comment.rb +0 -74
  120. data/lib/coradoc/html/converters/reviewer_note.rb +0 -134
  121. data/lib/coradoc/html/converters/section.rb +0 -90
  122. data/lib/coradoc/html/converters/sidebar.rb +0 -113
  123. data/lib/coradoc/html/converters/source.rb +0 -137
  124. data/lib/coradoc/html/converters/source_code.rb +0 -16
  125. data/lib/coradoc/html/converters/span.rb +0 -61
  126. data/lib/coradoc/html/converters/strikethrough.rb +0 -34
  127. data/lib/coradoc/html/converters/subscript.rb +0 -34
  128. data/lib/coradoc/html/converters/superscript.rb +0 -34
  129. data/lib/coradoc/html/converters/table.rb +0 -85
  130. data/lib/coradoc/html/converters/table_cell.rb +0 -203
  131. data/lib/coradoc/html/converters/table_row.rb +0 -45
  132. data/lib/coradoc/html/converters/template_html_converter.rb +0 -105
  133. data/lib/coradoc/html/converters/term.rb +0 -58
  134. data/lib/coradoc/html/converters/text_element.rb +0 -44
  135. data/lib/coradoc/html/converters/underline.rb +0 -34
  136. data/lib/coradoc/html/converters/unordered.rb +0 -47
  137. data/lib/coradoc/html/converters/verse.rb +0 -105
  138. data/lib/coradoc/html/converters/video.rb +0 -179
  139. data/lib/coradoc/html/element_mapping.rb +0 -210
  140. data/lib/coradoc/html/entity.rb +0 -137
  141. data/lib/coradoc/html/input/converters/ignore.rb +0 -22
  142. data/lib/coradoc/html/input/converters/th.rb +0 -20
  143. data/lib/coradoc/html/theme/base.rb +0 -231
  144. data/lib/coradoc/html/theme/classic_renderer.rb +0 -390
  145. data/lib/coradoc/html/theme/modern/components/ui_components.rb +0 -344
  146. data/lib/coradoc/html/theme/modern/css_generator.rb +0 -311
  147. data/lib/coradoc/html/theme/modern/javascript_generator.rb +0 -314
  148. data/lib/coradoc/html/theme/modern/serializers/document_serializer.rb +0 -382
  149. data/lib/coradoc/html/theme/modern/tailwind_config_builder.rb +0 -164
  150. data/lib/coradoc/html/theme/modern/vue_template_generator.rb +0 -374
  151. data/lib/coradoc/html/theme/modern_renderer.rb +0 -250
  152. data/lib/coradoc/html/theme/registry.rb +0 -153
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef32c1399675f7e55b4ab77c56dd992b246c0f5fc0d42f027a4792c35b67ed05
4
- data.tar.gz: be81a3f8b9baa8dd31515bfeb32b134761271e4066d53cbeb57856a6735a4c77
3
+ metadata.gz: d86ee1dfe0630fc0923c8bbaaf53a3a9653faf3a90f3fa6760e2abe765cc46a3
4
+ data.tar.gz: 228cb361cb1b9a7dc64823788fac88afa87e5d972049064ffdd51d9909ad11a4
5
5
  SHA512:
6
- metadata.gz: 7e2696c2a2e80fb3059881b2ef7a4dbd124f8ca252b1b2fed68590324ae7d875c0d178349647be091547cf7d9143b64b75286abd55a5059dd8d91e15aff55715
7
- data.tar.gz: 5ccdc1ff38c8c851f0923deebddbe933488820738a6fb2faa1ed02d3262ca559e41d0c0d9b85e4fb5954a7809cf18ff7b1158dc960f5bfa973404c3749edbdda
6
+ metadata.gz: c219dbf71096377f684cd4ac7888e63248f1bf0ae279aec7e64923a1188bab59e57db330f4582cf5801155f2bfd061746c88dc4e61d79550130782459fd4b5e5
7
+ data.tar.gz: db6bb17213127a330405a09785ae40a54c45c7ebfa5cf4f00709efeffe0534827401aa502e9fb10a3c6ab51c17cf257ad3129ffa7650d53c5a6f64c141954f50
@@ -1,9 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'nokogiri'
4
+
3
5
  module Coradoc
4
6
  module Html
5
- # HTML configuration and options
6
7
  module Config
8
+ DEFAULT_LANG = 'en'
9
+ DEFAULT_TITLE = 'Untitled'
10
+
7
11
  # Default HTML output options
8
12
  DEFAULT_OPTIONS = {
9
13
  # Theme system options
@@ -225,7 +229,11 @@ module Coradoc
225
229
  # Build CSS link tag
226
230
  def css_link_tag(options = {})
227
231
  href = stylesheet_path(options)
228
- %(<link rel="stylesheet" href="#{href}">)
232
+ doc = Nokogiri::HTML::Document.new
233
+ node = Nokogiri::XML::Node.new('link', doc)
234
+ node['rel'] = 'stylesheet'
235
+ node['href'] = href
236
+ node.to_html
229
237
  end
230
238
 
231
239
  # Build CSS style tag with embedded content
@@ -236,14 +244,14 @@ module Coradoc
236
244
  content = css_content
237
245
  content += "\n\n#{custom_css}" if custom_css && !custom_css.empty?
238
246
 
239
- %(<style>\n#{content}\n</style>)
247
+ build_text_element('style', content)
240
248
  end
241
249
 
242
250
  # Build custom CSS style tag
243
251
  def custom_css_tag(custom_css)
244
252
  return '' unless custom_css && !custom_css.empty?
245
253
 
246
- %(<style>\n#{custom_css}\n</style>)
254
+ build_text_element('style', custom_css)
247
255
  end
248
256
 
249
257
  # Determine whether to embed or link CSS
@@ -305,7 +313,11 @@ module Coradoc
305
313
  # Build JavaScript link tag
306
314
  def js_link_tag(options = {})
307
315
  src = javascript_path(options)
308
- %(<script src="#{src}" defer></script>)
316
+ doc = Nokogiri::HTML::Document.new
317
+ node = Nokogiri::XML::Node.new('script', doc)
318
+ node['src'] = src
319
+ node['defer'] = ''
320
+ node.to_html
309
321
  end
310
322
 
311
323
  # Build JavaScript script tag with embedded content
@@ -313,7 +325,7 @@ module Coradoc
313
325
  js_content = embedded_javascript(options)
314
326
  return '' if js_content.empty?
315
327
 
316
- %(<script>\n#{js_content}\n</script>)
328
+ build_text_element('script', js_content)
317
329
  end
318
330
 
319
331
  # Build complete JavaScript tags (link or embedded)
@@ -378,14 +390,19 @@ module Coradoc
378
390
  # @return [String] HTML tags for Highlight.js
379
391
  def highlightjs_tags(options = {})
380
392
  theme = options[:highlightjs_theme] || DEFAULT_OPTIONS[:highlightjs_theme]
381
- tags = []
393
+ doc = Nokogiri::HTML::Document.new
382
394
 
383
- # Add Highlight.js library
384
- tags << %(<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/#{theme}.min.css">)
385
- tags << %(<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>)
386
- tags << %(<script>hljs.highlightAll();</script>)
395
+ link_node = Nokogiri::XML::Node.new('link', doc)
396
+ link_node['rel'] = 'stylesheet'
397
+ link_node['href'] = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/#{theme}.min.css"
387
398
 
388
- tags.join("\n")
399
+ script_node = Nokogiri::XML::Node.new('script', doc)
400
+ script_node['src'] = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js'
401
+
402
+ init_node = Nokogiri::XML::Node.new('script', doc)
403
+ init_node.content = 'hljs.highlightAll();'
404
+
405
+ [link_node.to_html, script_node.to_html, init_node.to_html].join("\n")
389
406
  end
390
407
 
391
408
  # Get data attributes for code block
@@ -461,6 +478,13 @@ module Coradoc
461
478
  line_break: 'br',
462
479
  admonition: 'div'
463
480
  }.freeze
481
+
482
+ def build_text_element(tag_name, content)
483
+ doc = Nokogiri::HTML::Document.new
484
+ node = Nokogiri::XML::Node.new(tag_name, doc)
485
+ node.content = content
486
+ node.to_html
487
+ end
464
488
  end
465
489
  end
466
490
  end
@@ -23,6 +23,21 @@ module Coradoc
23
23
  # Error class for unsupported document types
24
24
  class UnsupportedDocumentError < Coradoc::Error; end
25
25
 
26
+ # Base class for output converter configurations.
27
+ #
28
+ # Provides shared `merge` and `defaults` patterns.
29
+ # Subclasses define `initialize`, `to_h`, and `validate!`.
30
+ class ConfigurationBase
31
+ def self.defaults
32
+ new
33
+ end
34
+
35
+ def merge(other)
36
+ other_hash = other.is_a?(self.class) ? other.to_h : other.to_h.transform_keys(&:to_sym)
37
+ self.class.new(**to_h, **other_hash)
38
+ end
39
+ end
40
+
26
41
  attr_reader :document, :config
27
42
 
28
43
  # Initialize a new converter instance
@@ -80,24 +95,8 @@ module Coradoc
80
95
  new(document, config).to_file(output_path)
81
96
  end
82
97
 
83
- # Get the converter name
84
- #
85
- # @return [Symbol] Converter name (e.g., :static, :spa)
86
- def converter_name
87
- @converter_name ||= self.class.name.split('::').last
88
- .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
89
- .gsub(/([a-z\d])([A-Z])/, '\1_\2')
90
- .downcase
91
- .to_sym
92
- end
93
-
94
98
  protected
95
99
 
96
- # Validate the input document
97
- #
98
- # @param document [Object] The document to validate
99
- # @return [Coradoc::CoreModel::Base] The validated document
100
- # @raise [UnsupportedDocumentError] if document is not valid
101
100
  def validate_input(document)
102
101
  # Handle transformer hash output
103
102
  document = Coradoc::Transformer.transform(document) if document.is_a?(Hash) && document.key?(:document)
@@ -113,64 +112,23 @@ module Coradoc
113
112
  document
114
113
  end
115
114
 
116
- # Build configuration from options
117
- #
118
- # @param config [Hash, Object] Configuration options or object
119
- # @return [Object] Built configuration object
120
115
  def build_config(config)
121
- if config.public_methods.include?(:validate!)
122
- config.validate!
123
- return config
124
- end
116
+ klass = configuration_class
117
+ return config unless klass
125
118
 
126
- config
127
- end
128
-
129
- def extract_document_title
130
- if @document.is_a?(Coradoc::CoreModel::StructuralElement) && @document.title
131
- title = @document.title
132
- return title if title.is_a?(String)
133
- return title.text if title.is_a?(Coradoc::CoreModel::Base) && title.text
134
-
135
- return title.to_s
136
- end
137
-
138
- 'Untitled Document'
139
- end
140
-
141
- def extract_text_from_content(content)
142
- case content
143
- when Array
144
- content.map { |item| extract_text_from_content(item) }.join
145
- when String
146
- content
147
- when Coradoc::CoreModel::InlineElement
148
- content.content.to_s
149
- when Coradoc::CoreModel::Base
150
- if content.content
151
- extract_text_from_content(content.content)
152
- else
153
- content.to_s
154
- end
119
+ case config
120
+ when klass
121
+ config.validate!
122
+ config
123
+ when Hash
124
+ klass.new(**config)
155
125
  else
156
- content.to_s
126
+ klass.defaults
157
127
  end
158
128
  end
159
129
 
160
- # Escape HTML content
161
- #
162
- # @param text [String] Text to escape
163
- # @return [String] Escaped text
164
- def escape_html(text)
165
- Coradoc::Html::Base.escape_html(text.to_s)
166
- end
167
-
168
- # Escape HTML attribute value
169
- #
170
- # @param value [String] Value to escape
171
- # @return [String] Escaped value
172
- def escape_attr(value)
173
- value.to_s.gsub('"', '&quot;').gsub('<', '&lt;').gsub('>', '&gt;')
130
+ def configuration_class
131
+ nil
174
132
  end
175
133
  end
176
134
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Html
5
+ module Drop
6
+ class AnnotationDrop < Base
7
+ def template_type
8
+ 'annotation_block'
9
+ end
10
+
11
+ def annotation_type
12
+ (@model.annotation_type || 'note').to_s.downcase
13
+ end
14
+
15
+ def label
16
+ Escape.escape_html(@model.annotation_label || annotation_type.upcase)
17
+ end
18
+
19
+ def content
20
+ content_to_liquid(@model.renderable_content)
21
+ end
22
+
23
+ def css_class
24
+ "admonitionblock #{annotation_type}"
25
+ end
26
+ end
27
+
28
+ DropFactory.register(CoreModel::AnnotationBlock, AnnotationDrop)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'liquid'
4
+
5
+ module Coradoc
6
+ module Html
7
+ module Drop
8
+ class Base < Liquid::Drop
9
+ attr_reader :model
10
+
11
+ def initialize(model)
12
+ @model = model
13
+ end
14
+
15
+ def to_liquid
16
+ self
17
+ end
18
+
19
+ def template_type
20
+ self.class.name
21
+ .split('::').last
22
+ .sub(/Drop$/, '')
23
+ .gsub(/([A-Z])/, '_\1')
24
+ .downcase
25
+ .sub(/^_/, '')
26
+ end
27
+
28
+ def id
29
+ @model.id
30
+ end
31
+
32
+ def title
33
+ optional_text(@model.title)
34
+ end
35
+
36
+ protected
37
+
38
+ def optional_text(value)
39
+ return nil unless value && !value.to_s.empty?
40
+
41
+ Escape.escape_html(value)
42
+ end
43
+
44
+ def extract_text(content)
45
+ case content
46
+ when nil then ''
47
+ when String then content
48
+ when Array then content.map { |c| extract_text(c) }.join
49
+ when CoreModel::InlineElement
50
+ content.text || extract_text(content.content)
51
+ when CoreModel::TextContent
52
+ content.text.to_s
53
+ when CoreModel::Base
54
+ TitleText.resolve(content).to_s
55
+ else
56
+ content.to_s
57
+ end
58
+ end
59
+
60
+ def content_to_liquid(content)
61
+ DropFactory.create(content)
62
+ end
63
+
64
+ def children_to_liquid(children)
65
+ return [] unless children
66
+
67
+ children.map { |child| DropFactory.create(child) }
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ # Load DropFactory and all drops after Base is fully defined.
75
+ # Each drop self-registers; DropFactory sorts by type specificity
76
+ # so registration order doesn't matter.
77
+ require_relative 'drop_factory'
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Html
5
+ module Drop
6
+ class BibliographyDrop < Base
7
+ def entries
8
+ children_to_liquid(@model.entries)
9
+ end
10
+ end
11
+
12
+ DropFactory.register(CoreModel::Bibliography, BibliographyDrop)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Html
5
+ module Drop
6
+ class BibliographyEntryDrop < Base
7
+ def anchor_name
8
+ n = @model.anchor_name
9
+ n && !n.to_s.empty? ? n : nil
10
+ end
11
+
12
+ def document_id
13
+ optional_text(@model.document_id)
14
+ end
15
+
16
+ def ref_text
17
+ optional_text(@model.ref_text)
18
+ end
19
+ end
20
+
21
+ DropFactory.register(CoreModel::BibliographyEntry, BibliographyEntryDrop)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Html
5
+ module Drop
6
+ class BlockDrop < Base
7
+ SEMANTIC_TAG_MAP = {
8
+ paragraph: 'p', source_code: 'pre', quote: 'blockquote',
9
+ verse: 'blockquote', example: 'div', sidebar: 'aside',
10
+ literal: 'pre', listing: 'pre', open: 'div',
11
+ horizontal_rule: 'hr'
12
+ }.freeze
13
+
14
+ SEMANTIC_CLASS_MAP = {
15
+ example: 'example', sidebar: 'sidebar', literal: 'literal'
16
+ }.freeze
17
+
18
+ def semantic_type
19
+ resolved_semantic_type.to_s
20
+ end
21
+
22
+ def html_tag
23
+ SEMANTIC_TAG_MAP[resolved_semantic_type] || 'div'
24
+ end
25
+
26
+ def language
27
+ @model.language || @model.metadata('language')
28
+ end
29
+
30
+ def css_class
31
+ cls = SEMANTIC_CLASS_MAP[resolved_semantic_type]
32
+ cls ? "block-#{semantic_type} #{cls}" : "block-#{semantic_type}"
33
+ end
34
+
35
+ def content
36
+ content_to_liquid(@model.renderable_content)
37
+ end
38
+
39
+ def text
40
+ if %i[source_code literal listing].include?(resolved_semantic_type)
41
+ Escape.escape_html(@model.flat_text)
42
+ elsif resolved_semantic_type == :pass
43
+ @model.flat_text.to_s
44
+ end
45
+ end
46
+
47
+ def hidden?
48
+ %i[comment reviewer].include?(resolved_semantic_type)
49
+ end
50
+
51
+ def raw?
52
+ resolved_semantic_type == :pass
53
+ end
54
+
55
+ def hr?
56
+ resolved_semantic_type == :horizontal_rule
57
+ end
58
+
59
+ private
60
+
61
+ def resolved_semantic_type
62
+ @resolved_semantic_type ||= @model.resolve_semantic_type || :paragraph
63
+ end
64
+ end
65
+
66
+ DropFactory.register(CoreModel::Block, BlockDrop)
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Html
5
+ module Drop
6
+ class DefinitionItemDrop < Base
7
+ def term
8
+ Escape.escape_html(stripped_term)
9
+ end
10
+
11
+ def term_id
12
+ match = term_text.match(/\A\[\[([^\]]+)\]\]/)
13
+ match&.[](1)
14
+ end
15
+
16
+ def definitions
17
+ return [] unless @model.definitions
18
+
19
+ @model.definitions.map { |d| content_to_liquid(d) }
20
+ end
21
+
22
+ private
23
+
24
+ def term_text
25
+ @term_text ||= @model.term.to_s
26
+ end
27
+
28
+ def stripped_term
29
+ term_text.sub(/\A\[\[[^\]]+\]\]/, '')
30
+ end
31
+ end
32
+
33
+ DropFactory.register(CoreModel::DefinitionItem, DefinitionItemDrop)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Html
5
+ module Drop
6
+ class DefinitionListDrop < Base
7
+ def items
8
+ children_to_liquid(@model.items)
9
+ end
10
+ end
11
+
12
+ DropFactory.register(CoreModel::DefinitionList, DefinitionListDrop)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Html
5
+ module Drop
6
+ class DocumentDrop < Base
7
+ include SectionNumberable
8
+
9
+ def template_type
10
+ return 'document' if @model.is_a?(CoreModel::DocumentElement)
11
+
12
+ 'section'
13
+ end
14
+
15
+ def title
16
+ text = TitleText.resolve(@model.title)
17
+ return nil unless text && !text.empty?
18
+
19
+ if @section_number
20
+ Escape.escape_html("#{@section_number}. #{text}")
21
+ else
22
+ Escape.escape_html(text)
23
+ end
24
+ end
25
+
26
+ def children
27
+ children_to_liquid(@model.children)
28
+ end
29
+
30
+ def structural_type
31
+ case @model
32
+ when CoreModel::DocumentElement then 'document'
33
+ when CoreModel::SectionElement then 'section'
34
+ when CoreModel::HeaderElement then 'header'
35
+ when CoreModel::PreambleElement then 'preamble'
36
+ else 'structural'
37
+ end
38
+ end
39
+
40
+ def heading_level
41
+ if @model.is_a?(CoreModel::SectionElement)
42
+ [@model.heading_level + 1, 6].min
43
+ else
44
+ 1
45
+ end
46
+ end
47
+ end
48
+
49
+ DropFactory.register(CoreModel::StructuralElement, DocumentDrop)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Coradoc
6
+ module Html
7
+ module Drop
8
+ module DropFactory
9
+ @registry = []
10
+
11
+ def self.register(model_class, drop_class)
12
+ @registry << [model_class, drop_class]
13
+ sort_registry!
14
+ end
15
+
16
+ def self.create(obj)
17
+ return nil if obj.nil?
18
+ return obj.map { |o| create(o) } if obj.is_a?(Array)
19
+ return Escape.escape_html(obj) if obj.is_a?(String)
20
+ return obj.to_s if obj.is_a?(Numeric) || obj.is_a?(TrueClass) || obj.is_a?(FalseClass)
21
+
22
+ pair = lookup_pair(obj)
23
+ return pair.last.new(obj) if pair
24
+
25
+ Escape.escape_html(obj.to_s)
26
+ end
27
+
28
+ def self.drop_class_for(model)
29
+ pair = lookup_pair(model)
30
+ pair&.last
31
+ end
32
+
33
+ def self.template_type_for(model)
34
+ drop = drop_class_for(model)
35
+ drop&.new(model)&.template_type
36
+ end
37
+
38
+ class << self
39
+ private
40
+
41
+ def lookup_pair(obj)
42
+ @registry.find { |klass, _drop_class| obj.is_a?(klass) }
43
+ end
44
+
45
+ def sort_registry!
46
+ @registry.sort_by! { |klass, _| -klass.ancestors.length }
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ # Load all drops — each self-registers with DropFactory
55
+ require_relative 'annotation_drop'
56
+ require_relative 'block_drop'
57
+ require_relative 'list_block_drop'
58
+ require_relative 'list_item_drop'
59
+ require_relative 'table_drop'
60
+ require_relative 'table_row_drop'
61
+ require_relative 'table_cell_drop'
62
+ require_relative 'image_drop'
63
+ require_relative 'inline_element_drop'
64
+ require_relative 'bibliography_entry_drop'
65
+ require_relative 'bibliography_drop'
66
+ require_relative 'toc_entry_drop'
67
+ require_relative 'toc_drop'
68
+ require_relative 'definition_item_drop'
69
+ require_relative 'definition_list_drop'
70
+ require_relative 'term_drop'
71
+ require_relative 'footnote_drop'
72
+ require_relative 'text_content_drop'
73
+ require_relative 'document_drop'
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Html
5
+ module Drop
6
+ class FootnoteDrop < Base
7
+ def footnote_id
8
+ @model.id || ''
9
+ end
10
+
11
+ def content
12
+ Escape.escape_html(extract_text(@model.content || @model.inline_content))
13
+ end
14
+
15
+ def inline?
16
+ footnote_id.empty?
17
+ end
18
+ end
19
+
20
+ DropFactory.register(CoreModel::FootnoteReference, FootnoteDrop)
21
+ DropFactory.register(CoreModel::Footnote, FootnoteDrop)
22
+ end
23
+ end
24
+ end