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; |
59 | return if $res->status =~ /^3/ || length($res->body); |
60 | $res->body($self->view->render_window($self)); |
61 | $res->content_type($self->content_type); |
7adfd53f |
62 | }; |
63 | |
64 | # required by old Renderer::XHTML |
89939ff9 |
65 | |
7adfd53f |
66 | implements render_viewport => as { |
67 | my ($self, $vp) = @_; |
68 | return unless $vp; |
69 | return $self->view->render_viewport($self, $vp); |
70 | }; |
71 | |
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 | |
9964b409 |
89 | # More commonly, as Reaction::UI::Controller::Root creates one for you: |
7adfd53f |
90 | my $window = $ctx->stash->{window}; |
91 | |
89939ff9 |
92 | # Resolve current events and render the view of the UI |
7adfd53f |
93 | # elements of this Window: |
9964b409 |
94 | # This is called by the end action of Reaction::UI::Controller::Root |
7adfd53f |
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 |
9964b409 |
115 | L<Reaction::UI::Controller::Root>, it is used to contain all the |
7adfd53f |
116 | elements (ViewPorts) that make up the UI. The Window is rendered in |
9964b409 |
117 | the end action of the Root Controller to make up the page. |
7adfd53f |
118 | |
119 | To add L<ViewPorts|Reaction::UI::ViewPort> to the stack, read the |
120 | L<Reaction::UI::FocusStack> and L<Reaction::UI::ViewPort> documentation. |
121 | |
122 | Several Window attributes are set by |
9964b409 |
123 | L<Reaction::UI::Controller::Root/begin> when a new Window is created, |
7adfd53f |
124 | these are as follows: |
125 | |
126 | =over |
127 | |
128 | =item ctx |
129 | |
130 | The current L<Catalyst> context object is set. |
131 | |
132 | =item view_name |
133 | |
9964b409 |
134 | The view_name is set from the L<Reaction::UI::Controller::Root> attributes. |
7adfd53f |
135 | |
136 | =item content_type |
137 | |
9964b409 |
138 | The content_type is set from the L<Reaction::UI::Controller::Root> attributes. |
7adfd53f |
139 | |
9964b409 |
140 | =item title |
7adfd53f |
141 | |
9964b409 |
142 | The title is set from the L<Reaction::UI::Controller::Root> |
143 | window_title attribute. |
7adfd53f |
144 | |
145 | =back |
146 | |
147 | =head1 METHODS |
148 | |
149 | =head2 ctx |
150 | |
151 | =over |
152 | |
9964b409 |
153 | =item Arguments: $ctx? |
7adfd53f |
154 | |
155 | =back |
156 | |
9964b409 |
157 | Retrieve/set the current L<Catalyst> context object. |
7adfd53f |
158 | |
159 | =head2 view_name |
160 | |
161 | =over |
162 | |
9964b409 |
163 | =item Arguments: %viewname? |
7adfd53f |
164 | |
165 | =back |
166 | |
9964b409 |
167 | Retrieve/set the name of the L<Catalyst::View> component used to render |
7adfd53f |
168 | this Window. If this has not been set, rendering the Window will fail. |
169 | |
170 | =head2 content_type |
171 | |
172 | =over |
173 | |
9964b409 |
174 | =item Arguments: $contenttype? |
7adfd53f |
175 | |
176 | =back |
177 | |
178 | Retrieve the content_type for the page. If this has not been set, |
179 | rendering the Window will fail. |
180 | |
181 | =head2 title |
182 | |
183 | =over |
184 | |
185 | =item Arguments: $title? |
186 | |
187 | =back |
188 | |
189 | [% window.title %] |
190 | |
9964b409 |
191 | Retrieve/set the title of this page, if not set, it will default to |
7adfd53f |
192 | "Untitled window". |
193 | |
194 | =head2 view |
195 | |
196 | =over |
197 | |
198 | =item Arguments: none |
199 | |
200 | =back |
201 | |
202 | Retrieve the L<Catalyst::View> instance, this can be set, or will be |
203 | instantiated using the L<view_name> class. |
204 | |
205 | =head2 focus_stack |
206 | |
207 | =over |
208 | |
209 | =item Arguments: none |
210 | |
211 | =back |
212 | |
213 | $window->focus_stack->push_viewport('Reaction::UI::ViewPort'); |
214 | |
215 | Retrieve the L<stack|Reaction::UI::FocusStack> of |
216 | L<ViewPorts|Reaction::UI::ViewPorts> that contains all the UI elements |
217 | for this Window. Use L<Reaction::UI::FocusStack/push_viewport> on this |
218 | to create more elements. An empty FocusStack is created by the |
9964b409 |
219 | Controller::Root when the Window is created. |
7adfd53f |
220 | |
221 | =head2 render_viewport |
222 | |
223 | =over |
224 | |
225 | =item Arguments: $viewport |
226 | |
227 | =back |
228 | |
229 | $window->render_viewport($viewport); |
230 | |
231 | [% window.render_viewport(self.inner) %] |
232 | |
233 | Calls render on the L<view> object used by this Window. The following |
234 | arguments are given: |
235 | |
236 | =over |
237 | |
238 | =item ctx |
239 | |
240 | The L<Catalyst> context object. |
241 | |
242 | =item self |
243 | |
244 | The ViewPort object to be rendered. |
245 | |
246 | =item window |
247 | |
248 | The Window object. |
249 | |
250 | =item type |
251 | |
252 | The string that describes the layout from L<Reaction::UI::ViewPort/layout>. |
253 | |
254 | =back |
255 | |
256 | =head2 flush |
257 | |
258 | =over |
259 | |
260 | =item Arguments: none |
261 | |
262 | =back |
263 | |
264 | Synchronize the current events with all the L<Reaction::UI::ViewPort> |
265 | objects in the UI, then render the root ViewPort. This is called for |
9964b409 |
266 | you by L<Reaction::UI::Controller::Root/end>. |
7adfd53f |
267 | |
268 | =head2 flush_events |
269 | |
270 | =over |
271 | |
272 | =item Arguments: none |
273 | |
274 | =back |
275 | |
276 | Resolves all the current events, first the query parameters then the |
277 | body parameters, with all the L<Reaction::UI::ViewPort> objects in the |
278 | UI. This calls L<Reaction::UI::FocusStack/apply_events>. This method |
279 | is called by L<flush>. |
280 | |
281 | =head2 flush_view |
282 | |
283 | =over |
284 | |
285 | =item Arguments: none |
286 | |
287 | =back |
288 | |
289 | Renders the page into the L<Catalyst::Response> body, unless the |
290 | response status is already set to 3xx, or the body has already been |
291 | filled. This calls L<render_viewport> with the root |
292 | L<Reaction::UI::ViewPort> from the L<focus_stack>. This method is |
293 | called by L<flush>. |
294 | |
295 | =head1 AUTHORS |
296 | |
297 | See L<Reaction::Class> for authors. |
298 | |
299 | =head1 LICENSE |
300 | |
301 | See L<Reaction::Class> for the license. |
302 | |
303 | =cut |