made hidden array field use the value event instead of value_string
[catagits/Reaction.git] / lib / Reaction / UI / Controller.pm
CommitLineData
7adfd53f 1package Reaction::UI::Controller;
2
7f43bb45 3use base qw(Catalyst::Controller); # Reaction::Object);
1810d302 4
7adfd53f 5use Reaction::Class;
747a1feb 6use Scalar::Util 'weaken';
db80cb74 7use namespace::clean -except => [ qw(meta) ];
7adfd53f 8
d0736579 9has context => (is => 'ro', isa => 'Object', weak_ref => 1);
10with 'Catalyst::Component::InstancePerContext';
11
12sub build_per_context_instance {
13 my ($self, $c, @args) = @_;
987fc6e2 14 my $class = ref($self) || $self;
15 my $newself = $class->new($self->_application, {%$self, context => $c, @args});
d0736579 16 return $newself;
17}
18
7adfd53f 19sub push_viewport {
20 my $self = shift;
1810d302 21 my $c = $self->context;
22 my $focus_stack = $c->stash->{focus_stack};
7adfd53f 23 my ($class, @proto_args) = @_;
24 my %args;
7adfd53f 25 if (my $vp_attr = $c->stack->[-1]->attributes->{ViewPort}) {
26 if (ref($vp_attr) eq 'ARRAY') {
27 $vp_attr = $vp_attr->[0];
28 }
29 if (ref($vp_attr) eq 'HASH') {
59e40811 30 $class = $vp_attr->{class} if defined $vp_attr->{class};
504e2c44 31 %args = %{ $self->merge_config_hashes($vp_attr, {@proto_args}) };
7adfd53f 32 } else {
33 $class = $vp_attr;
34 %args = @proto_args;
35 }
36 } else {
37 %args = @proto_args;
38 }
39
40 $args{ctx} = $c;
41
42 if (exists $args{next_action} && !ref($args{next_action})) {
43 $args{next_action} = [ $self, 'redirect_to', $args{next_action} ];
44 }
45 $focus_stack->push_viewport($class, %args);
46}
47
48sub pop_viewport {
1810d302 49 return shift->context->stash->{focus_stack}->pop_viewport;
7adfd53f 50}
51
52sub pop_viewports_to {
53 my ($self, $vp) = @_;
1810d302 54 return $self->context->stash->{focus_stack}->pop_viewports_to($vp);
7adfd53f 55}
56
57sub redirect_to {
58 my ($self, $c, $to, $cap, $args, $attrs) = @_;
59
60 #the confess calls could be changed later to $c->log ?
61 my $action;
9cf5bc0b 62 my $reftype = ref($to);
63 if( $reftype eq '' ){
64 $action = $self->action_for($to);
65 confess("Failed to locate action ${to} in " . blessed($self)) unless $action;
66 } elsif($reftype eq 'ARRAY' && @$to == 2){ #is that overkill / too strict?
67 $action = $c->controller($to->[0])->action_for($to->[1]);
68 confess("Failed to locate action $to->[1] in $to->[0]" ) unless $action;
69 } elsif( blessed $to && $to->isa('Catalyst::Action') ){
70 $action = $to;
7adfd53f 71 } else{
9cf5bc0b 72 confess("Failed to locate action from ${to}");
7adfd53f 73 }
74
75 $cap ||= $c->req->captures;
76 $args ||= $c->req->args;
77 $attrs ||= {};
78 my $uri = $c->uri_for($action, $cap, @$args, $attrs);
79 $c->res->redirect($uri);
80}
81
747a1feb 82sub make_context_closure {
83 my($self, $closure) = @_;
84 my $ctx = $self->context;
db80cb74 85 weaken($ctx);
747a1feb 86 return sub { $closure->($ctx, @_) };
87}
88
7adfd53f 891;
f2756356 90
91__END__;
92
93=head1 NAME
94
63bb30b4 95Reaction::UI::Controller - Reaction Base Controller Class
96
97=head1 SYNOPSIS
98
99 package MyApp::Controller::Foo;
100 use strict;
101 use warnings;
102 use parent 'Reaction::UI::Controller';
103
104 use aliased 'Reaction::UI::ViewPort';
105
106 sub foo: Chained('/base') Args(0) {
107 my ($self, $ctx) = @_;
108
109 $ctx->push_viewport(ViewPort,
110 layout => 'foo',
111 );
112 }
113
114 1;
f2756356 115
116=head1 DESCRIPTION
117
118Base Reaction Controller class. Inherits from:
119
120=over 4
121
122=item L<Catalyst::Controller>
123=item L<Catalyst::Component::ACCEPT_CONTEXT>
124=item L<Reaction::Object>
125
126=back
127
128=head1 METHODS
129
130=head2 push_viewport $vp_class, %args
131
f1cd5548 132Creates a new instance of the L<Reaction::UI::ViewPort> class
133($vp_class) using the rest of the arguments given (%args). Defaults of
134the action can be overridden by using the C<ViewPort> key in the
135controller configuration. For example to override the default number
136of items in a CRUD list action:
137
138__PACKAGE__->config(
139 action => {
140 list => { ViewPort => { per_page => 50 } },
141 }
142 );
143
144The ViewPort is added to the L<Reaction::UI::Window>'s FocusStack in
145the stash, and also returned to the calling code.
146
147Related items:
148
149=over
150
151=item L<Reaction::UI::Controller::Root>
152=item L<Reaction::UI::Window>
153
154=back
f2756356 155
156TODO: explain how next_action as a scalar gets converted to the redirect arrayref thing
157
158=head2 pop_viewport
159
160=head2 pop_viewport_to $vp
161
f1cd5548 162Call L<Reaction::UI::FocusStack/pop_viewport> or
163L<Reaction::UI::FocusStack/pop_viewport_to> on
164the C<< $c->stash->{focus_stack} >>.
f2756356 165
166=head2 redirect_to $c, $to, $captures, $args, $attrs
167
f1cd5548 168Construct a URI and redirect to it.
169
170$to can be:
171
172=over
f2756356 173
f1cd5548 174=item The name of an action in the current controller.
f2756356 175
f1cd5548 176=item A L<Catalyst::Action> instance.
177
178=item An arrayref of controller name and the name of an action in that
179controller.
180
181=back
f2756356 182
f1cd5548 183$captures and $args default to the current requests $captures and
184$args if not supplied.
f2756356 185
b4e081f8 186=head2 make_context_closure
187
188The purpose of this method is to prevent memory leaks.
189It weakens the context object, often denoted $c, and passes it as the
190first argument to the sub{} that is passed to the make_context_closure method.
191In other words,
192
193=over 4
194
195make_context_closure returns sub { $sub_you_gave_it->($weak_c, @_)
196
197=back
198
199To further expound up this useful construct consider code written before
200make_context_closure was created:
201
202 on_apply_callback =>
203 sub {
204 $self->after_search( $c, @_ );
205 }
206 ),
207
208This could be rewritten as:
209
210 on_apply_callback => $self->make_context_closure(
211 sub {
212 my $weak_c = shift;
213 $self->after_search( $weak_c, @_ );
214 }
215 ),
216
217Or even more succintly:
218
219 on_apply_callback => $self->make_context_closure(
220 sub {
221 $self->after_search( @_ );
222 }
223 ),
224
f2756356 225=head1 AUTHORS
226
227See L<Reaction::Class> for authors.
228
229=head1 LICENSE
230
231See L<Reaction::Class> for the license.
232
233=cut