Module: Coradoc::Html::ElementMapping

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

Overview

Element mapping between CoreModel and HTML elements

This module provides bidirectional mapping between CoreModel types and HTML elements for conversion purposes.

Constant Summary collapse

MODEL_TO_HTML =

Mapping from CoreModel types to HTML elements

{
  # Document structure
  document: { tag: 'article', semantic: true },
  section: { tag: 'section', semantic: true },
  header: { tag: 'header', semantic: true },
  title: { tag: 'h1', semantic: true },
  structuralelement: { tag: 'section', semantic: true },

  # Block elements
  paragraph: { tag: 'p', semantic: true },
  block: { tag: 'div', semantic: true },
  example: { tag: 'div', class: 'example', semantic: false },
  annotationblock: { tag: 'aside', semantic: true },
  quote: { tag: 'blockquote', semantic: true },
  verse: { tag: 'div', class: 'verse', semantic: false },
  listing: { tag: 'pre', semantic: true },
  literal: { tag: 'pre', semantic: true },
  source: { tag: 'pre', semantic: true },
  open: { tag: 'div', semantic: false },
  pass: { tag: 'div', class: 'pass', semantic: false },

  # Inline elements
  inlineelement: { tag: 'span', semantic: false },
  bold: { tag: 'strong', semantic: true },
  italic: { tag: 'em', semantic: true },
  monospace: { tag: 'code', semantic: true },
  highlight: { tag: 'mark', semantic: true },
  superscript: { tag: 'sup', semantic: true },
  subscript: { tag: 'sub', semantic: true },
  underline: { tag: 'u', semantic: false },
  strikethrough: { tag: 'del', semantic: true },
  smallcaps: { tag: 'span', class: 'small-caps', semantic: false },
  link: { tag: 'a', semantic: true },
  anchor: { tag: 'a', semantic: true },
  xref: { tag: 'a', class: 'xref', semantic: true },
  quotation: { tag: 'q', semantic: true },

  # Lists
  listblock: { tag: 'ul', semantic: true },
  listitem: { tag: 'li', semantic: true },
  orderedlist: { tag: 'ol', semantic: true },
  unorderedlist: { tag: 'ul', semantic: true },

  # Tables
  table: { tag: 'table', semantic: true },
  tablerow: { tag: 'tr', semantic: true },
  tablecell: { tag: 'td', semantic: true },

  # Media
  image: { tag: 'img', semantic: true, self_closing: true },
  video: { tag: 'video', semantic: true },
  audio: { tag: 'audio', semantic: true },

  # Other
  break: { tag: 'hr', semantic: true, self_closing: true },
  linebreak: { tag: 'br', semantic: true, self_closing: true },

  # Text
  textelement: { tag: 'text', semantic: false }
}.freeze
HTML_TO_MODEL =

Mapping from HTML elements to CoreModel types

{
  # Block elements
  p: 'Coradoc::CoreModel::Block',
  div: 'Coradoc::CoreModel::Block',
  section: 'Coradoc::CoreModel::StructuralElement',
  article: 'Coradoc::CoreModel::StructuralElement',
  header: 'Coradoc::CoreModel::StructuralElement',
  aside: 'Coradoc::CoreModel::AnnotationBlock',
  blockquote: 'Coradoc::CoreModel::Block',
  pre: 'Coradoc::CoreModel::Block',

  # Inline elements
  strong: 'Coradoc::CoreModel::InlineElement',
  b: 'Coradoc::CoreModel::InlineElement',
  em: 'Coradoc::CoreModel::InlineElement',
  i: 'Coradoc::CoreModel::InlineElement',
  code: 'Coradoc::CoreModel::InlineElement',
  mark: 'Coradoc::CoreModel::InlineElement',
  sup: 'Coradoc::CoreModel::InlineElement',
  sub: 'Coradoc::CoreModel::InlineElement',
  u: 'Coradoc::CoreModel::InlineElement',
  del: 'Coradoc::CoreModel::InlineElement',
  s: 'Coradoc::CoreModel::InlineElement',
  strike: 'Coradoc::CoreModel::InlineElement',

  # Links
  a: 'Coradoc::CoreModel::InlineElement',

  # Lists
  ul: 'Coradoc::CoreModel::ListBlock',
  ol: 'Coradoc::CoreModel::ListBlock',
  li: 'Coradoc::CoreModel::ListItem',
  dl: 'Coradoc::CoreModel::ListBlock',
  dt: 'Coradoc::CoreModel::ListItem',
  dd: 'Coradoc::CoreModel::ListItem',

  # Tables
  table: 'Coradoc::CoreModel::Table',
  tr: 'Coradoc::CoreModel::TableRow',
  td: 'Coradoc::CoreModel::TableCell',
  th: 'Coradoc::CoreModel::TableCell',

  # Media
  img: 'Coradoc::CoreModel::Image',
  video: 'Coradoc::CoreModel::Block',
  audio: 'Coradoc::CoreModel::Block',

  # Other
  hr: 'Coradoc::CoreModel::Block',
  br: 'Coradoc::CoreModel::InlineElement',

  # Headings
  h1: 'Coradoc::CoreModel::StructuralElement',
  h2: 'Coradoc::CoreModel::StructuralElement',
  h3: 'Coradoc::CoreModel::StructuralElement',
  h4: 'Coradoc::CoreModel::StructuralElement',
  h5: 'Coradoc::CoreModel::StructuralElement',
  h6: 'Coradoc::CoreModel::StructuralElement'
}.freeze
BLOCK_ELEMENTS =

Block-level HTML elements

%i[
  div p section article aside header footer main nav
  blockquote pre ul ol li dl dt dd
  table tr td th thead tbody tfoot
  h1 h2 h3 h4 h5 h6
  hr
  figure figcaption
].freeze
INLINE_ELEMENTS =

Inline-level HTML elements

%i[
  span strong em b i u s del ins mark small
  code kbd samp var
  a abbr cite dfn q
  sub sup
  time
  br wbr
].freeze
SELF_CLOSING_ELEMENTS =

Self-closing HTML elements

%i[
  area base br col embed hr img input link meta param source track wbr
].freeze

Class Method Summary collapse

Class Method Details

.block_element?(tag) ⇒ Boolean

Check if HTML element is block-level

Returns:

  • (Boolean)


169
170
171
# File 'lib/coradoc/html/element_mapping.rb', line 169

def block_element?(tag)
  BLOCK_ELEMENTS.include?(tag.to_sym)
end

.default_element_for(model_class) ⇒ Object

Get default element for a model class



24
25
26
27
28
29
30
# File 'lib/coradoc/html/element_mapping.rb', line 24

def default_element_for(model_class)
  if model_class.ancestors.any? { |a| a.name&.include?('InlineElement') }
    { tag: 'span', semantic: false }
  else
    { tag: 'div', semantic: false }
  end
end

.default_model_for(tag, _context) ⇒ Object

Get default model for an HTML element



33
34
35
36
37
38
39
40
41
42
43
# File 'lib/coradoc/html/element_mapping.rb', line 33

def default_model_for(tag, _context)
  # Return CoreModel types
  case tag
  when :p, :div, :section, :article
    'Coradoc::CoreModel::Block'
  when :strong, :b, :em, :i, :code
    'Coradoc::CoreModel::InlineElement'
  else
    'Coradoc::CoreModel::InlineElement'
  end
end

.html_element_to_model(tag_name, context = {}) ⇒ Object

Map HTML element to CoreModel class



18
19
20
21
# File 'lib/coradoc/html/element_mapping.rb', line 18

def html_element_to_model(tag_name, context = {})
  tag = tag_name.to_s.downcase.to_sym
  HTML_TO_MODEL[tag] || default_model_for(tag, context)
end

.inline_element?(tag) ⇒ Boolean

Check if HTML element is inline-level

Returns:

  • (Boolean)


174
175
176
# File 'lib/coradoc/html/element_mapping.rb', line 174

def inline_element?(tag)
  INLINE_ELEMENTS.include?(tag.to_sym)
end

.model_to_html_element(model_class) ⇒ Object

Map CoreModel class to HTML element



12
13
14
15
# File 'lib/coradoc/html/element_mapping.rb', line 12

def model_to_html_element(model_class)
  model_name = model_class.name.split('::').last.downcase.to_sym
  MODEL_TO_HTML[model_name] || default_element_for(model_class)
end

.self_closing?(tag) ⇒ Boolean

Check if HTML element is self-closing

Returns:

  • (Boolean)


179
180
181
# File 'lib/coradoc/html/element_mapping.rb', line 179

def self_closing?(tag)
  SELF_CLOSING_ELEMENTS.include?(tag.to_sym)
end