Updated date and version
[sdlgit/SDL-Site.git] / code / HTML / Zoom / ActionBuilder.pm
1 package HTML::Zoom::ActionBuilder;
2
3 use strict;
4 use warnings FATAL => 'all';
5
6 use HTML::Zoom::Parser::BuiltIn;
7 use HTML::Zoom::EventFilter;
8 use Storable ();
9 use Carp qw(confess);
10
11 sub build {
12   my ($tb, $name, @args) = @_;
13   confess "Don't know how to build ${name} in ${tb}"
14     unless $tb->can("build_${name}");
15
16   return $tb->${\"build_${name}"}(@args);
17 }
18
19 sub build_add_attribute {
20   my ($tb, $name, $value) = @_;
21   sub {
22     my ($self, $evt) = @_;
23     delete @{$evt}{qw(raw raw_attrs)};
24     if (defined $evt->{attrs}{$name}) {
25       $evt->{attrs}{$name} .= ' '.$value;
26     } else {
27       $evt->{attrs}{$name} = $value;
28     }
29   };
30 }
31
32 sub build_set_attribute {
33   my ($tb, $name, $value) = @_;
34   sub {
35     my ($self, $evt) = @_;
36     delete @{$evt}{qw(raw raw_attrs)};
37     $evt->{attrs}{$name} = $value;
38   };
39 }
40
41 sub build_add_class { shift->build_add_attribute('class' => @_) }
42 sub build_set_class { shift->build_set_attribute('class' => @_) }
43
44 sub build_replace_content {
45   my ($tb, $text) = @_;
46   my $raw = HTML::Zoom::Parser::BuiltIn::_simple_escape($text);
47   $tb->build_replace_content_raw($raw);
48 }
49
50 sub build_replace_content_raw {
51   my ($tb, $raw) = @_;
52   sub {
53     my ($self, $evt) = @_;
54     my $in_place_close = $evt->{is_in_place_close};
55     if ($in_place_close) {
56       delete $evt->{raw};
57       $evt->{is_in_place_close} = 0;
58     }
59     $self->until_close_do_last(
60       undef,
61       sub {
62         delete $_[1]->{raw} if $in_place_close;
63         $_[0]->next({ type => 'TEXT', raw => $raw })
64       }
65     )
66   };
67 }
68
69 sub build_repeat {
70   my ($tb, $args) = @_;
71   my $data = $args->{data};
72   my $do_repeat = sub {
73     my ($self, $to_repeat) = @_;
74     my $stole_last;
75     if ($to_repeat->[-1]->{type} eq 'TEXT') {
76       if ($to_repeat->[-1]->{raw} =~ s/(\s+)$//) {
77         $stole_last = $1;
78       }
79     }
80     foreach my $d (@$data) {
81       my @pairs = map {
82         HTML::Zoom::EventFilter->build_selector_pair($_, $d->{$_})
83       } sort keys %$d;
84       my $sel = HTML::Zoom::EventFilter->selector_handler(\@pairs);
85       $sel->set_next($self->get_next);
86       $sel->call($_) for @$to_repeat;
87     }
88     if (defined $stole_last) {
89       $self->next({ type => 'TEXT', raw => $stole_last });
90     }
91   };
92   sub {
93     my ($self, $evt) = @_;
94     return if $evt->{is_in_place_close}; # no content to repeat
95     my @repeat;
96     $self->until_close_do_last(
97        sub { push(@repeat, $_[1]) },
98        sub { $_[0]->$do_repeat(\@repeat) },
99     );
100   };
101 }
102
103 1;