Commit | Line | Data |
7adfd53f |
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::RootController 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::RootController |
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::RootController>, 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 RootController 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::RootController/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::RootController> attributes. |
125 | |
126 | =item content_type |
127 | |
128 | The content_type is set from the L<Reaction::UI::RootController> attributes. |
129 | |
130 | =item window_title |
131 | |
132 | The window_title is set from the L<Reaction::UI::RootController> attributes. |
133 | |
134 | =back |
135 | |
136 | =head1 METHODS |
137 | |
138 | =head2 ctx |
139 | |
140 | =over |
141 | |
142 | =item Arguments: none |
143 | |
144 | =back |
145 | |
146 | Retrieve the current L<Catalyst> context object. |
147 | |
148 | =head2 view_name |
149 | |
150 | =over |
151 | |
152 | =item Arguments: none |
153 | |
154 | =back |
155 | |
156 | Retrieve the name of the L<Catalyst::View> component used to render |
157 | this Window. If this has not been set, rendering the Window will fail. |
158 | |
159 | =head2 content_type |
160 | |
161 | =over |
162 | |
163 | =item Arguments: none |
164 | |
165 | =back |
166 | |
167 | Retrieve the content_type for the page. If this has not been set, |
168 | rendering the Window will fail. |
169 | |
170 | =head2 title |
171 | |
172 | =over |
173 | |
174 | =item Arguments: $title? |
175 | |
176 | =back |
177 | |
178 | [% window.title %] |
179 | |
180 | Retrieve the title of this page, if not set, it will default to |
181 | "Untitled window". |
182 | |
183 | =head2 view |
184 | |
185 | =over |
186 | |
187 | =item Arguments: none |
188 | |
189 | =back |
190 | |
191 | Retrieve the L<Catalyst::View> instance, this can be set, or will be |
192 | instantiated using the L<view_name> class. |
193 | |
194 | =head2 focus_stack |
195 | |
196 | =over |
197 | |
198 | =item Arguments: none |
199 | |
200 | =back |
201 | |
202 | $window->focus_stack->push_viewport('Reaction::UI::ViewPort'); |
203 | |
204 | Retrieve the L<stack|Reaction::UI::FocusStack> of |
205 | L<ViewPorts|Reaction::UI::ViewPorts> that contains all the UI elements |
206 | for this Window. Use L<Reaction::UI::FocusStack/push_viewport> on this |
207 | to create more elements. An empty FocusStack is created by the |
208 | RootController when the Window is created. |
209 | |
210 | =head2 render_viewport |
211 | |
212 | =over |
213 | |
214 | =item Arguments: $viewport |
215 | |
216 | =back |
217 | |
218 | $window->render_viewport($viewport); |
219 | |
220 | [% window.render_viewport(self.inner) %] |
221 | |
222 | Calls render on the L<view> object used by this Window. The following |
223 | arguments are given: |
224 | |
225 | =over |
226 | |
227 | =item ctx |
228 | |
229 | The L<Catalyst> context object. |
230 | |
231 | =item self |
232 | |
233 | The ViewPort object to be rendered. |
234 | |
235 | =item window |
236 | |
237 | The Window object. |
238 | |
239 | =item type |
240 | |
241 | The string that describes the layout from L<Reaction::UI::ViewPort/layout>. |
242 | |
243 | =back |
244 | |
245 | =head2 flush |
246 | |
247 | =over |
248 | |
249 | =item Arguments: none |
250 | |
251 | =back |
252 | |
253 | Synchronize the current events with all the L<Reaction::UI::ViewPort> |
254 | objects in the UI, then render the root ViewPort. This is called for |
255 | you by L<Reaction::UI::RootController/end>. |
256 | |
257 | =head2 flush_events |
258 | |
259 | =over |
260 | |
261 | =item Arguments: none |
262 | |
263 | =back |
264 | |
265 | Resolves all the current events, first the query parameters then the |
266 | body parameters, with all the L<Reaction::UI::ViewPort> objects in the |
267 | UI. This calls L<Reaction::UI::FocusStack/apply_events>. This method |
268 | is called by L<flush>. |
269 | |
270 | =head2 flush_view |
271 | |
272 | =over |
273 | |
274 | =item Arguments: none |
275 | |
276 | =back |
277 | |
278 | Renders the page into the L<Catalyst::Response> body, unless the |
279 | response status is already set to 3xx, or the body has already been |
280 | filled. This calls L<render_viewport> with the root |
281 | L<Reaction::UI::ViewPort> from the L<focus_stack>. This method is |
282 | called by L<flush>. |
283 | |
284 | =head1 AUTHORS |
285 | |
286 | See L<Reaction::Class> for authors. |
287 | |
288 | =head1 LICENSE |
289 | |
290 | See L<Reaction::Class> for the license. |
291 | |
292 | =cut |