Module: Coradoc::Html::Config

Defined in:
lib/coradoc/html/config.rb

Overview

HTML configuration and options

Constant Summary collapse

DEFAULT_OPTIONS =

Default HTML output options

{
  # Theme system options
  theme: :classic,
  modern: {
    # Appearance
    color_scheme: :glass,
    primary_color: '#6366f1',
    accent_color: '#8b5cf6',

    # Layout
    max_width: '1200px',
    content_width: '65ch',
    sidebar_width: '280px',

    # Features
    theme_toggle: true,
    reading_progress: true,
    back_to_top: true,
    toc_sticky: true,
    copy_code_buttons: true,

    # Animation
    enable_animations: true,
    animation_duration: '300ms',

    # Performance
    lazy_load_images: true
  }.freeze,

  # HTML version
  html_version: :html5,

  # Formatting options
  pretty_print: false,
  indent: '  ',
  line_wrap: 0,

  # Content options
  escape_content: true,
  preserve_whitespace: false,
  convert_line_breaks: true,
  preserve_comments: false,

  # Element options
  use_semantic_elements: true,
  add_css_classes: true,
  add_data_attributes: false,

  # Link options
  external_link_target: nil,
  link_rel: nil,

  # Image options
  image_loading: nil,
  image_decoding: nil,

  # Code block options
  syntax_highlighter: nil,
  syntax_highlighter_opts: {},

  # Table options
  table_border: false,
  table_stripes: false,

  # Attribute options
  preserve_custom_attributes: true,
  attribute_prefix: 'data-',

  # CSS & Styling options
  stylesheet: 'coradoc.css',
  stylesdir: './css',
  linkcss: false,
  copycss: true,
  css_theme: 'professional',
  custom_css: nil,

  # JavaScript options
  javascript: 'coradoc.js',
  jsdir: './js',
  linkjs: false,
  theme_toggle: true,
  toc_interactive: nil,

  # Document metadata options
  author: nil,
  description: nil,
  keywords: nil,
  lang: 'en',
  embedded: false,
  meta_tags: {},

  # Table of contents options
  toc: false,
  toclevels: 2,
  toc_title: 'Table of Contents',
  toc_placement: :auto,

  # Section numbering options
  sectnums: false,
  sectnumlevels: 3,

  # Syntax highlighting options
  source_highlighter: nil,
  highlightjs_theme: 'github',
  pygments_style: 'default',
  rouge_style: 'github'
}.freeze
TAG_MAPPING =

Mapping of Coradoc elements to HTML tags

{
  # Sections
  section: 'section',
  header: 'header',

  # Blocks
  paragraph: 'p',
  example: 'div',
  sidebar: 'aside',
  quote: 'blockquote',
  verse: 'div',
  listing: 'pre',
  literal: 'pre',
  source: 'pre',
  open: 'div',

  # Lists
  ordered_list: 'ol',
  unordered_list: 'ul',
  list_item: 'li',
  description_list: 'dl',
  description_term: 'dt',
  description_detail: 'dd',

  # Tables
  table: 'table',
  table_row: 'tr',
  table_cell: 'td',
  table_header: 'th',

  # Inline
  bold: 'strong',
  italic: 'em',
  monospace: 'code',
  highlight: 'mark',
  superscript: 'sup',
  subscript: 'sub',
  underline: 'u',
  strikethrough: 'del',
  small_caps: 'span',

  # Links
  anchor: 'a',
  cross_reference: 'a',

  # Media
  image: 'img',
  video: 'video',
  audio: 'audio',

  # Other
  break: 'hr',
  line_break: 'br',
  admonition: 'div'
}.freeze

Class Method Summary collapse

Class Method Details

.code_block_attributes(language, options = {}) ⇒ Hash

Get data attributes for code block

Parameters:

  • language (String)

    Programming language

  • options (Hash) (defaults to: {})

    Code block options

Returns:

  • (Hash)

    Data attributes



395
396
397
398
399
400
401
402
403
404
405
406
# File 'lib/coradoc/html/config.rb', line 395

def code_block_attributes(language, options = {})
  attrs = {}

  attrs[:class] = "language-#{language}" if language && !language.empty?

  if options[:linenums] || options[:line_numbers]
    attrs[:class] =
      [attrs[:class], 'line-numbers'].compact.join(' ')
  end

  attrs
end

.css_class_for(element_type, role = nil) ⇒ Object

Get CSS class for element type



138
139
140
141
142
# File 'lib/coradoc/html/config.rb', line 138

def css_class_for(element_type, role = nil)
  classes = [element_type.to_s.tr('_', '-')]
  classes << role if role
  classes.join(' ')
end

Build CSS link tag



226
227
228
229
# File 'lib/coradoc/html/config.rb', line 226

def css_link_tag(options = {})
  href = stylesheet_path(options)
  %(<link rel="stylesheet" href="#{href}">)
end

.css_style_tag(options = {}) ⇒ Object

Build CSS style tag with embedded content



232
233
234
235
236
237
238
239
240
# File 'lib/coradoc/html/config.rb', line 232

def css_style_tag(options = {})
  css_content = embedded_stylesheet(options)
  custom_css = options[:custom_css]

  content = css_content
  content += "\n\n#{custom_css}" if custom_css && !custom_css.empty?

  %(<style>\n#{content}\n</style>)
end

.css_tags(options = {}) ⇒ Object

Build complete CSS tags (link or embedded, plus custom)



257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/coradoc/html/config.rb', line 257

def css_tags(options = {})
  tags = []

  if embed_css?(options)
    # Embedded mode: include full stylesheet in style tag
    tags << css_style_tag(options)
  else
    # Linked mode: link to external stylesheet
    tags << css_link_tag(options)
    # Add custom CSS separately if provided
    tags << custom_css_tag(options[:custom_css]) if options[:custom_css]
  end

  tags.join("\n")
end

.custom_css_tag(custom_css) ⇒ Object

Build custom CSS style tag



243
244
245
246
247
# File 'lib/coradoc/html/config.rb', line 243

def custom_css_tag(custom_css)
  return '' unless custom_css && !custom_css.empty?

  %(<style>\n#{custom_css}\n</style>)
end

.data_attribute_name(name, prefix: 'data-') ⇒ Object

Get data attribute name



145
146
147
# File 'lib/coradoc/html/config.rb', line 145

def data_attribute_name(name, prefix: 'data-')
  "#{prefix}#{name.to_s.tr('_', '-')}"
end

.default_optionsObject

Get default options



118
119
120
# File 'lib/coradoc/html/config.rb', line 118

def default_options
  DEFAULT_OPTIONS.dup
end

.element_config(element_type, options = {}) ⇒ Object

Build element configuration



150
151
152
153
154
155
156
# File 'lib/coradoc/html/config.rb', line 150

def element_config(element_type, options = {})
  {
    tag: html_tag_for(element_type),
    css_class: css_class_for(element_type, options[:role]),
    attributes: options[:attributes] || {}
  }
end

.embed_css?(options = {}) ⇒ Boolean

Determine whether to embed or link CSS

Returns:

  • (Boolean)


250
251
252
253
254
# File 'lib/coradoc/html/config.rb', line 250

def embed_css?(options = {})
  # Embed if linkcss is false or embedded mode is true
  !options.fetch(:linkcss, DEFAULT_OPTIONS[:linkcss]) ||
    options.fetch(:embedded, DEFAULT_OPTIONS[:embedded])
end

.embed_js?(options = {}) ⇒ Boolean

Determine whether to embed or link JavaScript

Returns:

  • (Boolean)


274
275
276
277
278
279
# File 'lib/coradoc/html/config.rb', line 274

def embed_js?(options = {})
  # Embed if linkjs is false, embedded mode is true, or linkcss is false (to match CSS behavior)
  !options.fetch(:linkjs, DEFAULT_OPTIONS[:linkjs]) ||
    options.fetch(:embedded, DEFAULT_OPTIONS[:embedded]) ||
    !options.fetch(:linkcss, DEFAULT_OPTIONS[:linkcss])
end

.embedded_javascript(options = {}) ⇒ Object

Get embedded JavaScript content



294
295
296
297
298
299
300
301
302
303
# File 'lib/coradoc/html/config.rb', line 294

def embedded_javascript(options = {})
  javascript_name = options[:javascript] || DEFAULT_OPTIONS[:javascript]
  asset_path = File.join(__dir__, 'assets', 'js', javascript_name)

  if File.exist?(asset_path)
    File.read(asset_path)
  else
    ''
  end
end

.embedded_stylesheet(options = {}) ⇒ Object

Get embedded stylesheet content



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/coradoc/html/config.rb', line 178

def embedded_stylesheet(options = {})
  css_theme = options[:css_theme] || DEFAULT_OPTIONS[:css_theme]
  stylesheet_name = "#{css_theme}.css"

  # Try themes directory first
  themes_path = File.join(__dir__, 'assets', 'themes', stylesheet_name)
  asset_path = if File.exist?(themes_path)
                 themes_path
               else
                 # Fall back to assets directory for backward compatibility
                 File.join(__dir__, 'assets', stylesheet_name)
               end

  css_content = if File.exist?(asset_path)
                  File.read(asset_path)
                else
                  # Fallback to default coradoc.css
                  default_path = File.join(__dir__, 'assets', 'coradoc.css')
                  File.exist?(default_path) ? File.read(default_path) : ''
                end

  # Resolve @import statements for embedded CSS
  # @import doesn't work in inline <style> tags
  resolve_css_imports(css_content, File.dirname(asset_path))
end

.highlightjs_tags(options = {}) ⇒ String

Build Highlight.js tags

Parameters:

  • options (Hash) (defaults to: {})

    Configuration options

Returns:

  • (String)

    HTML tags for Highlight.js



379
380
381
382
383
384
385
386
387
388
389
# File 'lib/coradoc/html/config.rb', line 379

def highlightjs_tags(options = {})
  theme = options[:highlightjs_theme] || DEFAULT_OPTIONS[:highlightjs_theme]
  tags = []

  # Add Highlight.js library
  tags << %(<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/#{theme}.min.css">)
  tags << %(<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>)
  tags << %(<script>hljs.highlightAll();</script>)

  tags.join("\n")
end

.html_tag_for(element_type) ⇒ Object

Map element type to HTML tag



159
160
161
# File 'lib/coradoc/html/config.rb', line 159

def html_tag_for(element_type)
  TAG_MAPPING[element_type] || 'div'
end

.javascript_path(options = {}) ⇒ Object

Get JavaScript file path



282
283
284
285
286
287
288
289
290
291
# File 'lib/coradoc/html/config.rb', line 282

def javascript_path(options = {})
  javascript = options[:javascript] || DEFAULT_OPTIONS[:javascript]
  jsdir = options[:jsdir] || DEFAULT_OPTIONS[:jsdir]

  if jsdir && jsdir != '.'
    File.join(jsdir, javascript)
  else
    javascript
  end
end

Build JavaScript link tag



306
307
308
309
# File 'lib/coradoc/html/config.rb', line 306

def js_link_tag(options = {})
  src = javascript_path(options)
  %(<script src="#{src}" defer></script>)
end

.js_script_tag(options = {}) ⇒ Object

Build JavaScript script tag with embedded content



312
313
314
315
316
317
# File 'lib/coradoc/html/config.rb', line 312

def js_script_tag(options = {})
  js_content = embedded_javascript(options)
  return '' if js_content.empty?

  %(<script>\n#{js_content}\n</script>)
end

.js_tags(options = {}) ⇒ Object

Build complete JavaScript tags (link or embedded)



320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'lib/coradoc/html/config.rb', line 320

def js_tags(options = {})
  return '' if options[:javascript] == false

  tags = []

  tags << if embed_js?(options)
            # Embedded mode: include full JavaScript in script tag
            js_script_tag(options)
          else
            # Linked mode: link to external JavaScript file
            js_link_tag(options)
          end

  tags.join("\n")
end

.merge_options(user_options = {}) ⇒ Object

Merge user options with defaults



123
124
125
# File 'lib/coradoc/html/config.rb', line 123

def merge_options(user_options = {})
  default_options.merge(user_options)
end

.resolve_css_imports(css_content, base_dir) ⇒ String

Resolve @import statements in CSS content

Parameters:

  • css_content (String)

    CSS content with potential @import statements

  • base_dir (String)

    Base directory for resolving relative imports

Returns:

  • (String)

    CSS content with imports resolved



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/coradoc/html/config.rb', line 208

def resolve_css_imports(css_content, base_dir)
  # Match @import url('...') or @import url("...") or @import '...' or @import "..."
  css_content.gsub(/@import\s+(?:url\()?['"]([^'"]+)['"]\)?;?/) do
    import_path = ::Regexp.last_match(1)
    full_path = File.join(base_dir, import_path)

    if File.exist?(full_path)
      # Read the imported file and recursively resolve its imports
      imported_content = File.read(full_path)
      resolve_css_imports(imported_content, File.dirname(full_path))
    else
      # Keep the original import if file not found
      ::Regexp.last_match(0)
    end
  end
end

.stylesheet_path(options = {}) ⇒ Object

Get stylesheet path



164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/coradoc/html/config.rb', line 164

def stylesheet_path(options = {})
  # When linking, use css_theme-based filename, not the stylesheet option
  css_theme = options[:css_theme] || DEFAULT_OPTIONS[:css_theme]
  stylesheet = "#{css_theme}.css"
  stylesdir = options[:stylesdir] || DEFAULT_OPTIONS[:stylesdir]

  if stylesdir && stylesdir != '.'
    File.join(stylesdir, stylesheet)
  else
    stylesheet
  end
end

.syntax_highlighter_tags(options = {}) ⇒ String

Build syntax highlighter tags (CSS and JS)

Parameters:

  • options (Hash) (defaults to: {})

    Configuration options

Returns:

  • (String)

    HTML tags for syntax highlighting



358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
# File 'lib/coradoc/html/config.rb', line 358

def syntax_highlighter_tags(options = {})
  highlighter = options[:source_highlighter]
  return '' unless highlighter

  case highlighter.to_sym
  when :highlightjs, :highlight_js, :'highlight.js'
    highlightjs_tags(options)
  when :pygments
    # Pygments requires server-side processing, not implemented for client-side HTML
    ''
  when :rouge
    # Rouge requires server-side processing, not implemented for client-side HTML
    ''
  else
    ''
  end
end

.theme_toggle?(options = {}) ⇒ Boolean

Check if theme toggle should be enabled

Returns:

  • (Boolean)


337
338
339
# File 'lib/coradoc/html/config.rb', line 337

def theme_toggle?(options = {})
  options.fetch(:theme_toggle, DEFAULT_OPTIONS[:theme_toggle])
end

.toc_interactive?(options = {}) ⇒ Boolean

Check if interactive TOC should be enabled

Returns:

  • (Boolean)


342
343
344
345
346
347
348
349
350
351
352
353
# File 'lib/coradoc/html/config.rb', line 342

def toc_interactive?(options = {})
  # Default to true if TOC is enabled and toc_interactive is not explicitly set to false
  toc_enabled = options.fetch(:toc, DEFAULT_OPTIONS[:toc])
  toc_interactive = options[:toc_interactive]

  # If toc_interactive is nil, default to true when TOC is enabled
  if toc_interactive.nil?
    toc_enabled
  else
    toc_interactive
  end
end

.validate_options(options) ⇒ Object

Validate options

Raises:

  • (ArgumentError)


128
129
130
131
132
133
134
135
# File 'lib/coradoc/html/config.rb', line 128

def validate_options(options)
  valid_keys = DEFAULT_OPTIONS.keys
  invalid_keys = options.keys - valid_keys

  raise ArgumentError, "Invalid options: #{invalid_keys.join(', ')}" unless invalid_keys.empty?

  options
end