# frozen_string_literal: true module DraftjsHtml module Draftjs Block = Struct.new(:key, :text, :type, :inline_style_ranges, :raw_entity_ranges, keyword_init: true) do def self.parse(raw) new( key: raw['key'], text: raw['text'], type: raw['type'], inline_style_ranges: Array(raw['inlineStyleRanges']), raw_entity_ranges: Array(raw['entityRanges']), ) end def length text.length end def blank? text.empty? && entity_ranges.empty? end def each_char return to_enum(:each_char) unless block_given? text.chars.map.with_index do |char, index| yield CharacterMeta.new( char: char, style_names: inline_styles.select { _1.range.cover?(index) }.map(&:name), entity_key: entity_ranges.select { _1.range.cover?(index) }.map(&:name).first, ) end end CharRange = Struct.new(:text, :style_names, :entity_key, keyword_init: true) def each_range return to_enum(:each_range) unless block_given? current_styles = [] current_entity = nil ranges = [CharRange.new(text: '', style_names: current_styles, entity_key: current_entity)] each_char.with_index do |char, index| if char.style_names != current_styles || char.entity_key != current_entity current_styles = char.style_names current_entity = char.entity_key yield(ranges.last) unless index == 0 ranges << CharRange.new(text: '', style_names: current_styles, entity_key: current_entity) end ranges.last.text += char.char end yield ranges.last end alias plaintext text def inline_styles @inline_styles ||= inline_style_ranges.map do |raw| ApplicableRange.parse(raw['style'], raw) end end def entity_ranges @entity_ranges ||= raw_entity_ranges.map do |raw| ApplicableRange.parse(raw['key'].to_s, raw) end end def add_style(name, range) inline_styles << ApplicableRange.new(name: name, range: range) end end end end