Created
February 24, 2019 00:02
-
-
Save clarkenciel/68b77d7884cd6e4f240e9c65a6f2b455 to your computer and use it in GitHub Desktop.
building up to block elements from quill delta ops
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Line | |
include Enumerable | |
delegate :each, to: :@elements | |
attr_reader :elements, :attributes | |
def initialize elements: [], attributes: {} | |
@elements = elements | |
@attributes = Attributes.new(**(attributes || {})) | |
end | |
def closed? | |
@elements.last.closed? | |
end | |
def join other | |
Line.new elements: @elements + other.elements, | |
attributes: @attributes.merge(other.attributes) | |
end | |
class Attributes < Hash | |
VALID_ATTRS = %i( | |
list | |
indent | |
header | |
) | |
def initialize **args | |
args.select { |k, v| VALID_ATTRS.include? k }.each do |k, v| | |
self[k] = v | |
end | |
end | |
end | |
end | |
class Text | |
attr_reader :content, :attributes | |
def initialize content: '', attributes: {} | |
@content = content | |
@attributes = Attributes.new(**(attributes || {})) | |
end | |
def closed? | |
@content.ends_with? "\n" | |
end | |
class Attributes < Hash | |
INVALID_ATTRS = %i( | |
list | |
indent | |
header | |
) | |
def initialize **args | |
args.reject { |k, v| INVALID_ATTRS.include? k }.each do |k, v| | |
self[k] = v | |
end | |
end | |
end | |
end | |
class Lines | |
include Enumerable | |
delegate :each, to: :lines | |
attr_reader :lines | |
def initialize lines: [] | |
@lines = lines | |
end | |
def self.from_ops ops | |
ops.inject(new) { |lines, op| lines.apply op } | |
end | |
def apply op | |
lines = op[:insert].split(/(?<=\n)/).map do |t| | |
Line.new elements: [Text.new(content: t, attributes: op[:attributes])], | |
attributes: op[:attributes] | |
end | |
return Lines.new lines: lines if @lines.empty? | |
return Lines.new lines: @lines + lines if @lines.last.closed? | |
Lines.new lines: [ | |
*@lines[0...-1], | |
@lines.last.join(lines.first), | |
*lines[1..-1], | |
] | |
end | |
def blocks | |
Blocks.from_lines @lines | |
end | |
end | |
class Block | |
def self.containing lines | |
new lines: lines, attributes: lines.first.attributes | |
end | |
attr_reader :attributes | |
def initialize lines: [], attributes: {} | |
@lines = lines | |
@attributes = attributes | |
end | |
end | |
class Blocks | |
include Enumerable | |
def self.from_lines lines | |
last_line = nil | |
new(blocks: lines.slice_before do |line| | |
is_block_break = last_line&.attributes != line.attributes | |
last_line = line | |
is_block_break | |
end.map { |lines| block.containing lines }) | |
end | |
delegate :each, to: :blocks | |
attr_reader :blocks | |
def initialize blocks: [] | |
@blocks = blocks | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment