r15425@deathmachine (orig r456): groditi | 2008-01-02 13:49:19 -0500
[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 class Window which {
7
8   has ctx => (isa => 'Catalyst', is => 'ro', required => 1);
9   has view_name => (isa => 'Str', is => 'ro', lazy_fail => 1);
10   has content_type => (isa => 'Str', is => 'ro', lazy_fail => 1);
11   has title => (isa => 'Str', is => 'rw', default => sub { 'Untitled window' });
12   has view => (
13     # XXX compile failure because the Catalyst::View constraint would be
14     # auto-generated which doesn't work with unions. ::Types::Catalyst needed.
15     #isa => 'Catalyst::View|Reaction::UI::View',
16     isa => 'Object', is => 'ro', lazy_build => 1
17   );
18   has focus_stack => (
19     isa => 'Reaction::UI::FocusStack',
20     is => 'ro', required => 1,
21     default => sub { Reaction::UI::FocusStack->new },
22   );
23
24   implements _build_view => as {
25     my ($self) = @_;
26     return $self->ctx->view($self->view_name);
27   };
28
29   implements flush => as {
30     my ($self) = @_;
31     $self->flush_events;
32     $self->flush_view;
33   };
34
35   implements flush_events => as {
36     my ($self) = @_;
37     my $ctx = $self->ctx;
38     foreach my $type (qw/query body/) {
39       my $meth = "${type}_parameters";
40       my $param_hash = $ctx->req->$meth;
41       $self->focus_stack->apply_events($ctx, $param_hash);
42     }
43   };
44
45   implements flush_view => as {
46     my ($self) = @_;
47     return if $self->ctx->res->status =~ /^3/ || length($self->ctx->res->body);
48     $self->ctx->res->body(
49       $self->view->render_window($self)
50     );
51     $self->ctx->res->content_type($self->content_type);
52   };
53
54   # required by old Renderer::XHTML
55
56   implements render_viewport => as {
57     my ($self, $vp) = @_;
58     return unless $vp;
59     return $self->view->render_viewport($self, $vp);
60   };
61
62 };
63
64 1;
65
66 =head1 NAME
67
68 Reaction::UI::Window - Container for rendering the UI elements in
69
70 =head1 SYNOPSIS
71
72   my $window = Reaction::UI::Window->new(
73     ctx => $ctx,
74     view_name => $view_name,
75     content_type => $content_type,
76     title => $window_title,
77   );
78
79   # More commonly, as Reaction::UI::Controller::Root creates one for you:
80   my $window = $ctx->stash->{window};
81
82   # Resolve current events and render the view of the UI
83   #  elements of this Window:
84   # This is called by the end action of Reaction::UI::Controller::Root
85   $window->flush();
86
87   # Resolve current events:
88   $window->flush_events();
89
90   # Render the top ViewPort in the FocusStack of this Window:
91   $window->flush_view();
92
93   # Render a particular ViewPort:
94   $window->render_viewport($viewport);
95
96   # Or in a template:
97   [% window.render_viewport(self.inner) %]
98
99   # Add a ViewPort to the UI:
100   $window->focus_stack->push_viewport('Reaction::UI::ViewPort');
101
102 =head1 DESCRIPTION
103
104 A Window object is created and stored in the stash by
105 L<Reaction::UI::Controller::Root>, it is used to contain all the
106 elements (ViewPorts) that make up the UI. The Window is rendered in
107 the end action of the Root Controller to make up the page.
108
109 To add L<ViewPorts|Reaction::UI::ViewPort> to the stack, read the
110 L<Reaction::UI::FocusStack> and L<Reaction::UI::ViewPort> documentation.
111
112 Several Window attributes are set by
113 L<Reaction::UI::Controller::Root/begin> when a new Window is created,
114 these are as follows:
115
116 =over
117
118 =item ctx
119
120 The current L<Catalyst> context object is set.
121
122 =item view_name
123
124 The view_name is set from the L<Reaction::UI::Controller::Root> attributes.
125
126 =item content_type
127
128 The content_type is set from the L<Reaction::UI::Controller::Root> attributes.
129
130 =item title
131
132 The title is set from the L<Reaction::UI::Controller::Root>
133 window_title attribute.
134
135 =back
136
137 =head1 METHODS
138
139 =head2 ctx
140
141 =over
142
143 =item Arguments: $ctx?
144
145 =back
146
147 Retrieve/set the current L<Catalyst> context object.
148
149 =head2 view_name
150
151 =over
152
153 =item Arguments: %viewname?
154
155 =back
156
157 Retrieve/set the name of the L<Catalyst::View> component used to render
158 this Window. If this has not been set, rendering the Window will fail.
159
160 =head2 content_type
161
162 =over
163
164 =item Arguments: $contenttype?
165
166 =back
167
168 Retrieve the content_type for the page. If this has not been set,
169 rendering the Window will fail.
170
171 =head2 title
172
173 =over
174
175 =item Arguments: $title?
176
177 =back
178
179   [% window.title %]
180
181 Retrieve/set the title of this page, if not set, it will default to
182 "Untitled window".
183
184 =head2 view
185
186 =over
187
188 =item Arguments: none
189
190 =back
191
192 Retrieve the L<Catalyst::View> instance, this can be set, or will be
193 instantiated using the L<view_name> class.
194
195 =head2 focus_stack
196
197 =over
198
199 =item Arguments: none
200
201 =back
202
203   $window->focus_stack->push_viewport('Reaction::UI::ViewPort');
204
205 Retrieve the L<stack|Reaction::UI::FocusStack> of
206 L<ViewPorts|Reaction::UI::ViewPorts> that contains all the UI elements
207 for this Window. Use L<Reaction::UI::FocusStack/push_viewport> on this
208 to create more elements. An empty FocusStack is created by the
209 Controller::Root when the Window is created.
210
211 =head2 render_viewport
212
213 =over
214
215 =item Arguments: $viewport
216
217 =back
218
219   $window->render_viewport($viewport);
220
221   [% window.render_viewport(self.inner) %]
222
223 Calls render on the L<view> object used by this Window. The following
224 arguments are given:
225
226 =over
227
228 =item ctx
229
230 The L<Catalyst> context object.
231
232 =item self
233
234 The ViewPort object to be rendered.
235
236 =item window
237
238 The Window object.
239
240 =item type
241
242 The string that describes the layout from L<Reaction::UI::ViewPort/layout>.
243
244 =back
245
246 =head2 flush
247
248 =over
249
250 =item Arguments: none
251
252 =back
253
254 Synchronize the current events with all the L<Reaction::UI::ViewPort>
255 objects in the UI, then render the root ViewPort. This is called for
256 you by L<Reaction::UI::Controller::Root/end>.
257
258 =head2 flush_events
259
260 =over
261
262 =item Arguments: none
263
264 =back
265
266 Resolves all the current events, first the query parameters then the
267 body parameters, with all the L<Reaction::UI::ViewPort> objects in the
268 UI. This calls L<Reaction::UI::FocusStack/apply_events>. This method
269 is called by L<flush>.
270
271 =head2 flush_view
272
273 =over
274
275 =item Arguments: none
276
277 =back
278
279 Renders the page into the L<Catalyst::Response> body, unless the
280 response status is already set to 3xx, or the body has already been
281 filled. This calls L<render_viewport> with the root
282 L<Reaction::UI::ViewPort> from the L<focus_stack>. This method is
283 called by L<flush>.
284
285 =head1 AUTHORS
286
287 See L<Reaction::Class> for authors.
288
289 =head1 LICENSE
290
291 See L<Reaction::Class> for the license.
292
293 =cut