aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Reaction/UI/Widget/Container.pm
blob: f470d510090c578527d32aa4292ab535539e69bf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package Reaction::UI::Widget::Container;

use Reaction::UI::WidgetClass;

use aliased 'Reaction::UI::ViewPort';

use namespace::clean -except => [ qw(meta) ];


our $child_name;

# somewhat evil. fragment returns ($name, $code) to pass to implements
# or a method modifier name, so [1] will get us just the code

# This is convenient to do here but DO NOT duplicate this code outside of
# the same dist as WidgetClass since it's internals-dependent.

my $child_fragment_method
  = (fragment container_child {
       arg '_' => $_{viewport}->$child_name;
       render 'viewport';
     })[1];

around _method_for_fragment_name => sub {
  my $orig = shift;
  my $self = shift;
  my ($fragment_name) = @_;
  if (defined($child_name)
      && $fragment_name eq $child_name) {
    return $self->$orig(@_) || $child_fragment_method;
  }
  return $self->$orig(@_);
};
  
before _fragment_widget => sub {
  my ($self, $do_render, $args, $new_args) = @_;
  my @contained_names = $self->_contained_names($args->{viewport});
  foreach my $name (@contained_names) {
    $new_args->{$name} ||= sub {
      local $child_name = $name;
      $self->render($name, @_);
    };
  }
};

implements _contained_names => sub {
  my ($self, $vp) = @_;
  my @names;
  foreach my $attr ($vp->meta->compute_all_applicable_attributes) {
    next unless eval { $attr->type_constraint->name->isa(ViewPort) };
    my $name = $attr->name;
    next if ($name eq 'outer');
    push(@names, $name);
  }
  return @names;
};

__PACKAGE__->meta->make_immutable;

1;

__END__

=head1 NAME

Reaction::UI::Widget::Container - Provide viewport attibutes in the current viewport

=head1 DESCRIPTION

This widget base class (with no corresponding layout set) will search the viewports
attributes for those that contain L<Reaction::UI::ViewPort> classes or subclasses.

These attributes will then be provided as arguments to the C<widget> fragment and
can be rendered by their attribute name.

=head1 FRAGMENTS

=head2 widget

Provides rendering callbacks to those attributes of the viewport that can contain
viewport objects as arguments to the C<widget> layout.

=head1 AUTHORS

See L<Reaction::Class> for authors.

=head1 LICENSE

See L<Reaction::Class> for the license.

=cut