[Haml] Add the ability to use CSS class/id shorthand with haml_tag.

This commit is contained in:
hasclass 2009-12-10 13:17:35 +01:00 committed by Nathan Weizenbaum
parent 94704f9918
commit 60e498d044
4 changed files with 84 additions and 5 deletions

View File

@ -5,6 +5,22 @@
## 2.4.0 (Unreleased)
### haml_tag improvement
The {Haml::Helpers#haml_tag haml\_tag} helper can now take a string
using the same class/id shorthand as in standard Haml code.
Manually-specified class and id attributes are merged,
again as in standard Haml code.
For example:
haml_tag('#foo') #=> <div id='foo' />
haml_tag('.bar) #=> <div class='bar' />
haml_tag('span#foo.bar') #=> <span class='bar' id='foo' />
haml_tag('span#foo.bar', :class => 'abc') #=> <span class='abc bar' id='foo' />
haml_tag('span#foo.bar', :id => 'abc') #=> <span class='bar' id='abc_foo' />
Cheers, [S. Burkhard](http://github.com/hasclass/).
### Object Reference Customization
It's now possible to customize the name used for {file:HAML_REFERENCE.md#object_reference_ object reference}

View File

@ -367,6 +367,11 @@ END
# If the block is a Haml block or outputs text using \{#haml\_concat},
# the text will be properly indented.
#
# `name` can be a string using the standard Haml class/id shorthand
# (e.g. "span#foo.bar", "#foo").
# Just like standard Haml tags, these class and id values
# will be merged with manually-specified attributes.
#
# `flags` is a list of symbol flags
# like those that can be put at the end of a Haml tag
# (`:/`, `:<`, and `:>`).
@ -381,7 +386,7 @@ END
#
# haml_tag :table do
# haml_tag :tr do
# haml_tag :td, {:class => 'cell'} do
# haml_tag 'td.cell' do
# haml_tag :strong, "strong!"
# haml_concat "data"
# end
@ -417,13 +422,14 @@ END
def haml_tag(name, *rest, &block)
ret = ErrorReturn.new("haml_tag")
name = name.to_s
text = rest.shift.to_s unless [Symbol, Hash, NilClass].any? {|t| rest.first.is_a? t}
flags = []
flags << rest.shift while rest.first.is_a? Symbol
name, attrs = merge_name_and_attributes(name.to_s, rest.shift || {})
attributes = Haml::Precompiler.build_attributes(haml_buffer.html?,
haml_buffer.options[:attr_wrapper],
rest.shift || {})
attrs)
if text.nil? && block.nil? && (haml_buffer.options[:autoclose].include?(name) || flags.include?(:/))
haml_concat "<#{name}#{attributes} />"
@ -512,6 +518,17 @@ END
private
# Parses the tag name used for \{#haml\_tag}
# and merges it with the Ruby attributes hash.
def merge_name_and_attributes(name, attributes_hash = {})
# skip merging if no ids or classes found in name
return name, attributes_hash unless name =~ /^(.+?)?([\.#].*)$/
return $1 || "div", Buffer.merge_attrs(
Precompiler.parse_class_and_id($2),
Haml::Util.map_keys(attributes_hash) {|key| key.to_s})
end
# Runs a block of code with the given buffer as the currently active buffer.
#
# @param buffer [Haml::Buffer] The Haml buffer to use temporarily

View File

@ -480,10 +480,12 @@ END
@template_tabs -= 1
end
# This is a class method so it can be accessed from {Haml::Helpers}.
#
# Iterates through the classes and ids supplied through `.`
# and `#` syntax, and returns a hash with them as attributes,
# that can then be merged with another attributes hash.
def parse_class_and_id(list)
def self.parse_class_and_id(list)
attributes = {}
list.scan(/([#.])([-_a-zA-Z0-9]+)/) do |type, property|
case type
@ -733,7 +735,7 @@ END
object_ref = "nil" if object_ref.nil? || @options[:suppress_eval]
attributes = parse_class_and_id(attributes)
attributes = Precompiler.parse_class_and_id(attributes)
attributes_hashes.map! do |syntax, attributes_hash|
if syntax == :old
static_attributes = parse_static_hash(attributes_hash)

View File

@ -125,6 +125,50 @@ HTML
HAML
end
def test_haml_tag_name_attribute_with_id
assert_equal("<p id='some_id'></p>\n", render("- haml_tag 'p#some_id'"))
end
def test_haml_tag_without_name_but_with_id
assert_equal("<div id='some_id'></div>\n", render("- haml_tag '#some_id'"))
end
def test_haml_tag_without_name_but_with_class
assert_equal("<div class='foo'></div>\n", render("- haml_tag '.foo'"))
end
def test_haml_tag_name_with_id_and_class
assert_equal("<p class='foo' id='some_id'></p>\n", render("- haml_tag 'p#some_id.foo'"))
end
def test_haml_tag_name_with_class
assert_equal("<p class='foo'></p>\n", render("- haml_tag 'p.foo'"))
end
def test_haml_tag_name_with_class_and_id
assert_equal("<p class='foo' id='some_id'></p>\n", render("- haml_tag 'p.foo#some_id'"))
end
def test_haml_tag_name_with_id_and_multiple_classes
assert_equal("<p class='foo bar' id='some_id'></p>\n", render("- haml_tag 'p#some_id.foo.bar'"))
end
def test_haml_tag_name_with_multiple_classes_and_id
assert_equal("<p class='foo bar' id='some_id'></p>\n", render("- haml_tag 'p.foo.bar#some_id'"))
end
def test_haml_tag_name_and_attribute_classes_merging
assert_equal("<p class='foo bar' id='some_id'></p>\n", render("- haml_tag 'p#some_id.foo', :class => 'bar'"))
end
def test_haml_tag_name_and_attribute_classes_merging
assert_equal("<p class='bar foo'></p>\n", render("- haml_tag 'p.foo', :class => 'bar'"))
end
def test_haml_tag_name_merges_id_and_attribute_id
assert_equal("<p id='foo_bar'></p>\n", render("- haml_tag 'p#foo', :id => 'bar'"))
end
def test_haml_tag_attribute_html_escaping
assert_equal("<p id='foo&amp;bar'>baz</p>\n", render("%p{:id => 'foo&bar'} baz", :escape_html => true))
end