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