class SlateSerializer::Html

Html de- and serializer

Constants

BLOCK_ELEMENTS

Default block types list

ELEMENTS

Default lookup list to convert html tags to object types

INLINE_ELEMENTS

Default inline types list

MARK_ELEMENTS

Default mark types list

Attributes

block_elements[RW]
elements[RW]
inline_elements[RW]
mark_elements[RW]

Public Class Methods

deserializer(html, options = {}) click to toggle source

Convert html to a Slate document

@param html format [String] the HTML @param options [Hash] @option options [Array] :elements Lookup list to convert html tags to object types @option options [Array] :block_elemnts List of block types @option options [Array] :inline_elemnts List of inline types @option options [Array] :mark_elemnts List of mark types

# File lib/slate_serializer/html.rb, line 46
def deserializer(html, options = {})
  return empty_state if html.nil? || html == ''

  self.elements = options[:elements] || ELEMENTS
  self.block_elements = options[:block_elements] || BLOCK_ELEMENTS
  self.inline_elements = options[:inline_elements] || INLINE_ELEMENTS
  self.mark_elements = options[:mark_elements] || MARK_ELEMENTS

  html = html.gsub('<br>', "\n")
  nodes = Nokogiri::HTML.fragment(html).elements.map do |element|
    element_to_node(element)
  end

  {
    document: {
      object: 'document',
      nodes: nodes
    }
  }
end
serializer(value) click to toggle source

Convert html to a Slate document

@param value format [Hash] the Slate document @return [String] plain text version of the Slate documnent

# File lib/slate_serializer/html.rb, line 71
def serializer(value)
  return '' unless value.key?(:document)

  serialize_node(value[:document])
end

Private Class Methods

block?(element) click to toggle source
# File lib/slate_serializer/html.rb, line 161
def block?(element)
  block_elements.include?(element.name)
end
convert_name_to_mark(name) click to toggle source
# File lib/slate_serializer/html.rb, line 149
def convert_name_to_mark(name)
  type = mark_elements[name.to_sym]

  return nil unless type

  {
    data: [],
    object: 'mark',
    type: type
  }
end
convert_name_to_type(element) click to toggle source
# File lib/slate_serializer/html.rb, line 144
def convert_name_to_type(element)
  type = [element.name, element.attributes['type']&.value].compact.join
  elements[type.to_sym] || elements[:p]
end
element_to_inline(element) click to toggle source
# File lib/slate_serializer/html.rb, line 106
def element_to_inline(element)
  type = convert_name_to_type(element)
  nodes = element.children.flat_map do |child|
    element_to_texts(child)
  end

  {
    data: element.attributes.each_with_object({}) { |a, h| h[a[1].name] = a[1].value },
    object: 'inline',
    nodes: nodes,
    type: type
  }
end
element_to_node(element) click to toggle source
# File lib/slate_serializer/html.rb, line 81
def element_to_node(element)
  type = convert_name_to_type(element)

  nodes = element.children.flat_map do |child|
    if block?(child)
      element_to_node(child)
    elsif inline?(child)
      element_to_inline(child)
    else
      next if child.text.strip == ''

      element_to_texts(child)
    end
  end.compact

  nodes << { marks: [], object: 'text', text: '' } if nodes.empty? && type != 'image'

  {
    data: element.attributes.each_with_object({}) { |a, h| h[a[1].name] = a[1].value },
    object: 'block',
    nodes: nodes,
    type: type
  }
end
element_to_text(element, mark = nil) click to toggle source
# File lib/slate_serializer/html.rb, line 135
def element_to_text(element, mark = nil)
  marks = [mark, convert_name_to_mark(element.name)].compact
  {
    marks: marks,
    object: 'text',
    text: element.text
  }
end
element_to_texts(element) click to toggle source
# File lib/slate_serializer/html.rb, line 120
def element_to_texts(element)
  nodes = []
  mark = convert_name_to_mark(element.name)

  if element.class == Nokogiri::XML::Element
    element.children.each do |child|
      nodes << element_to_text(child, mark)
    end
  else
    nodes << element_to_text(element)
  end

  nodes
end
empty_state() click to toggle source
# File lib/slate_serializer/html.rb, line 169
def empty_state
  {
    document: {
      object: 'document',
      nodes: [
        {
          data: {},
          object: 'block',
          type: 'paragraph',
          nodes: [
            {
              marks: [],
              object: 'text',
              text: ''
            }
          ]
        }
      ]
    }
  }
end
inline?(element) click to toggle source
# File lib/slate_serializer/html.rb, line 165
def inline?(element)
  inline_elements.include?(element.name)
end
serialize_node(node) click to toggle source
# File lib/slate_serializer/html.rb, line 191
def serialize_node(node)
  if node[:object] == 'document'
    node[:nodes].map { |n| serialize_node(n) }.join
  elsif node[:object] == 'block'
    children = node[:nodes].map { |n| serialize_node(n) }.join

    element = ELEMENTS.find { |_, v| v == node[:type] }[0]
    data = node[:data].map { |k, v| "#{k}=\"#{v}\"" }

    if %i[ol1 ola].include?(element)
      data << ["type=\"#{element.to_s[-1]}\""]
      element = :ol
    end

    "<#{element}#{!data.empty? ? " #{data.join(' ')}" : ''}>#{children}</#{element}>"
  else
    node[:text]
  end
end