d64ab42d45d08b1d776f95a9896ddcfb659367cc
[catagits/Reaction.git] / lib / Reaction / UI / ViewPort / Collection.pm
1 package Reaction::UI::ViewPort::Collection;
2
3 use Reaction::Class;
4 use Scalar::Util qw/blessed/;
5 use aliased 'Reaction::InterfaceModel::Collection' => 'IM_Collection';
6 use aliased 'Reaction::UI::ViewPort::Object';
7
8 use MooseX::Types::Moose qw/Str HashRef/;
9
10 use namespace::clean -except => [ qw(meta) ];
11 extends 'Reaction::UI::ViewPort';
12
13 with 'Reaction::UI::ViewPort::Collection::Role::Pager';
14 with 'Reaction::UI::ViewPort::Role::Actions';
15
16 has members => (is => 'rw', isa => 'ArrayRef', lazy_build => 1);
17
18 has collection         => (is => 'ro', isa => IM_Collection, required   => 1);
19 has current_collection => (is => 'rw', isa => IM_Collection, lazy_build => 1);
20
21 has member_args => ( is => 'rw', isa => HashRef, lazy_build => 1);
22 has member_class => ( is => 'ro', isa => Str, lazy_build => 1);
23
24 sub BUILD {
25   my ($self, $args) = @_;
26   if( my $member_args = delete $args->{Member} ){
27     $self->member_args( $member_args );
28   }
29 }
30
31 sub _build_member_args { {} }
32
33 sub _build_member_class { Object };
34
35 after clear_current_collection => sub{
36   shift->clear_members; #clear the members the current collection changes, duh
37 };
38
39 sub _build_current_collection {
40   return $_[0]->collection;
41 }
42
43 #I'm not really sure why this is here all of a sudden.
44 sub model { shift->current_collection }
45
46 sub _build_members {
47   my ($self) = @_;
48   my (@members, $i);
49   my $args = $self->member_args;
50   my $builders = {};
51   my $field_orders = {};
52   my $ctx = $self->ctx;
53   my $loc = join('-', $self->location, 'member');
54   my $class = $self->member_class;
55
56   #replace $i with a real unique identifier so that we don't run a risk of
57   # events being passed down to the wrong viewport. for now i disabled event
58   # passing until i fix this (groditi)
59   for my $obj ( $self->current_collection->members ) {
60     my $type = blessed $obj;
61     my $builder_cache = $builders->{$type} ||= {};
62     my @order;
63     if( exists $args->{computed_field_order} ){
64       @order = (computed_field_order => $args->{computed_field_order});
65     } elsif( exists $field_orders->{$type} ) {
66       @order = (computed_field_order => $field_orders->{$type});
67     }
68
69     my $member = $class->new(
70       ctx => $ctx,
71       model => $obj,
72       location => join('-', $loc, $i++),
73       builder_cache => $builder_cache,
74       @order, %$args,
75     );
76
77     #cache to prevent the sort function from having to be run potentially
78     #hundreds of times
79     $field_orders->{$type} ||= $member->computed_field_order unless @order;
80     push(@members, $member);
81   }
82   return \@members;
83 };
84
85 __PACKAGE__->meta->make_immutable;
86
87
88 1;
89
90 __END__;
91
92 =head1 NAME
93
94 Reaction::UI::ViewPort::Collection
95
96 =head1 DESCRIPTION
97
98 Creates, from an InterfaceModel::Collection, a list of viewports representing
99 each member of the collection.
100
101 =head1 ATTRIBUTES
102
103 =head2 collection
104
105 Required read-only L<InterfaceModel::Collection|Reaction::InterfaceModel::Collection>
106 This is the original collection.
107
108 =head2 current_collection
109
110 Read-only, lazy-building
111 L<InterfaceModel::Collection|Reaction::InterfaceModel::Collection>
112 This is the collection that will be used to create C<members> and should be
113 altered to reflect any ordering, paging, etc. By default this is the
114 same thing as C<collection>.
115
116 =head2 member_args
117
118 A read-write HASH ref of additional parameters to pass to the C<member_class>
119 constructor as items are instantiated.
120
121 =head2 member_class
122
123 The class to use when instantiating items to represent the member items.
124
125 See: L<Object|Reaction::UI::ViewPort::Object>,
126 L<Member|Reaction::UI::ViewPort::Collection::Grid::Member>.
127
128 =head1 INTERNAL METHODS
129
130 These methods, although stable, are subject to change without notice.
131 Extend at your own risk, APIs may change in the future.
132
133 =head2 BUILD
134
135 Intercept a parameter with the key C<Member> amd store it in C<member_args>
136
137 =head2 model
138
139 Returns the C<current_collection>
140
141 =head2 _build_members
142
143 Build individual viewports for each member of the collection,
144
145 =head2 _build_member_args
146
147 Defaults to an empty HASH ref.
148
149 =head2 _build_member_class
150
151 Defaults to L<Reaction::UI::ViewPort::Object>
152
153 =head1 AUTHORS
154
155 See L<Reaction::Class> for authors.
156
157 =head1 LICENSE
158
159 See L<Reaction::Class> for the license.
160
161 =cut