$VERSION
=
'0.09'
;
use
CSS::DOM::Rule;
our
@ISA
=
'CSS::DOM::Rule'
;
no
constant 1.03 ();
styl
=> 2,
selc
=> 3,
};
sub
type { CSS::DOM::Rule::STYLE_RULE }
sub
cssText {
my
$self
=
shift
;
my
$old
;
if
(
defined
wantarray
) {
my
$sel
=
$self
->selectorText;
length
$sel
and
$sel
.=
' '
;
$old
=
"$sel\{ "
.
$self
->[styl]->cssText .
" }\n"
;
}
if
(
@_
) {
my
$new_rule
=
$self
->_parse(
shift
);
@$self
[styl,selc] =
@$new_rule
[styl,selc];
}
$old
;
};
sub
selectorText {
my
$old
= (
my
$self
=
shift
)->[selc];
$old
=
join
''
, @{
$$old
[1]}
if
ref
$old
eq
'ARRAY'
and
defined
wantarray
;
$self
->[selc] =
""
.
shift
if
@_
;
$old
;
}
sub
_set_selector_tokens {
shift
->[selc] = \
@_
;
}
sub
_selector_matches {
my
$self
=
shift
;
my
$elem
=
shift
;
my
$pseudo
=
shift
;
unless
(
ref
$self
->[selc]) {
$self
->[selc] = [ CSS
'DOM'
tokenise(
$self
->[selc]) ];
}
my
$tree
;
unless
(
$tree
=
$self
->[selc][2]) {
my
(
$types
,
@tokens
) = (
$self
->[selc][0], @{
$self
->[selc][1] });
$self
->[selc][2] =
$tree
= [];
comma:
while
(
$types
) {
my
@pieces
;
while
(
$types
) {
push
@pieces
, \
my
@subsel
;
if
(
$types
=~ s/^i//) {
@subsel
=
lc
shift
@tokens
;
}
elsif
(
$tokens
[0] eq
'*'
) {
shift
@tokens
;
$types
=~ s/^.//;
@subsel
=
'*'
;
}
else
{
@subsel
=
undef
}
while
(
$types
) {
if
(
$types
=~ s/^
push
@subsel
,
'#'
, CSS
'DOM'
Util'unescape(
substr
shift
@tokens
, 1 ),
undef
;
}
elsif
(
$types
=~ /^di/ &&
$tokens
[0] eq
'.'
) {
$types
=~ s/^..//;
shift
@tokens
;
push
@subsel
,
'~'
,
'class'
,
CSS
'DOM'
Util'unescape(
shift
@tokens
);
}
elsif
(
$types
=~ s/^(::?)i//) {
push
@subsel
, $1,
lc
CSS
'DOM'
Util'unescape(
$tokens
[
length
$1]),
undef
;
splice
@tokens
, 0, $+[0];
}
elsif
(
$types
=~ s/^:fi\)//) {
push
@subsel
,
':'
,
lc
CSS
'DOM'
Util'unescape(
substr
$tokens
[1], 0, -1),
lc
CSS
'DOM'
Util'unescape(
$tokens
[2]);
splice
@tokens
, 0, 4;
}
elsif
(
$types
=~ s/^\[i]//) {
push
@subsel
,
'='
,
lc
CSS
'DOM'
Util'unescape(
$tokens
[1]),
undef
;
splice
@tokens
, 0, 3;
}
elsif
(
$types
=~ /^\[id
']/ && $tokens[2] eq '
=') {
$types
=~ s/^.{5}//;
push
@subsel
,
'='
,
lc
CSS
'DOM'
Util'unescape(
$tokens
[1]),
CSS
'DOM'
Util'unescape_str(
$tokens
[3]);
splice
@tokens
, 0, 5;
}
elsif
(
$types
=~ s/^\[i[~|]']//) {
push
@subsel
,
$tokens
[2],
lc
CSS
'DOM'
Util'unescape(
$tokens
[1]),
CSS
'DOM'
Util'unescape_str(
$tokens
[3]);
splice
@tokens
, 0, 5;
}
else
{
last
}
}
if
(
@subsel
== 1 and !
defined
$subsel
[0]) {
no
warnings
'regexp'
;
$types
=~ s/^
$CSS::DOM::Parser::any_re
*,?//o;
splice
@tokens
, 0, $+[0];
next
comma;
}
if
(
$types
=~ /^(s?)d/ and
$tokens
[$+[1]] =~ /([>+])/) {
push
@pieces
, $1;
$types
=~ s/^s?d//;
splice
@tokens
, $+[0];
}
else
{
push
@pieces
,
''
}
$types
=~ s/^s// and
shift
@tokens
;
if
(
$types
=~ s/^(?:,s?|\z)//) {
splice
@tokens
, 0, $+[0];
push
@$tree
, \
@pieces
;
pop
@pieces
;
next
comma;
}
}
}
}
my
$specificity
=
''
;
comma:
for
(
@$tree
) {
my
$spec
= _elem_matches_sel(
$elem
,
$pseudo
,
$_
) or
next
comma;
no
warnings
'uninitialized'
;
$spec
=
join
''
,
map
chr
,
@$spec
;
$spec
gt
$specificity
and
$specificity
=
$spec
;
}
return
$specificity
|| ();
}
sub
_elem_matches_sel {
my
(
$elem
,
$pseudo
,
$subsels
) =
@_
;
my
$spec
= _elem_matches_subsel(
$elem
,
$pseudo
,
$$subsels
[-1] )or
return
;
subsel:
for
(
my
$i
=
$#$subsels
-1;
$i
>=0;
$i
-=2) {
my
$combinator
=
$$subsels
[
$i
];
my
$next_sel
=
$$subsels
[
$i
-1];
if
(!
$combinator
) {
my
$e
=
$elem
;
while
(
$e
=
$e
->parentNode) {
last
if
!
$e
->can(
'tagName'
);
my
$s
= _elem_matches_sel(
$e
,
undef
, [
@$subsels
[0..
$i
-1] ] );
if
(
$s
) {
for
(0..2) {
no
warnings
'uninitialized'
;
$$spec
[
$_
] +=
$$s
[
$_
];
}
last
subsel;
}
}
return
}
else
{
my
$meth
= (
'previousSibling'
,
'parentNode'
)[
$combinator
eq
'>'
];
$elem
=
$elem
->
$meth
;
last
unless
$elem
->can(
'tagName'
);
my
$s
= _elem_matches_subsel(
$elem
,
undef
,
$next_sel
) or
return
;
for
(0..2) {
$$spec
[
$_
] +=
$$s
[
$_
];
}
}
}
return
$spec
;
}
sub
_elem_matches_subsel {
my
(
$elem
,
$pseudo
,
$subsel
) =
@_
;
my
@subsel
=
@$subsel
;
my
(
$ids
,
$attrs
,
$tags
);
my
$tag
=
shift
@subsel
;
if
(
defined
$tag
and
$tag
ne
'*'
) {
$tag
eq
lc
$elem
->tagName or
return
;
++
$tags
}
while
(
@subsel
) {
my
(
$type
,
$id
,
$arg
) =
splice
@subsel
, 0, 3;
if
(
$type
eq
'#'
) {
$id
eq
$elem
->id or
return
;
++
$ids
;
}
elsif
(
$type
eq
'~'
) {
my
$attr
=
$elem
->getAttribute(
$id
);
!
defined
$attr
|| !
length
$attr
and
return
;
$attr
=~ /(?:^|[ \t\r\n\f])\Q
$arg
\E(?:\z|[ \t\r\n\f])/ or
return
;
++
$attrs
;
}
elsif
(
$type
eq
':'
and
$id
!~ /^(?:first-l(?:ine|etter)|
before
|
after
)\z/) {
return
}
elsif
(
$type
=~ /:/) {
return
unless
$pseudo
and
lc
$id
eq
lc
$pseudo
;
}
elsif
(
$type
eq
'='
) {
my
$attr
=
$elem
->getAttribute(
$id
);
if
(
defined
$arg
) {
no
warnings;
$attr
eq
$arg
or
return
;
}
else
{
defined
$attr
||
length
$attr
or
return
}
++
$attrs
;
}
elsif
(
$type
eq
'|'
) {
my
$attr
=
$elem
->getAttribute(
$id
);
!
defined
$attr
|| !
length
$attr
and
return
;
$attr
=~ /^\Q
$arg
\E(?:-|\z)/ or
return
;
++
$attrs
;
}
}
return
[
$ids
,
$attrs
,
$tags
];
}
sub
style {
$_
[0]->[styl] ||=
do
{
new CSS::DOM::Style
shift
};
}
!()__END__()!
=head1 NAME
CSS::DOM::Rule::Style - CSS style rule class
for
CSS::DOM
=head1 VERSION
Version 0.09
=head1 SYNOPSIS
my
$ruleset
= CSS::DOM->parse(
'p:firstline, h3 { font-weight: bold }'
)->cssRules->[0];
$ruleset
->selectorText;
$ruleset
->style;
$ruleset
->style->fontWeight;
=head1 DESCRIPTION
This module implements CSS style rules
for
L<CSS::DOM>. It inherits
from
L<CSS::DOM::Rule> and implements
the CSSStyleRule DOM interface.
=head1 METHODS
=over 4
=item selectorText
Returns a string representing the selector(s). Pass an argument to set it.
=item style
Returns the CSS::DOM::Style object representing the declaration block
of this rule.
=back
=head1 SEE ALSO
L<CSS::DOM>
L<CSS::DOM::Style>
L<CSS::DOM::Rule>