X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FHTML%2FZoom%2FSelectorParser.pm;h=1432c4ddf7c97f0e6278eaa8d0faba5629ed84a9;hb=4c6b44299edb3613877d7e99586026423e9f15b5;hp=ef61d93e349449a692fefebaa395c870cd7817f6;hpb=24725e7b32b680b376c06b1f9d641ec11fc1d067;p=catagits%2FHTML-Zoom.git diff --git a/lib/HTML/Zoom/SelectorParser.pm b/lib/HTML/Zoom/SelectorParser.pm index ef61d93..1432c4d 100644 --- a/lib/HTML/Zoom/SelectorParser.pm +++ b/lib/HTML/Zoom/SelectorParser.pm @@ -1,13 +1,14 @@ package HTML::Zoom::SelectorParser; -use strict; -use warnings FATAL => 'all'; +use strictures 1; use base qw(HTML::Zoom::SubObject); use Carp qw(confess); my $sel_char = '-\w_'; -my $sel_re = qr/([$sel_char]+)/; -my $match_value_re = qr/"?$sel_re"?/; +my $sel_meta_char = q-!"#$%&'()*+,./:;<=>?@[\]^`{|}~-; +my $sel_item = qr/(?:(?:\\[\Q$sel_meta_char\E])|[$sel_char])/; +my $sel_re = qr/($sel_item+)/; +my $match_value_re = qr/"?($sel_item*)"?/; sub new { bless({}, shift) } @@ -24,7 +25,7 @@ sub _raw_parse_simple_selector { /\G$sel_re/gc and return do { - my $name = $1; + my $name = $_[0]->_unescape($1); sub { $_[0]->{name} && $_[0]->{name} eq $name } }; @@ -32,7 +33,7 @@ sub _raw_parse_simple_selector { /\G#$sel_re/gc and return do { - my $id = $1; + my $id = $_[0]->_unescape($1); sub { $_[0]->{attrs}{id} && $_[0]->{attrs}{id} eq $id } }; @@ -41,20 +42,20 @@ sub _raw_parse_simple_selector { /\G((?:\.$sel_re)+)/gc and return do { my $cls = $1; $cls =~ s/^\.//; - my @cl = split(/\./, $cls); + my @cl = map $_[0]->_unescape($_), split(/(?{attrs}{class} - && !grep $_[0]->{attrs}{class} !~ /(^|\s+)$_($|\s+)/, @cl + && !grep $_[0]->{attrs}{class} !~ /(^|\s+)\Q$_\E($|\s+)/, @cl } }; # '[attr^=foo]' - match attribute with ^ anchored regex /\G\[$sel_re\^=$match_value_re\]/gc and return do { - my $attribute = $1; - my $value = $2; + my $attribute = $_[0]->_unescape($1); + my $value = $_[0]->_unescape($2); sub { - $_[0]->{attrs}{$attribute} + exists $_[0]->{attrs}{$attribute} && $_[0]->{attrs}{$attribute} =~ qr/^\Q$value\E/; } }; @@ -62,10 +63,10 @@ sub _raw_parse_simple_selector { # '[attr$=foo]' - match attribute with $ anchored regex /\G\[$sel_re\$=$match_value_re\]/gc and return do { - my $attribute = $1; - my $value = $2; + my $attribute = $_[0]->_unescape($1); + my $value = $_[0]->_unescape($2); sub { - $_[0]->{attrs}{$attribute} + exists $_[0]->{attrs}{$attribute} && $_[0]->{attrs}{$attribute} =~ qr/\Q$value\E$/; } }; @@ -73,10 +74,10 @@ sub _raw_parse_simple_selector { # '[attr*=foo] - match attribute with regex: /\G\[$sel_re\*=$match_value_re\]/gc and return do { - my $attribute = $1; - my $value = $2; + my $attribute = $_[0]->_unescape($1); + my $value = $_[0]->_unescape($2); sub { - $_[0]->{attrs}{$attribute} + exists $_[0]->{attrs}{$attribute} && $_[0]->{attrs}{$attribute} =~ qr/\Q$value\E/; } }; @@ -84,21 +85,32 @@ sub _raw_parse_simple_selector { # '[attr~=bar]' - match attribute contains word /\G\[$sel_re~=$match_value_re\]/gc and return do { - my $attribute = $1; - my $value = $2; + my $attribute = $_[0]->_unescape($1); + my $value = $_[0]->_unescape($2); sub { - $_[0]->{attrs}{$attribute} - && grep { $_ eq $value } split(' ', $_[0]->{attrs}{$attribute}); + exists $_[0]->{attrs}{$attribute} + && $_[0]->{attrs}{$attribute} =~ qr/\b\Q$value\E\b/; + } + }; + + # '[attr!=bar]' - match attribute contains prefix (for language matches) + /\G\[$sel_re\|=$match_value_re\]/gc and + return do { + my $attribute = $_[0]->_unescape($1); + my $value = $_[0]->_unescape($2); + sub { + exists $_[0]->{attrs}{$attribute} + && $_[0]->{attrs}{$attribute} =~ qr/^\Q$value\E(?:-|$)/; } }; # '[attr=bar]' - match attributes /\G\[$sel_re=$match_value_re\]/gc and return do { - my $attribute = $1; - my $value = $2; + my $attribute = $_[0]->_unescape($1); + my $value = $_[0]->_unescape($2); sub { - $_[0]->{attrs}{$attribute} + exists $_[0]->{attrs}{$attribute} && $_[0]->{attrs}{$attribute} eq $value; } }; @@ -106,10 +118,10 @@ sub _raw_parse_simple_selector { # '[attr!=bar]' - attributes doesn't match /\G\[$sel_re!=$match_value_re\]/gc and return do { - my $attribute = $1; - my $value = $2; + my $attribute = $_[0]->_unescape($1); + my $value = $_[0]->_unescape($2); sub { - ! ($_[0]->{attrs}{$attribute} + ! (exists $_[0]->{attrs}{$attribute} && $_[0]->{attrs}{$attribute} eq $value); } }; @@ -117,12 +129,12 @@ sub _raw_parse_simple_selector { # '[attr]' - match attribute being present: /\G\[$sel_re\]/gc and return do { - my $attribute = $1; + my $attribute = $_[0]->_unescape($1); sub { exists $_[0]->{attrs}{$attribute}; } }; - + # none of the above matched, try catching some obvious errors: # indicate unmatched square bracket: @@ -181,6 +193,11 @@ sub parse_selector { } } +sub _unescape { + my ($self, $escaped) = @_; + (my $unescaped = $escaped) =~ s/\\([\Q$sel_meta_char\E])/$1/g; + return $unescaped; +} sub _blam { my ($self, $error) = @_;