remove class blocks from widget code
[catagits/Reaction.git] / lib / Reaction / UI / Widget / Container.pm
1 package Reaction::UI::Widget::Container;
2
3 use Reaction::UI::WidgetClass;
4
5 use aliased 'Reaction::UI::ViewPort';
6
7 use namespace::clean -except => [ qw(meta) ];
8
9
10 our $child_name;
11
12 # somewhat evil. fragment returns ($name, $code) to pass to implements
13 # or a method modifier name, so [1] will get us just the code
14
15 # This is convenient to do here but DO NOT duplicate this code outside of
16 # the same dist as WidgetClass since it's internals-dependent.
17
18 my $child_fragment_method
19   = (fragment container_child {
20        arg '_' => $_{viewport}->$child_name;
21        render 'viewport';
22      })[1];
23
24 around _method_for_fragment_name => sub {
25   my $orig = shift;
26   my $self = shift;
27   my ($fragment_name) = @_;
28   if (defined($child_name)
29       && $fragment_name eq $child_name) {
30     return $self->$orig(@_) || $child_fragment_method;
31   }
32   return $self->$orig(@_);
33 };
34   
35 before _fragment_widget => sub {
36   my ($self, $do_render, $args, $new_args) = @_;
37   my @contained_names = $self->_contained_names($args->{viewport});
38   foreach my $name (@contained_names) {
39     $new_args->{$name} ||= sub {
40       local $child_name = $name;
41       $self->render($name, @_);
42     };
43   }
44 };
45
46 implements _contained_names => sub {
47   my ($self, $vp) = @_;
48   my @names;
49   foreach my $attr ($vp->meta->compute_all_applicable_attributes) {
50     next unless eval { $attr->type_constraint->name->isa(ViewPort) };
51     my $name = $attr->name;
52     next if ($name eq 'outer');
53     push(@names, $name);
54   }
55   return @names;
56 };
57
58 __PACKAGE__->meta->make_immutable;
59
60
61 1;