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