Class: Y::Lexxy
Overview
The Lexxy renderer: Y::Lexical (core Lexical) plus the Lexxy-specific
schema, applied beneath the app's rules — an app rule for one of these
types simply replaces it. This is the byte-parity class: the fixture
tests hold Y::Lexxy.new(doc).to_html identical to a live editor's own
serialized value.
The schema doubles as the reference for augmenting a renderer: simple nodes are declarative hashes, nodes with logic are plain methods mapped in NODES.
Constant Summary collapse
- NODES =
{ # Lexxy's replacement for Lexical's CodeNode. "early_escape_code" => { tag: "pre", attrs: { "data-language" => :language } }, "horizontal_divider" => { tag: "hr", void: true }, "provisonal_paragraph" => method(:provisional_paragraph), # (sic: Lexxy's spelling) "image_gallery" => method(:gallery), "table" => { contains: :blocks, render: method(:table) }, "wrapped_table_node" => { contains: :blocks, render: method(:table) }, "tablecell" => { contains: :blocks, render: method(:table_cell) }, "listitem" => { contains: :blocks, render: method(:list_item) }, "action_text_attachment" => method(:upload), "custom_action_text_attachment" => method(:mention) }.freeze
Class Method Summary collapse
-
.attachment_attr(node, html_name, stored) ⇒ Object
A stored nil (unset) is skipped; a stored empty string still emits.
-
.gallery(node) ⇒ Object
Adjacent previewable images; the class carries the image count (ActionText's convention).
-
.list_item(node) ⇒ Object
Attribute order follows Lexxy's export — checked items put aria-checked before value; items holding a nested list append the lexxy-nested-listitem class after value.
-
.mention(node) ⇒ Object
A content attachment (mention, embed):
contentcarries the escaped inner HTML;plainTextis not exported. -
.provisional_paragraph(node) ⇒ Object
A cursor-placement placeholder; empty ones export to nothing.
-
.table(node) ⇒ Object
Lexxy wraps tables in a styled figure.
-
.table_cell(node) ⇒ Object
Class + background match Lexxy's own header-cell export.
-
.upload(node) ⇒ Object
An upload, in the exact shape ActionText round-trips: attribute order and presence mirror Lexxy's exportDOM (nulls omitted,
previewableonly when true,presentation="gallery"always).
Instance Method Summary collapse
-
#initialize(doc, nodes: {}) ⇒ Lexxy
constructor
A new instance of Lexxy.
Methods inherited from Lexical
Constructor Details
Class Method Details
.attachment_attr(node, html_name, stored) ⇒ Object
A stored nil (unset) is skipped; a stored empty string still emits.
76 77 78 79 80 |
# File 'lib/y/lexxy.rb', line 76 def self.(node, html_name, stored) return "" if node.attrs[stored].nil? %( #{html_name}="#{RenderRules.escape_attr(node.attrs[stored])}") end |
.gallery(node) ⇒ Object
Adjacent previewable images; the class carries the image count (ActionText's convention).
21 22 23 |
# File 'lib/y/lexxy.rb', line 21 def self.gallery(node) %(<div class="attachment-gallery attachment-gallery--#{node.child_types.length}">#{node.content}</div>) end |
.list_item(node) ⇒ Object
Attribute order follows Lexxy's export — checked items put aria-checked before value; items holding a nested list append the lexxy-nested-listitem class after value.
42 43 44 45 46 47 48 49 |
# File 'lib/y/lexxy.rb', line 42 def self.list_item(node) out = +"<li" checked = node.attrs["__checked"] out << %( aria-checked="#{checked}") unless checked.nil? out << %( value="#{node.attrs["__value"] || 1}") out << %( class="lexxy-nested-listitem") if node.child_types.include?("list") "#{out}>#{node.content}</li>" end |
.mention(node) ⇒ Object
A content attachment (mention, embed): content carries the escaped
inner HTML; plainText is not exported.
67 68 69 70 71 72 73 |
# File 'lib/y/lexxy.rb', line 67 def self.mention(node) out = +"<action-text-attachment" out << (node, "sgid", "sgid") out << (node, "content", "innerHtml") out << (node, "content-type", "contentType") "#{out}></action-text-attachment>" end |
.provisional_paragraph(node) ⇒ Object
A cursor-placement placeholder; empty ones export to nothing.
15 16 17 |
# File 'lib/y/lexxy.rb', line 15 def self.provisional_paragraph(node) node.content.empty? ? "" : "<p>#{node.content}</p>" end |
.table(node) ⇒ Object
Lexxy wraps tables in a styled figure.
26 27 28 |
# File 'lib/y/lexxy.rb', line 26 def self.table(node) %(<figure class="lexxy-content__table-wrapper"><table><tbody>#{node.content}</tbody></table></figure>) end |
.table_cell(node) ⇒ Object
Class + background match Lexxy's own header-cell export.
31 32 33 34 35 36 37 |
# File 'lib/y/lexxy.rb', line 31 def self.table_cell(node) header = node.attrs["__headerState"].is_a?(Numeric) && node.attrs["__headerState"].positive? return "<td>#{node.content}</td>" unless header style = %(style="background-color: rgb(242, 243, 245);") %(<th class="lexxy-content__table-cell--header" #{style}>#{node.content}</th>) end |
.upload(node) ⇒ Object
An upload, in the exact shape ActionText round-trips: attribute order
and presence mirror Lexxy's exportDOM (nulls omitted, previewable
only when true, presentation="gallery" always).
54 55 56 57 58 59 60 61 62 63 |
# File 'lib/y/lexxy.rb', line 54 def self.upload(node) out = +"<action-text-attachment" out << (node, "sgid", "sgid") out << %( previewable="true") if node.attrs["previewable"] == true [%w[url src], %w[alt altText], %w[caption caption], %w[content-type contentType], %w[filename fileName], %w[filesize fileSize], %w[width width], %w[height height]] .each { |html_name, stored| out << (node, html_name, stored) } %(#{out} presentation="gallery"></action-text-attachment>) end |