1 package Reaction::UI::Window;
4 use Reaction::UI::FocusStack;
6 use namespace::clean -except => [ qw(meta) ];
9 has ctx => (isa => 'Catalyst', is => 'ro', required => 1, weak_ref => 1);
10 has view_name => (isa => 'Str', is => 'ro', lazy_fail => 1);
11 has content_type => (isa => 'Str', is => 'rw', lazy_fail => 1);
12 has title => (isa => 'Str', is => 'rw', default => sub { 'Untitled window' });
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
20 isa => 'Reaction::UI::FocusStack',
21 is => 'ro', required => 1,
22 default => sub { Reaction::UI::FocusStack->new },
26 return $self->ctx->view($self->view_name);
30 my $res = $self->ctx->res;
31 if ( $res->status =~ /^3/ || length($res->body) ) {
32 $res->content_type('text/plain') unless $res->content_type;
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?
51 foreach my $type (qw/query body/) {
52 my $meth = "${type}_parameters";
53 my $param_hash = { %{$ctx->req->$meth} }; # yeah, FocusStack deletes it
54 my @param_keys = keys %$param_hash;
57 utf8::decode($param_hash->{$_})
58 unless (utf8::is_utf8($param_hash->{$_}));
60 $self->focus_stack->apply_events($param_hash);
66 my $res = $self->ctx->res;
67 my $res_body = $self->view->render_window($self);
68 utf8::encode($res_body) if utf8::is_utf8($res_body);
69 $res->body($res_body);
70 $res->content_type($self->content_type);
73 # required by old Renderer::XHTML
77 return $self->view->render_viewport($self, $vp);
80 __PACKAGE__->meta->make_immutable;
87 Reaction::UI::Window - Container for rendering the UI elements in
91 my $window = Reaction::UI::Window->new(
93 view_name => $view_name,
94 content_type => $content_type,
95 title => $window_title,
98 # More commonly, as Reaction::UI::Controller::Root creates one for you:
99 my $window = $ctx->stash->{window};
101 # Resolve current events and render the view of the UI
102 # elements of this Window:
103 # This is called by the end action of Reaction::UI::Controller::Root
106 # Resolve current events:
107 $window->flush_events();
109 # Render the top ViewPort in the FocusStack of this Window:
110 $window->flush_view();
112 # Render a particular ViewPort:
113 $window->render_viewport($viewport);
116 [% window.render_viewport(self.inner) %]
118 # Add a ViewPort to the UI:
119 $window->focus_stack->push_viewport('Reaction::UI::ViewPort');
123 A Window object is created and stored in the stash by
124 L<Reaction::UI::Controller::Root>, it is used to contain all the
125 elements (ViewPorts) that make up the UI. The Window is rendered in
126 the end action of the Root Controller to make up the page.
128 To add L<ViewPorts|Reaction::UI::ViewPort> to the stack, use the
129 L<Reaction::UI::Controller/push_viewport> method. For more detailed
130 information, read the L<Reaction::UI::FocusStack> and
131 L<Reaction::UI::ViewPort> documentation.
135 These are set for you by L<Reaction::UI::Controller::Root/begin> from
136 your Root controller configuration.
142 =item Arguments: $ctx?
146 The current L<Catalyst> context object.
152 =item Arguments: $viewname?
156 Retrieve/set 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.
163 =item Arguments: $contenttype?
167 Retrieve the content_type for the page. If this has not been set,
168 rendering the Window will fail.
174 =item Arguments: $title?
180 Retrieve/set the title of this page, if not set, it will default to
187 =item Arguments: none
191 Retrieve the L<Catalyst::View> instance, this can be set, or will be
192 instantiated using the L<view_name> class.
198 =item Arguments: none
202 $window->focus_stack->push_viewport('Reaction::UI::ViewPort');
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 Controller::Root when the Window is created.
216 =item Arguments: none
220 Synchronize the current events with all the L<Reaction::UI::ViewPort>
221 objects in the UI, then render the root ViewPort. This is called for
222 you by L<Reaction::UI::Controller::Root/end>.
228 =item Arguments: none
232 Resolves all the current events, first the query parameters then the
233 body parameters, with all the L<Reaction::UI::ViewPort> objects in the
234 UI. This calls L<Reaction::UI::FocusStack/apply_events>. This method
235 is called by L<flush>.
241 =item Arguments: none
245 Renders the page into the L<Catalyst::Response> body, unless the
246 response status is already set to 3xx, or the body has already been
247 filled. This is done via L<Reaction::UI::View/render_window>. This
248 method is called by L<flush>.
252 See L<Reaction::Class> for authors.
256 See L<Reaction::Class> for the license.