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