Support for all possible nth-child arguments.
That is, as far as I can tell based on Nokogiri's behaviour (which Oga now matches).
This commit is contained in:
parent
0e6aefb727
commit
03f897c2b7
|
@ -271,10 +271,31 @@ rule
|
||||||
# on_pseudo_class_nth_child() to determine what the final AST should be.
|
# on_pseudo_class_nth_child() to determine what the final AST should be.
|
||||||
|
|
||||||
nth
|
nth
|
||||||
: T_NTH { s(:nth, s(:int, 1)) }
|
# n
|
||||||
| T_MINUS T_NTH { s(:nth, s(:int, 1)) }
|
: T_NTH { s(:nth, s(:int, 1)) }
|
||||||
| integer T_NTH { s(:nth, val[0]) }
|
|
||||||
| integer T_NTH integer { s(:nth, val[0], val[2]) }
|
# -n
|
||||||
|
| T_MINUS T_NTH { s(:nth, s(:int, 1)) }
|
||||||
|
|
||||||
|
# -n+2, -n-2
|
||||||
|
| T_MINUS T_NTH integer { s(:nth, nil, val[2]) }
|
||||||
|
|
||||||
|
# 2n
|
||||||
|
| integer T_NTH { s(:nth, val[0]) }
|
||||||
|
|
||||||
|
# 2n+1, 2n-1
|
||||||
|
| integer T_NTH integer
|
||||||
|
{
|
||||||
|
a = val[0]
|
||||||
|
b = val[2]
|
||||||
|
|
||||||
|
# 2n-1 gets turned into 2n+1
|
||||||
|
if b.children[0] < 0
|
||||||
|
b = s(:int, a.children[0] - (b.children[0] % a.children[0]))
|
||||||
|
end
|
||||||
|
|
||||||
|
s(:nth, a, b)
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
odd
|
odd
|
||||||
|
@ -358,6 +379,7 @@ end
|
||||||
# @return [AST::Node]
|
# @return [AST::Node]
|
||||||
#
|
#
|
||||||
def on_pseudo_class_nth_child(arg)
|
def on_pseudo_class_nth_child(arg)
|
||||||
|
# literal 2, 4, etc
|
||||||
if arg.type == :int
|
if arg.type == :int
|
||||||
node = s(
|
node = s(
|
||||||
:eq,
|
:eq,
|
||||||
|
@ -371,18 +393,35 @@ end
|
||||||
else
|
else
|
||||||
step, offset = *arg
|
step, offset = *arg
|
||||||
|
|
||||||
before_count = s(
|
count_call = s(
|
||||||
:add,
|
:call,
|
||||||
s(:call, 'count', s(:axis, 'preceding-sibling', s(:test, nil, '*'))),
|
'count',
|
||||||
s(:int, 1)
|
s(:axis, 'preceding-sibling', s(:test, nil, '*'))
|
||||||
)
|
)
|
||||||
|
|
||||||
if offset
|
before_count = s(:add, count_call, s(:int, 1))
|
||||||
|
|
||||||
|
if step and step.children[0] >= 0
|
||||||
|
compare = :gte
|
||||||
|
else
|
||||||
|
compare = :lte
|
||||||
|
end
|
||||||
|
|
||||||
|
# -n-6, -n-4, etc
|
||||||
|
if !step and offset.children[0] <= 0
|
||||||
|
node = s(:eq, count_call, s(:int, -1))
|
||||||
|
|
||||||
|
# 2n+2, 2n-4, etc
|
||||||
|
elsif offset
|
||||||
|
mod_val = step ? s(:int, 2) : s(:int, 1)
|
||||||
|
|
||||||
node = s(
|
node = s(
|
||||||
:and,
|
:and,
|
||||||
s(:gte, before_count, offset),
|
s(compare, before_count, offset),
|
||||||
s(:eq, s(:mod, s(:sub, before_count, offset), s(:int, 2)), s(:int, 0))
|
s(:eq, s(:mod, s(:sub, before_count, offset), mod_val), s(:int, 0))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 2n, n, -2n
|
||||||
else
|
else
|
||||||
node = s(:eq, s(:mod, before_count, step), s(:int, 0))
|
node = s(:eq, s(:mod, before_count, step), s(:int, 0))
|
||||||
end
|
end
|
||||||
|
|
|
@ -57,56 +57,48 @@ describe Oga::CSS::Parser do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the x:nth-child(2n) pseudo class' do
|
example 'parse the x:nth-child(-n+6) pseudo class' do
|
||||||
parse_css('x:nth-child(2n)').should == s(
|
parse_css('x:nth-child(-n+6)').should == parse_xpath(
|
||||||
:pseudo,
|
'descendant-or-self::x[((count(preceding-sibling::*) + 1) <= 6) ' \
|
||||||
s(:test, nil, 'x'),
|
'and (((count(preceding-sibling::*) + 1) - 6) mod 1) = 0]'
|
||||||
'nth-child',
|
|
||||||
s(:nth, s(:int, 2))
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
example 'parse the x:nth-child(-n-6) pseudo class' do
|
||||||
|
parse_css('x:nth-child(-n-6)').should == parse_xpath(
|
||||||
|
'descendant-or-self::x[count(preceding-sibling::*) = -1]'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
example 'parse the x:nth-child(2n) pseudo class' do
|
||||||
|
parse_css('x:nth-child(2n)').should == parse_css('x:nth-child(even)')
|
||||||
|
end
|
||||||
|
|
||||||
example 'parse the x:nth-child(2n+1) pseudo class' do
|
example 'parse the x:nth-child(2n+1) pseudo class' do
|
||||||
parse_css('x:nth-child(2n+1)').should == s(
|
parse_css('x:nth-child(2n+1)').should == parse_xpath(
|
||||||
:pseudo,
|
'descendant-or-self::x[(count(preceding-sibling::*) + 1) >= 1 ' \
|
||||||
s(:test, nil, 'x'),
|
'and (((count(preceding-sibling::*) + 1) - 1) mod 2) = 0]'
|
||||||
'nth-child',
|
|
||||||
s(:nth, s(:int, 2), s(:int, 1))
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the x:nth-child(2n-1) pseudo class' do
|
example 'parse the x:nth-child(2n-6) pseudo class' do
|
||||||
parse_css('x:nth-child(2n-1)').should == s(
|
parse_css('x:nth-child(2n-6)').should == parse_xpath(
|
||||||
:pseudo,
|
'descendant-or-self::x[(count(preceding-sibling::*) + 1) >= 2 ' \
|
||||||
s(:test, nil, 'x'),
|
'and (((count(preceding-sibling::*) + 1) - 2) mod 2) = 0]'
|
||||||
'nth-child',
|
|
||||||
s(:nth, s(:int, 2), s(:int, -1))
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the x:nth-child(-2n-1) pseudo class' do
|
example 'parse the x:nth-child(-2n-6) pseudo class' do
|
||||||
parse_css('x:nth-child(-2n-1)').should == s(
|
parse_css('x:nth-child(-2n-6)').should == parse_xpath(
|
||||||
:pseudo,
|
'descendant-or-self::x[((count(preceding-sibling::*) + 1) <= -2) ' \
|
||||||
s(:test, nil, 'x'),
|
'and (((count(preceding-sibling::*) + 1) - -2) mod 2) = 0]'
|
||||||
'nth-child',
|
|
||||||
s(:nth, s(:int, -2), s(:int, -1))
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse two pseudo selectors' do
|
example 'parse the x:nth-child(-2n+6) pseudo class' do
|
||||||
parse_css('x:focus:hover').should == s(
|
parse_css('x:nth-child(-2n+6)').should == parse_xpath(
|
||||||
:pseudo,
|
'descendant-or-self::x[((count(preceding-sibling::*) + 1) <= 6) ' \
|
||||||
s(:pseudo, s(:test, nil, 'x'), 'focus'),
|
'and (((count(preceding-sibling::*) + 1) - 6) mod 2) = 0]'
|
||||||
'hover'
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
example 'parse a pseudo class with an identifier as the argument' do
|
|
||||||
parse_css('x:lang(fr)').should == s(
|
|
||||||
:pseudo,
|
|
||||||
s(:test, nil, 'x'),
|
|
||||||
'lang',
|
|
||||||
s(:test, nil, 'fr')
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue