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