The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
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->get_all_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