Grid->field_labels as rw attr
[catagits/Reaction.git] / lib / Reaction / UI / Window.pm
1 package Reaction::UI::Window;
2
3 use Reaction::Class;
4 use Reaction::UI::FocusStack;
5
6 use namespace::clean -except => [ qw(meta) ];
7
8
9 has ctx => (isa => 'Catalyst', is => 'ro', required => 1);
10 has view_name => (isa => 'Str', is => 'ro', lazy_fail => 1);
11 has content_type => (isa => 'Str', is => 'rw', lazy_fail => 1);
12 has title => (isa => 'Str', is => 'rw', default => sub { 'Untitled window' });
13 has view => (
14   # XXX compile failure because the Catalyst::View constraint would be
15   # auto-generated which doesn't work with unions. ::Types::Catalyst needed.
16   #isa => 'Catalyst::View|Reaction::UI::View',
17   isa => 'Object', is => 'ro', lazy_build => 1
18 );
19 has focus_stack => (
20   isa => 'Reaction::UI::FocusStack',
21   is => 'ro', required => 1,
22   default => sub { Reaction::UI::FocusStack->new },
23 );
24 sub _build_view {
25   my ($self) = @_;
26   return $self->ctx->view($self->view_name);
27 };
28 sub flush {
29   my ($self) = @_;
30   $self->flush_events;
31   $self->flush_view;
32 };
33 sub flush_events {
34   my ($self) = @_;
35   my $ctx = $self->ctx;
36
37   #I really think we should make a copies of the parameter hashes here
38   #and then as we handle events, delete ethem from the event hashref, so
39   #that it thins down as it makes it down the viewport tree. which would
40   #limit the number of events that get to the children viewports. it wont
41   #save that many subcalls unless there is a lot of child_items, but it's
42   #more about doing the correct thing. It also avoids children viewports
43   #being able to see their parents' events, which leaves the door open for
44   #abuse of the system.  thoughts anyone?
45
46   foreach my $type (qw/query body/) {
47     my $meth = "${type}_parameters";
48     my $param_hash = $ctx->req->$meth;
49     $self->focus_stack->apply_events($param_hash)
50       if keys %$param_hash;
51   }
52 };
53 sub flush_view {
54   my ($self) = @_;
55   my $res = $self->ctx->res;
56   if ( $res->status =~ /^3/ || length($res->body) ) {
57       $res->content_type('text/plain') unless $res->content_type;
58       return;
59   }
60   $res->body($self->view->render_window($self));
61   $res->content_type($self->content_type);
62 };
63
64 # required by old Renderer::XHTML
65 sub render_viewport {
66   my ($self, $vp) = @_;
67   return unless $vp;
68   return $self->view->render_viewport($self, $vp);
69 };
70
71 __PACKAGE__->meta->make_immutable;
72
73
74 1;
75
76 =head1 NAME
77
78 Reaction::UI::Window - Container for rendering the UI elements in
79
80 =head1 SYNOPSIS
81
82   my $window = Reaction::UI::Window->new(
83     ctx => $ctx,
84     view_name => $view_name,
85     content_type => $content_type,
86     title => $window_title,
87   );
88
89   # More commonly, as Reaction::UI::Controller::Root creates one for you:
90   my $window = $ctx->stash->{window};
91
92   # Resolve current events and render the view of the UI
93   #  elements of this Window:
94   # This is called by the end action of Reaction::UI::Controller::Root
95   $window->flush();
96
97   # Resolve current events:
98   $window->flush_events();
99
100   # Render the top ViewPort in the FocusStack of this Window:
101   $window->flush_view();
102
103   # Render a particular ViewPort:
104   $window->render_viewport($viewport);
105
106   # Or in a template:
107   [% window.render_viewport(self.inner) %]
108
109   # Add a ViewPort to the UI:
110   $window->focus_stack->push_viewport('Reaction::UI::ViewPort');
111
112 =head1 DESCRIPTION
113
114 A Window object is created and stored in the stash by
115 L<Reaction::UI::Controller::Root>, it is used to contain all the
116 elements (ViewPorts) that make up the UI. The Window is rendered in
117 the end action of the Root Controller to make up the page.
118
119 To add L<ViewPorts|Reaction::UI::ViewPort> to the stack, use the
120 L<Reaction::UI::Controller/push_viewport> method. For more detailed
121 information, read the L<Reaction::UI::FocusStack> and
122 L<Reaction::UI::ViewPort> documentation.
123
124 =head1 ATTRIBUTES
125
126 These are set for you by L<Reaction::UI::Controller::Root/begin> from
127 your Root controller configuration.
128
129 =head2 ctx
130
131 =over
132
133 =item Arguments: $ctx?
134
135 =back
136
137 The current L<Catalyst> context object.
138
139 =head2 view_name
140
141 =over
142
143 =item Arguments: $viewname?
144
145 =back
146
147 Retrieve/set the name of the L<Catalyst::View> component used to render
148 this Window. If this has not been set, rendering the Window will fail.
149
150 =head2 content_type
151
152 =over
153
154 =item Arguments: $contenttype?
155
156 =back
157
158 Retrieve the content_type for the page. If this has not been set,
159 rendering the Window will fail.
160
161 =head2 title
162
163 =over
164
165 =item Arguments: $title?
166
167 =back
168
169   [% window.title %]
170
171 Retrieve/set the title of this page, if not set, it will default to
172 "Untitled window".
173
174 =head2 view
175
176 =over
177
178 =item Arguments: none
179
180 =back
181
182 Retrieve the L<Catalyst::View> instance, this can be set, or will be
183 instantiated using the L<view_name> class.
184
185 =head2 focus_stack
186
187 =over
188
189 =item Arguments: none
190
191 =back
192
193   $window->focus_stack->push_viewport('Reaction::UI::ViewPort');
194
195 Retrieve the L<stack|Reaction::UI::FocusStack> of
196 L<ViewPorts|Reaction::UI::ViewPorts> that contains all the UI elements
197 for this Window. Use L<Reaction::UI::FocusStack/push_viewport> on this
198 to create more elements. An empty FocusStack is created by the
199 Controller::Root when the Window is created.
200
201 =head1 METHODS
202
203 =head2 flush
204
205 =over
206
207 =item Arguments: none
208
209 =back
210
211 Synchronize the current events with all the L<Reaction::UI::ViewPort>
212 objects in the UI, then render the root ViewPort. This is called for
213 you by L<Reaction::UI::Controller::Root/end>.
214
215 =head2 flush_events
216
217 =over
218
219 =item Arguments: none
220
221 =back
222
223 Resolves all the current events, first the query parameters then the
224 body parameters, with all the L<Reaction::UI::ViewPort> objects in the
225 UI. This calls L<Reaction::UI::FocusStack/apply_events>. This method
226 is called by L<flush>.
227
228 =head2 flush_view
229
230 =over
231
232 =item Arguments: none
233
234 =back
235
236 Renders the page into the L<Catalyst::Response> body, unless the
237 response status is already set to 3xx, or the body has already been
238 filled. This is done via L<Reaction::UI::View/render_window>. This
239 method is called by L<flush>.
240
241 =head1 AUTHORS
242
243 See L<Reaction::Class> for authors.
244
245 =head1 LICENSE
246
247 See L<Reaction::Class> for the license.
248
249 =cut