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/ || ( defined $res->body && 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 $req_param = $ctx->req->$meth;
56 $_ =~ m/(^r.+\:\w+)\.(x|y)/ ? # for <input type="image"... buttons
57 ( $1 => $req_param->{$_} )
58 : ( $_ => $req_param->{$_} )
60 }; # yeah, FocusStack deletes it
61 my @param_keys = keys %$param_hash;
64 utf8::decode($param_hash->{$_})
65 unless (utf8::is_utf8($param_hash->{$_}));
67 $self->focus_stack->apply_events($param_hash);
73 my $res = $self->ctx->res;
74 my $res_body = $self->view->render_window($self);
75 utf8::encode($res_body) if utf8::is_utf8($res_body);
76 $res->body($res_body);
77 $res->content_type($self->content_type);
80 # required by old Renderer::XHTML
84 return $self->view->render_viewport($self, $vp);
87 __PACKAGE__->meta->make_immutable;
94 Reaction::UI::Window - Container for rendering the UI elements in
98 my $window = Reaction::UI::Window->new(
100 view_name => $view_name,
101 content_type => $content_type,
102 title => $window_title,
105 # More commonly, as Reaction::UI::Controller::Root creates one for you:
106 my $window = $ctx->stash->{window};
108 # Resolve current events and render the view of the UI
109 # elements of this Window:
110 # This is called by the end action of Reaction::UI::Controller::Root
113 # Resolve current events:
114 $window->flush_events();
116 # Render the top ViewPort in the FocusStack of this Window:
117 $window->flush_view();
119 # Render a particular ViewPort:
120 $window->render_viewport($viewport);
123 [% window.render_viewport(self.inner) %]
125 # Add a ViewPort to the UI:
126 $window->focus_stack->push_viewport('Reaction::UI::ViewPort');
130 A Window object is created and stored in the stash by
131 L<Reaction::UI::Controller::Root>, it is used to contain all the
132 elements (ViewPorts) that make up the UI. The Window is rendered in
133 the end action of the Root Controller to make up the page.
135 To add L<ViewPorts|Reaction::UI::ViewPort> to the stack, use the
136 L<Reaction::UI::Controller/push_viewport> method. For more detailed
137 information, read the L<Reaction::UI::FocusStack> and
138 L<Reaction::UI::ViewPort> documentation.
142 These are set for you by L<Reaction::UI::Controller::Root/begin> from
143 your Root controller configuration.
149 =item Arguments: $ctx?
153 The current L<Catalyst> context object.
159 =item Arguments: $viewname?
163 Retrieve/set the name of the L<Catalyst::View> component used to render
164 this Window. If this has not been set, rendering the Window will fail.
170 =item Arguments: $contenttype?
174 Retrieve the content_type for the page. If this has not been set,
175 rendering the Window will fail.
181 =item Arguments: $title?
187 Retrieve/set the title of this page, if not set, it will default to
194 =item Arguments: none
198 Retrieve the L<Catalyst::View> instance, this can be set, or will be
199 instantiated using the L<view_name> class.
205 =item Arguments: none
209 $window->focus_stack->push_viewport('Reaction::UI::ViewPort');
211 Retrieve the L<stack|Reaction::UI::FocusStack> of
212 L<ViewPorts|Reaction::UI::ViewPorts> that contains all the UI elements
213 for this Window. Use L<Reaction::UI::FocusStack/push_viewport> on this
214 to create more elements. An empty FocusStack is created by the
215 Controller::Root when the Window is created.
223 =item Arguments: none
227 Synchronize the current events with all the L<Reaction::UI::ViewPort>
228 objects in the UI, then render the root ViewPort. This is called for
229 you by L<Reaction::UI::Controller::Root/end>.
235 =item Arguments: none
239 Resolves all the current events, first the query parameters then the
240 body parameters, with all the L<Reaction::UI::ViewPort> objects in the
241 UI. This calls L<Reaction::UI::FocusStack/apply_events>. This method
242 is called by L<flush>.
248 =item Arguments: none
252 Renders the page into the L<Catalyst::Response> body, unless the
253 response status is already set to 3xx, or the body has already been
254 filled. This is done via L<Reaction::UI::View/render_window>. This
255 method is called by L<flush>.
259 See L<Reaction::Class> for authors.
263 See L<Reaction::Class> for the license.