Skip to content

Commit

Permalink
HTML-15 Properly implement HTML5 void-elements
Browse files Browse the repository at this point in the history
  • Loading branch information
sbsoftware committed Aug 26, 2023
1 parent cb066f2 commit ef7e270
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 22 deletions.
4 changes: 2 additions & 2 deletions spec/instance_tag_attrs/tag_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ module ToHtml::InstanceTagAttrs::TagSpec
expected = <<-HTML
<div>
<a href="https://www.example.com">
<img src="https://www.example.com/img.jpg" alt="An image of this"></img>
<img src="https://www.example.com/img.jpg" alt="An image of this">
</a>
</div>
<div>
<a href="https://example.com">
<img src="https://example.com/img.jpg" alt="Another image of this"></img>
<img src="https://example.com/img.jpg" alt="Another image of this">
</a>
</div>
HTML
Expand Down
66 changes: 66 additions & 0 deletions spec/instance_template/void_element_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
require "../spec_helper"

module ToHtml::InstanceTemplate::VoidElementSpec
class MyView
ToHtml.class_template do
div do
span { "First line" }
br
span { "Second line" }
hr
embed MyVideo.new("/media/video.mp4")
hr
form action: "/inputs", method: "POST" do
input MyInputField.new("foo"), placeholder: "bar"
input type: "submit", name: "submit", value: "Submit"
end
end
end
end

class MyVideo
getter path : String

def initialize(@path); end

ToHtml.instance_tag_attrs do
type = "video/webm"
src = path
width = "250"
height = "200"
end
end

class MyInputField
getter field_value : String

def initialize(@field_value); end

ToHtml.instance_tag_attrs do
type = "text"
name = "name"
value = field_value
end
end

describe "MyView.to_html" do
it "should render void elements correctly" do
expected = <<-HTML.squish
<div>
<span>First line</span>
<br>
<span>Second line</span>
<hr>
<embed type="video/webm" src="/media/video.mp4" width="250" height="200">
<hr>
<form action="/inputs" method="POST">
<input type="text" name="name" value="foo" placeholder="bar">
<input type="submit" name="submit" value="Submit">
</form>
</div>
HTML

MyView.to_html.should eq(expected)
end
end
end
51 changes: 44 additions & 7 deletions src/instance_template.cr
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ module ToHtml
end

macro to_html_eval_exp(io, indent_level, break_line = true, &blk)
{% if blk.body.is_a?(Call) && ToHtml::TAG_NAMES.includes?(blk.body.name.stringify) %}
{% if blk.body.is_a?(Call) && ToHtml::VOID_TAG_NAMES.includes?(blk.body.name.stringify) %}
ToHtml.to_html_add_void_tag({{io}}, {{indent_level}}, {{break_line}}, {{blk.body}})
{% elsif blk.body.is_a?(Call) && ToHtml::TAG_NAMES.includes?(blk.body.name.stringify) %}
ToHtml.to_html_add_tag({{io}}, {{indent_level}}, {{break_line}}, {{blk.body}})
{% elsif blk.body.is_a?(Call) && blk.body.name.stringify == "doctype" %}
{{io}} << "<!DOCTYPE {{blk.body.args.first.id}}>"
Expand Down Expand Up @@ -127,12 +129,6 @@ module ToHtml
{% else %}
%attr_hash = ToHtml::AttributeHash.new

{% if call.named_args %}
{% for named_arg in call.named_args %}
%attr_hash[{{named_arg.name.stringify}}] = {{named_arg.value}}.to_s
{% end %}
{% end %}

{% for arg in call.args %}
{% if arg.is_a?(TupleLiteral) %}
%attr_hash[{{arg}}.first] = {{arg}}.last
Expand All @@ -141,6 +137,12 @@ module ToHtml
{% end %}
{% end %}

{% if call.named_args %}
{% for named_arg in call.named_args %}
%attr_hash[{{named_arg.name.stringify}}] = {{named_arg.value}}.to_s
{% end %}
{% end %}

{{io}} << "<{{call.name}}"
{{io}} << " " unless %attr_hash.empty?
{{io}} << %attr_hash
Expand Down Expand Up @@ -168,4 +170,39 @@ module ToHtml
{% end %}
{% end %}
end

macro to_html_add_void_tag(io, indent_level, break_line, call)
{% if flag?(:to_html_pretty) %}
{{io}} << " " * {{indent_level}}
{% end %}
{% if call.args.empty? && !call.named_args %}
{{io}} << "<{{call.name}}>"
{% elsif call.args.empty? && call.named_args %}
{{io}} << "<{{call.name}} " + {{ call.named_args.map { |a| "#{a.name}=#{a.value}" }.join(" ") }} + ">"
{% else %}
%attr_hash = ToHtml::AttributeHash.new

{% for arg in call.args %}
{% if arg.is_a?(TupleLiteral) %}
%attr_hash[{{arg}}.first] = {{arg}}.last
{% else %}
{{arg}}.to_html_attrs({{call.name.stringify}}, %attr_hash)
{% end %}
{% end %}

{% if call.named_args %}
{% for named_arg in call.named_args %}
%attr_hash[{{named_arg.name.stringify}}] = {{named_arg.value}}.to_s
{% end %}
{% end %}

{{io}} << "<{{call.name}}"
{{io}} << " " unless %attr_hash.empty?
{{io}} << %attr_hash
{{io}} << ">"
{% end %}
{% if flag?(:to_html_pretty) && break_line %}
{{io}} << "\n"
{% end %}
end
end
29 changes: 16 additions & 13 deletions src/tag_names.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,19 @@ module ToHtml
a
abbr
address
area
article
aside
audio
b
base
bdi
bdo
blockquote
body
br
button
canvas
caption
cite
code
col
colgroup
data
datalist
Expand All @@ -32,7 +28,6 @@ module ToHtml
dl
dt
em
embed
fieldset
figcaption
figure
Expand All @@ -46,23 +41,18 @@ module ToHtml
h6
head
header
hr
html
i
iframe
img
input
ins
kbd
label
legend
li
link
main
map
mark
menu
meta
meter
nav
noscript
Expand All @@ -72,7 +62,6 @@ module ToHtml
option
output
p
param
picture
pre
progress
Expand All @@ -86,7 +75,6 @@ module ToHtml
section
select
small
source
span
strong
style
Expand All @@ -105,11 +93,26 @@ module ToHtml
time
title
tr
track
u
ul
var
video
]

VOID_TAG_NAMES = %w[
area
base
br
col
embed
hr
img
input
link
meta
param
source
track
wbr
]
end

0 comments on commit ef7e270

Please sign in to comment.