diff --git a/lib/haml/engine.rb b/lib/haml/engine.rb
index dd4c7a2..d491d77 100644
--- a/lib/haml/engine.rb
+++ b/lib/haml/engine.rb
@@ -37,7 +37,7 @@ module Haml
@options = {
:suppress_eval => false,
:attr_wrapper => "'",
- :autoclose => ['meta', 'img', 'link', 'br', 'hr', 'input', 'area'],
+ :autoclose => %w(meta img link br hr input area param col base),
:filters => {
'sass' => Haml::Filters::Sass,
'plain' => Haml::Filters::Plain,
@@ -47,7 +47,8 @@ module Haml
'textile' => Haml::Filters::Textile,
'markdown' => Haml::Filters::Markdown },
:filename => '(haml)',
- :ugly => false
+ :ugly => false,
+ :html4 => false
}
@options.rec_merge! options
diff --git a/lib/haml/precompiler.rb b/lib/haml/precompiler.rb
index e79438e..922e434 100644
--- a/lib/haml/precompiler.rb
+++ b/lib/haml/precompiler.rb
@@ -473,8 +473,9 @@ END
result.compact.sort.join
end
- def prerender_tag(name, atomic, attributes)
- "<#{name}#{Precompiler.build_attributes(@options[:attr_wrapper], attributes)}#{atomic ? ' />' : '>'}"
+ def prerender_tag(name, self_close, attributes)
+ attributes_string = Precompiler.build_attributes(@options[:attr_wrapper], attributes)
+ "<#{name}#{attributes_string}#{self_close && !@options[:html4] ? ' /' : ''}>"
end
# Parses a line into tag_name, attributes, attributes_hash, object_ref, action, value
@@ -502,7 +503,7 @@ END
raise SyntaxError.new("Illegal element: classes and ids must have values.") if attributes =~ /[\.#](\.|#|\z)/
case action
- when '/'; atomic = true
+ when '/'; atomic = !@options[:html4]
when '~'; parse = flattened = true
when '='
parse = true
@@ -521,12 +522,12 @@ END
attributes = parse_class_and_id(attributes)
Buffer.merge_attrs(attributes, static_attributes) if static_attributes
- raise SyntaxError.new("Illegal Nesting: Nesting within an atomic tag is illegal.") if @block_opened && atomic
- raise SyntaxError.new("Illegal Nesting: Content can't be both given on the same line as %#{tag_name} and nested within it.") if @block_opened && !value.empty?
- raise SyntaxError.new("Tag has no content.") if parse && value.empty?
- raise SyntaxError.new("Atomic tags can't have content.") if atomic && !value.empty?
+ raise SyntaxError, "Illegal Nesting: Nesting within an atomic tag is illegal." if @block_opened && atomic
+ raise SyntaxError, "Illegal Nesting: Content can't be both given on the same line as %#{tag_name} and nested within it." if @block_opened && !value.empty?
+ raise SyntaxError, "Tag has no content." if parse && value.empty?
+ raise SyntaxError, "Atomic tags can't have content." if atomic && !value.empty?
- atomic = true if !@block_opened && value.empty? && @options[:autoclose].include?(tag_name)
+ atomic ||= !!( !@block_opened && value.empty? && @options[:autoclose].include?(tag_name) )
if object_ref == "nil" && attributes_hash.nil? && !flattened && (parse || Buffer.one_liner?(value))
# This means that we can render the tag directly to text and not process it in the buffer
@@ -600,22 +601,32 @@ END
def text_for_doctype(text)
text = text[3..-1].lstrip.downcase
if text[0...3] == "xml"
+ return nil if @options[:html4]
wrapper = @options[:attr_wrapper]
return ""
end
version, type = text.scan(DOCTYPE_REGEX)[0]
- if version == "1.1"
- return ''
- end
+
+ unless @options[:html4]
+ if version == "1.1"
+ return ''
+ end
- case type
- when "strict"; return ''
- when "frameset"; return ''
- else return ''
+ case type
+ when "strict"; return ''
+ when "frameset"; return ''
+ else return ''
+ end
+ else
+ case type
+ when "strict"; return ''
+ when "frameset"; return ''
+ else return ''
+ end
end
end
-
+
# Starts a filtered block.
def start_filtered(name)
raise SyntaxError.new('Filters must have nested text.') unless @block_opened
diff --git a/test/haml/engine_test.rb b/test/haml/engine_test.rb
index 7bc9842..5e5644c 100644
--- a/test/haml/engine_test.rb
+++ b/test/haml/engine_test.rb
@@ -394,4 +394,28 @@ class EngineTest < Test::Unit::TestCase
assert_equal("#{'s' * 75}
\n",
render("%p= 's' * 75", :ugly => true))
end
+
+ # HTML 4.0
+
+ def test_html_has_no_self_closing_tags
+ assert_equal "\n
\n
\n", render("%p\n %br", :html4 => :true)
+ assert_equal "
\n", render("%br/", :html4 => :true)
+ end
+
+ def test_html_renders_empty_node_with_closing_tag
+ assert_equal %{\n\n}, render(".foo", :html4 => :true)
+ end
+
+ def test_html_ignores_explicit_self_closing_declaration
+ assert_equal "\n\n", render("%a/", :html4 => :true)
+ end
+
+ def test_html_ignores_xml_prolog_declaration
+ assert_equal "\n", render('!!! XML', :html4 => :true)
+ end
+
+ def test_html_has_different_doctype
+ assert_equal %{\n},
+ render('!!!', :html4 => :true)
+ end
end
Pastie
