1 package HTML::Zoom::EventFilter;
4 use warnings FATAL => 'all';
8 my ($class, $code) = @_;
9 confess "from_code is a class method" if ref $class;
10 bless({ code => $code }, $class);
14 my $n = shift->{next} or return;
15 $n->${\$n->{code}}(@_);
23 $_[0]->{next} = $_[1];
27 sub get_next { $_[0]->{next} }
30 my ($self, $code) = @_;
31 $self->{next} = bless(
32 { code => $code, next => $self->{next} }
37 my ($self, $code) = @_;
39 while ($target->{next} && $target->{next}{next}) {
40 $target = $target->{next}
42 $target->push_next($code);
47 die "$self doesn't have a next (->pop($to))"
50 until ($target->{next} eq $to) {
51 $target = $target->{next} || die "Didn't find $to as next of $self";
53 $target->{next} = $to->{next};
57 sub until_close_do_next { shift->until_close_do(next => @_) }
58 sub until_close_do_last { shift->until_close_do(last => @_) }
61 my ($self, $direction, $do, $before_close, $after_close) = @_;
62 my %depth = (OPEN => 1, CLOSE => -1, TEXT => 0);
65 $self->${\"push_${direction}"}(
67 my ($self, $evt) = @_;
68 $count += $depth{$evt->{type}};
70 $do->(@_, $count) if $do;
73 $before_close->($self, $evt) if $before_close;
74 $outer->pop($self)->next($evt);
75 $after_close->($outer, $evt) if $after_close;
80 sub standard_emitter {
81 my ($class, $out) = @_;
82 confess "standard_emitter is a class method" if ref $class;
83 $class->from_code(sub {
84 my ($self, $evt) = @_;
85 return $out->print($evt->{raw}) if defined $evt->{raw};
86 if ($evt->{type} eq 'OPEN') {
90 .(defined $evt->{raw_attrs}
93 my @names = @{$evt->{attr_names}};
95 ? join(' ', '', map qq{${_}="${\$evt->{attrs}{$_}}"}, @names)
99 .($evt->{is_in_place_close} ? ' /' : '')
102 } elsif ($evt->{type} eq 'CLOSE') {
103 $out->print('</'.$evt->{name}.'>');
105 confess "No raw value in event and no special handling for type ".$evt->{type};
110 sub selector_handler {
111 my ($class, $pairs) = @_;
112 confess "selector_handler is a class method" if ref $class;
113 $class->from_code(sub {
114 my ($self, $evt) = @_;
115 my $next = $self->get_next;
116 if ($evt->{type} eq 'OPEN') {
117 foreach my $p (@$pairs) {
118 $p->[1]->($self, $evt) if $p->[0]->($evt);
125 sub build_selector_pair {
126 my ($class, $sel_spec, $action_spec) = @_;
127 my $selector = HTML::Zoom::SelectorParser->parse_selector($sel_spec);
129 if (ref($action_spec) eq 'HASH') {
130 confess "hash spec must be single key"
131 unless keys(%$action_spec) == 1;
132 my ($key) = keys (%$action_spec);
134 $action = HTML::Zoom::ActionBuilder->build($key, values %$action_spec);
136 [ $selector, $action ];