Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add logic to properly handle Phlex::SVG #139

Merged
merged 3 commits into from
Apr 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions gem/lib/phlexing/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ module Helpers
Phlex::HTML::VoidElements.registered_elements.values +
Phlex::HTML::StandardElements.registered_elements.values

SVG_ELEMENTS = Phlex::SVG::StandardElements.registered_elements.values.to_h { |element| [element.downcase, element] }

def whitespace
options.whitespace? ? "whitespace\n" : ""
end
Expand Down Expand Up @@ -59,17 +61,27 @@ def unwrap_erb(source)
end

def tag_name(node)
return "template_tag" if node.name == "template-tag"

name = node.name.tr("-", "_")

@converter.custom_elements << name unless KNOWN_ELEMENTS.include?(name)
return name if name == "template_tag"
return name if name.start_with?("s.")
return name if KNOWN_ELEMENTS.include?(name)

@converter.custom_elements << name

name
end

def block
def block(params = nil)
out << " {"

if params
out << " "
out << "|"
out << params
out << "|"
end

yield
out << " }"
end
Expand Down
5 changes: 3 additions & 2 deletions gem/lib/phlexing/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

module Phlexing
class Options
attr_accessor :component, :component_name, :parent_component, :whitespace
attr_accessor :component, :component_name, :parent_component, :whitespace, :svg_param

alias_method :whitespace?, :whitespace
alias_method :component?, :component

def initialize(component: false, component_name: "Component", parent_component: "Phlex::HTML", whitespace: true)
def initialize(component: false, component_name: "Component", parent_component: "Phlex::HTML", whitespace: true, svg_param: "s")
@component = component
@component_name = safe_constant_name(component_name)
@parent_component = safe_constant_name(parent_component)
@whitespace = whitespace
@svg_param = svg_param
end

def safe_constant_name(name)
Expand Down
26 changes: 24 additions & 2 deletions gem/lib/phlexing/template_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,10 @@ def handle_html_element_node(node, level)
out << tag_name(node)
out << handle_attributes(node)

params = node.name == "svg" ? options.svg_param : nil

if node.children.any?
block { handle_children(node, level) }
block(params) { handle_children(node, level) }
end

out << newline
Expand Down Expand Up @@ -189,6 +191,22 @@ def handle_element_node(node, level)
out << newline if level == 1
end

def handle_svg_node(node, level)
node.children.each do |child|
child.traverse do |subchild|
subchild.name = SVG_ELEMENTS[subchild.name] if SVG_ELEMENTS.key?(subchild.name)
subchild.name = subchild.name.prepend("#{options.svg_param}.") # rubocop:disable Style/RedundantSelfAssignment
end
end

whitespace_before = options.whitespace
options.whitespace = false

handle_element_node(node, level)

options.whitespace = whitespace_before
end

def handle_document_node(node, level)
handle_children(node, level)
end
Expand All @@ -204,7 +222,11 @@ def handle_node(node, level = 0)
in Nokogiri::XML::Text
handle_text_node(node)
in Nokogiri::XML::Element
handle_element_node(node, level)
if node.name == "svg"
handle_svg_node(node, level)
else
handle_element_node(node, level)
end
in Nokogiri::HTML4::Document | Nokogiri::HTML4::DocumentFragment | Nokogiri::XML::DTD
handle_document_node(node, level)
in Nokogiri::XML::Comment
Expand Down
115 changes: 115 additions & 0 deletions gem/test/phlexing/converter/svg_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# frozen_string_literal: true

require_relative "../../test_helper"

class Phlexing::Converter::SvgTest < Minitest::Spec
it "converts SVG" do
html = %(
<svg>
<path d="123"></path>
</svg>
)

expected = <<~PHLEX.strip
svg { |s| s.path(d: "123") }
PHLEX

assert_phlex_template expected, html
end

it "converts SVG with attributes" do
html = %(
<svg one="attribute" two="attributes">
<path d="123"></path>
</svg>
)

expected = <<~PHLEX.strip
svg(one: "attribute", two: "attributes") { |s| s.path(d: "123") }
PHLEX

assert_phlex_template expected, html
end

it "converts SVG with ERB interpolation" do
html = %(
<svg one="<%= interpolate %>" two="<%= method_call(123) %>">
<path d="123"></path>
</svg>
)

expected = <<~PHLEX.strip
svg(one: interpolate, two: method_call(123)) { |s| s.path(d: "123") }
PHLEX

assert_phlex_template expected, html do
assert_locals "interpolate"
assert_instance_methods "method_call"
end
end

it "converts SVG with case-sensitive" do
html = %(
<svg>
<feSpecularLighting>
<fePointLight/>
</feSpecularLighting>
</svg>
)

expected = <<~PHLEX.strip
svg { |s| s.feSpecularLighting { s.fePointLight } }
PHLEX

assert_phlex_template expected, html
end

it "nested SVG" do
html = %(
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="5cm" height="5cm">
<desc>Two groups, each of two rectangles</desc>
<g id="group1" fill="red">
<rect x="1cm" y="1cm" width="1cm" height="1cm"/>
<rect x="3cm" y="1cm" width="1cm" height="1cm"/>
</g>

<g id="group2" fill="blue">
<rect x="1cm" y="3cm" width="1cm" height="1cm"/>
<rect x="3cm" y="3cm" width="1cm" height="1cm"/>
</g>

<rect x=".01cm" y=".01cm" width="4.98cm" height="4.98cm" fill="none" stroke="blue" stroke-width=".02cm"/>
</svg>
)

expected = <<~PHLEX.strip
svg(
xmlns: "http://www.w3.org/2000/svg",
version: "1.1",
width: "5cm",
height: "5cm"
) do |s|
s.desc { "Two groups, each of two rectangles" }
s.g(id: "group1", fill: "red") do
s.rect(x: "1cm", y: "1cm", width: "1cm", height: "1cm")
s.rect(x: "3cm", y: "1cm", width: "1cm", height: "1cm")
end
s.g(id: "group2", fill: "blue") do
s.rect(x: "1cm", y: "3cm", width: "1cm", height: "1cm")
s.rect(x: "3cm", y: "3cm", width: "1cm", height: "1cm")
end
s.rect(
x: ".01cm",
y: ".01cm",
width: "4.98cm",
height: "4.98cm",
fill: "none",
stroke: "blue",
stroke_width: ".02cm"
)
end
PHLEX

assert_phlex_template expected, html
end
end