mirror of
https://github.com/haml/haml.git
synced 2022-11-09 12:33:31 -05:00
parent
20e54364f7
commit
7d3056b89a
6 changed files with 188 additions and 18 deletions
|
@ -10,18 +10,18 @@ module Hamlit
|
|||
class Attribute
|
||||
include Concerns::AttributeBuilder
|
||||
|
||||
def self.build(quote, attributes)
|
||||
def self.build(quote, attributes, base = {})
|
||||
builder = self.new(quote)
|
||||
builder.build(attributes)
|
||||
builder.build(attributes, base)
|
||||
end
|
||||
|
||||
def initialize(quote)
|
||||
@quote = quote
|
||||
end
|
||||
|
||||
def build(attributes)
|
||||
def build(attributes, base)
|
||||
result = ''
|
||||
flatten_attributes(attributes).each do |key, value|
|
||||
merge_attributes(base, attributes).each do |key, value|
|
||||
if value == true
|
||||
result += " #{key}"
|
||||
next
|
||||
|
@ -32,5 +32,27 @@ module Hamlit
|
|||
end
|
||||
result
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def merge_attributes(base, target)
|
||||
result = {}
|
||||
base = flatten_attributes(base)
|
||||
target = flatten_attributes(target)
|
||||
|
||||
(base.keys | target.keys).each do |key|
|
||||
if base[key] && target[key]
|
||||
case key
|
||||
when :id
|
||||
result[key] = [base[key], target[key]].compact.join('_')
|
||||
else
|
||||
result[key] = [base[key], target[key]].compact.join(' ')
|
||||
end
|
||||
else
|
||||
result[key] = base[key].nil? ? target[key] : base[key]
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
require 'hamlit/compilers/new_attribute'
|
||||
require 'hamlit/compilers/old_attribute'
|
||||
require 'hamlit/compilers/runtime_attribute'
|
||||
require 'hamlit/concerns/escapable'
|
||||
require 'hamlit/concerns/included'
|
||||
|
||||
|
@ -9,6 +10,7 @@ module Hamlit
|
|||
extend Concerns::Included
|
||||
include Compilers::NewAttribute
|
||||
include Compilers::OldAttribute
|
||||
include Compilers::RuntimeAttribute
|
||||
|
||||
included do
|
||||
include Concerns::Escapable
|
||||
|
@ -21,6 +23,13 @@ module Hamlit
|
|||
attrs = join_ids(attrs)
|
||||
attrs = combine_classes(attrs)
|
||||
attrs = pull_class_first(attrs)
|
||||
|
||||
if has_runtime_attribute?(attrs) && has_attr?(attrs, 'class', 'id')
|
||||
attrs = merge_runtime_attributes(attrs)
|
||||
return [:html, :attrs, *escape_attribute_values(attrs)]
|
||||
end
|
||||
attrs = attrs.map { |a| compile(a) }
|
||||
|
||||
[:html, :attrs, *escape_attribute_values(attrs)]
|
||||
end
|
||||
|
||||
|
@ -72,9 +81,13 @@ module Hamlit
|
|||
[[:html, :attr, 'id', [:multi, *insert_static(values, '_')]]] + (attrs - id_attrs)
|
||||
end
|
||||
|
||||
def filter_attrs(attrs, target)
|
||||
class_attrs = attrs.select do |html, attr, name, content|
|
||||
name == target
|
||||
def has_attr?(attrs, *targets)
|
||||
filter_attrs(attrs, *targets).any?
|
||||
end
|
||||
|
||||
def filter_attrs(attrs, *targets)
|
||||
attrs.select do |html, attr, name, content|
|
||||
targets.include?(name)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
require 'hamlit/attribute'
|
||||
require 'hamlit/concerns/attribute_builder'
|
||||
require 'hamlit/concerns/balanceable'
|
||||
require 'hamlit/concerns/ripperable'
|
||||
|
@ -31,7 +30,8 @@ module Hamlit
|
|||
[:html, :attr, key, [:dynamic, value]]
|
||||
end
|
||||
rescue RuntimeBuild
|
||||
return runtime_build(str)
|
||||
# Give up static compilation when given string is invalid as ruby hash
|
||||
[[:runtime, str]]
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -48,7 +48,7 @@ module Hamlit
|
|||
end
|
||||
end
|
||||
|
||||
# Give up static copmile when variables are detected.
|
||||
# Give up static compilation when variables are detected.
|
||||
def assert_static_value!(value)
|
||||
tokens = Ripper.lex(value)
|
||||
tokens.each do |(row, col), type, str|
|
||||
|
@ -114,13 +114,6 @@ module Hamlit
|
|||
raise SyntaxError unless type == :on_op && str == '=>'
|
||||
end
|
||||
|
||||
def runtime_build(str)
|
||||
str = str.gsub(/(\A\{|\}\Z)/, '')
|
||||
quote = options[:attr_quote].inspect
|
||||
code = "::Hamlit::Attribute.build(#{quote}, #{str})"
|
||||
[[:dynamic, code]]
|
||||
end
|
||||
|
||||
def split_hash(str)
|
||||
columns = HashParser.assoc_columns(str)
|
||||
columns = reject_nested_columns(str, columns)
|
||||
|
|
58
lib/hamlit/compilers/runtime_attribute.rb
Normal file
58
lib/hamlit/compilers/runtime_attribute.rb
Normal file
|
@ -0,0 +1,58 @@
|
|||
require 'hamlit/attribute'
|
||||
require 'hamlit/concerns/string_interpolation'
|
||||
|
||||
# This module compiles :runtime sexp. It is a special version of
|
||||
# old-style attribute which is built on runtime.
|
||||
module Hamlit
|
||||
module Compilers
|
||||
module RuntimeAttribute
|
||||
include Concerns::StringInterpolation
|
||||
|
||||
# This is used for compiling only runtime attribute in Compilers::Attribute.
|
||||
def on_runtime(str)
|
||||
compile_runtime_attribute(str)
|
||||
end
|
||||
|
||||
# Given html attrs, merge classes and ids to :dynamic_attribute.
|
||||
def merge_runtime_attributes(attrs)
|
||||
merge_targets = filter_attrs(attrs, 'id', 'class')
|
||||
dynamic_attr = attrs.find { |exp, *args| exp == :runtime }
|
||||
|
||||
attrs -= merge_targets
|
||||
attrs.delete(dynamic_attr)
|
||||
|
||||
base = decompile_temple_attrs(merge_targets)
|
||||
[compile_runtime_attribute(dynamic_attr.last, base), *attrs]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def compile_runtime_attribute(str, base = nil)
|
||||
str = str.gsub(/(\A\{|\}\Z)/, '')
|
||||
quote = options[:attr_quote].inspect
|
||||
code = "::Hamlit::Attribute.build(#{[quote, str, base].compact.join(', ')})"
|
||||
[:dynamic, code]
|
||||
end
|
||||
|
||||
def has_runtime_attribute?(attrs)
|
||||
attrs.any? do |exp, *args|
|
||||
exp == :runtime
|
||||
end
|
||||
end
|
||||
|
||||
# Given attrs in temple ast, return an attribute as hash literal.
|
||||
def decompile_temple_attrs(attrs)
|
||||
literal = '{'
|
||||
attrs.each do |html, attr, name, (type, value)|
|
||||
case type
|
||||
when :static
|
||||
literal += ":#{name}=>#{string_literal(value)},"
|
||||
when :dynamic
|
||||
literal += ":#{name}=>#{value},"
|
||||
end
|
||||
end
|
||||
literal.gsub(/,\Z/, '') + '}'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -41,5 +41,43 @@ describe Hamlit::Engine do
|
|||
HTML
|
||||
end
|
||||
end
|
||||
|
||||
describe 'element class with attribute class' do
|
||||
it 'does not generate double classes' do
|
||||
assert_render(<<-HAML, <<-HTML)
|
||||
.item(class='first')
|
||||
HAML
|
||||
<div class='first item'></div>
|
||||
HTML
|
||||
end
|
||||
|
||||
it 'does not generate double classes for a variable' do
|
||||
assert_render(<<-HAML, <<-HTML)
|
||||
- val = 'val'
|
||||
.element(class=val)
|
||||
HAML
|
||||
<div class='element val'></div>
|
||||
HTML
|
||||
end
|
||||
end
|
||||
|
||||
describe 'element id with attribute id' do
|
||||
it 'concatenates ids with underscore' do
|
||||
assert_render(<<-HAML, <<-HTML)
|
||||
#item(id='first')
|
||||
HAML
|
||||
<div id='item_first'></div>
|
||||
HTML
|
||||
end
|
||||
|
||||
it 'concatenates ids with underscore for a variable' do
|
||||
assert_render(<<-HAML, <<-HTML)
|
||||
- val = 'first'
|
||||
#item(id=val)
|
||||
HAML
|
||||
<div id='item_first'></div>
|
||||
HTML
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -160,7 +160,7 @@ describe Hamlit::Engine do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'element class with attributes class' do
|
||||
describe 'element class with attribute class' do
|
||||
it 'does not generate double classes' do
|
||||
assert_render(<<-HAML, <<-HTML)
|
||||
.item{ class: 'first' }
|
||||
|
@ -177,6 +177,52 @@ describe Hamlit::Engine do
|
|||
<div class='element val'></div>
|
||||
HTML
|
||||
end
|
||||
|
||||
it 'does not generate double classes for hash attributes' do
|
||||
assert_render(<<-HAML, <<-HTML)
|
||||
- hash = { class: 'val' }
|
||||
.element{ hash }
|
||||
HAML
|
||||
<div class='element val'></div>
|
||||
HTML
|
||||
end
|
||||
end
|
||||
|
||||
describe 'element id with attribute id' do
|
||||
it 'does not generate double ids' do
|
||||
assert_render(<<-HAML, <<-HTML)
|
||||
#item{ id: 'first' }
|
||||
HAML
|
||||
<div id='item_first'></div>
|
||||
HTML
|
||||
end
|
||||
|
||||
it 'does not generate double ids for a variable' do
|
||||
assert_render(<<-HAML, <<-HTML)
|
||||
- val = 'first'
|
||||
#item{ id: val }
|
||||
HAML
|
||||
<div id='item_first'></div>
|
||||
HTML
|
||||
end
|
||||
|
||||
it 'does not generate double ids for hash attributes' do
|
||||
assert_render(<<-HAML, <<-HTML)
|
||||
- hash = { id: 'first' }
|
||||
#item{ hash }
|
||||
HAML
|
||||
<div id='item_first'></div>
|
||||
HTML
|
||||
end
|
||||
|
||||
it 'does not generate double ids and classes for hash attributes' do
|
||||
assert_render(<<-HAML, <<-HTML)
|
||||
- hash = { id: 'first', class: 'foo' }
|
||||
#item.bar{ hash }
|
||||
HAML
|
||||
<div class='bar foo' id='item_first'></div>
|
||||
HTML
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue