moved handle for image buttons to UI::Window
[catagits/Reaction.git] / lib / Reaction / UI / Window.pm
index 2bf4fc6..0289b39 100644 (file)
@@ -3,63 +3,89 @@ package Reaction::UI::Window;
 use Reaction::Class;
 use Reaction::UI::FocusStack;
 
-class Window which {
-
-  has ctx => (isa => 'Catalyst', is => 'ro', required => 1);
-  has view_name => (isa => 'Str', is => 'ro', lazy_fail => 1);
-  has content_type => (isa => 'Str', is => 'ro', lazy_fail => 1);
-  has title => (isa => 'Str', is => 'rw', default => sub { 'Untitled window' });
-  has view => (
-    # XXX compile failure because the Catalyst::View constraint would be
-    # auto-generated which doesn't work with unions. ::Types::Catalyst needed.
-    #isa => 'Catalyst::View|Reaction::UI::View',
-    isa => 'Object', is => 'ro', lazy_build => 1
-  );
-  has focus_stack => (
-    isa => 'Reaction::UI::FocusStack',
-    is => 'ro', required => 1,
-    default => sub { Reaction::UI::FocusStack->new },
-  );
-
-  implements _build_view => as {
-    my ($self) = @_;
-    return $self->ctx->view($self->view_name);
-  };
-
-  implements flush => as {
-    my ($self) = @_;
-    $self->flush_events;
-    $self->flush_view;
-  };
-
-  implements flush_events => as {
-    my ($self) = @_;
-    my $ctx = $self->ctx;
-    foreach my $type (qw/query body/) {
-      my $meth = "${type}_parameters";
-      my $param_hash = $ctx->req->$meth;
-      $self->focus_stack->apply_events($ctx, $param_hash);
+use namespace::clean -except => [ qw(meta) ];
+
+
+has ctx => (isa => 'Catalyst', is => 'ro', required => 1, weak_ref => 1);
+has view_name => (isa => 'Str', is => 'ro', lazy_fail => 1);
+has content_type => (isa => 'Str', is => 'rw', lazy_fail => 1);
+has title => (isa => 'Str', is => 'rw', default => sub { 'Untitled window' });
+has view => (
+  # XXX compile failure because the Catalyst::View constraint would be
+  # auto-generated which doesn't work with unions. ::Types::Catalyst needed.
+  #isa => 'Catalyst::View|Reaction::UI::View',
+  isa => 'Object', is => 'ro', lazy_build => 1
+);
+has focus_stack => (
+  isa => 'Reaction::UI::FocusStack',
+  is => 'ro', required => 1,
+  default => sub { Reaction::UI::FocusStack->new },
+);
+sub _build_view {
+  my ($self) = @_;
+  return $self->ctx->view($self->view_name);
+};
+sub flush {
+  my ($self) = @_;
+  my $res = $self->ctx->res;
+  if ( $res->status =~ /^3/ || length($res->body) ) {
+      $res->content_type('text/plain') unless $res->content_type;
+      return;
+  }
+  $self->flush_events;
+  $self->flush_view;
+};
+sub flush_events {
+  my ($self) = @_;
+  my $ctx = $self->ctx;
+
+  #I really think we should make a copies of the parameter hashes here
+  #and then as we handle events, delete ethem from the event hashref, so
+  #that it thins down as it makes it down the viewport tree. which would
+  #limit the number of events that get to the children viewports. it wont
+  #save that many subcalls unless there is a lot of child_items, but it's
+  #more about doing the correct thing. It also avoids children viewports
+  #being able to see their parents' events, which leaves the door open for
+  #abuse of the system.  thoughts anyone?
+
+  foreach my $type (qw/query body/) {
+    my $meth = "${type}_parameters";
+    my $req_param = $ctx->req->$meth;
+    my $param_hash = { 
+        map {
+            $_ =~ m/(^r.+\:\w+)\.(x|y)/ ? # for <input type="image"... buttons
+              ( $1 => $req_param->{$_} )
+              : ( $_ => $req_param->{$_} )
+        } keys %$req_param
+    }; # yeah, FocusStack deletes it
+    my @param_keys = keys %$param_hash;
+    if (@param_keys) {
+        for (@param_keys) {
+            utf8::decode($param_hash->{$_})
+                unless (utf8::is_utf8($param_hash->{$_}));
+        }
+        $self->focus_stack->apply_events($param_hash);
     }
-  };
-
-  implements flush_view => as {
-    my ($self) = @_;
-    return if $self->ctx->res->status =~ /^3/ || length($self->ctx->res->body);
-    $self->ctx->res->body(
-      $self->view->render_window($self)
-    );
-    $self->ctx->res->content_type($self->content_type);
-  };
+  }
+};
+sub flush_view {
+  my ($self) = @_;
+  my $res = $self->ctx->res;
+  my $res_body = $self->view->render_window($self);
+  utf8::encode($res_body) if utf8::is_utf8($res_body);
+  $res->body($res_body);
+  $res->content_type($self->content_type);
+};
 
-  # required by old Renderer::XHTML
+# required by old Renderer::XHTML
+sub render_viewport {
+  my ($self, $vp) = @_;
+  return unless $vp;
+  return $self->view->render_viewport($self, $vp);
+};
 
-  implements render_viewport => as {
-    my ($self, $vp) = @_;
-    return unless $vp;
-    return $self->view->render_viewport($self, $vp);
-  };
+__PACKAGE__->meta->make_immutable;
 
-};
 
 1;
 
@@ -76,12 +102,12 @@ Reaction::UI::Window - Container for rendering the UI elements in
     title => $window_title,
   );
 
-  # More commonly, as Reaction::UI::RootController creates one for you:
+  # More commonly, as Reaction::UI::Controller::Root creates one for you:
   my $window = $ctx->stash->{window};
 
   # Resolve current events and render the view of the UI
   #  elements of this Window:
-  # This is called by the end action of Reaction::UI::RootController
+  # This is called by the end action of Reaction::UI::Controller::Root
   $window->flush();
 
   # Resolve current events:
@@ -102,65 +128,46 @@ Reaction::UI::Window - Container for rendering the UI elements in
 =head1 DESCRIPTION
 
 A Window object is created and stored in the stash by
-L<Reaction::UI::RootController>, it is used to contain all the
+L<Reaction::UI::Controller::Root>, it is used to contain all the
 elements (ViewPorts) that make up the UI. The Window is rendered in
-the end action of the RootController to make up the page.
+the end action of the Root Controller to make up the page.
 
-To add L<ViewPorts|Reaction::UI::ViewPort> to the stack, read the
-L<Reaction::UI::FocusStack> and L<Reaction::UI::ViewPort> documentation.
-
-Several Window attributes are set by
-L<Reaction::UI::RootController/begin> when a new Window is created,
-these are as follows:
-
-=over
+To add L<ViewPorts|Reaction::UI::ViewPort> to the stack, use the
+L<Reaction::UI::Controller/push_viewport> method. For more detailed
+information, read the L<Reaction::UI::FocusStack> and
+L<Reaction::UI::ViewPort> documentation.
 
-=item ctx
+=head1 ATTRIBUTES
 
-The current L<Catalyst> context object is set.
-
-=item view_name
-
-The view_name is set from the L<Reaction::UI::RootController> attributes.
-
-=item content_type
-
-The content_type is set from the L<Reaction::UI::RootController> attributes.
-
-=item window_title
-
-The window_title is set from the L<Reaction::UI::RootController> attributes.
-
-=back
-
-=head1 METHODS
+These are set for you by L<Reaction::UI::Controller::Root/begin> from
+your Root controller configuration.
 
 =head2 ctx
 
 =over
 
-=item Arguments: none
+=item Arguments: $ctx?
 
 =back
 
-Retrieve the current L<Catalyst> context object.
+The current L<Catalyst> context object.
 
 =head2 view_name
 
 =over
 
-=item Arguments: none
+=item Arguments: $viewname?
 
 =back
 
-Retrieve the name of the L<Catalyst::View> component used to render
+Retrieve/set the name of the L<Catalyst::View> component used to render
 this Window. If this has not been set, rendering the Window will fail.
 
 =head2 content_type
 
 =over
 
-=item Arguments: none
+=item Arguments: $contenttype?
 
 =back
 
@@ -177,7 +184,7 @@ rendering the Window will fail.
 
   [% window.title %]
 
-Retrieve the title of this page, if not set, it will default to
+Retrieve/set the title of this page, if not set, it will default to
 "Untitled window".
 
 =head2 view
@@ -205,42 +212,9 @@ Retrieve the L<stack|Reaction::UI::FocusStack> of
 L<ViewPorts|Reaction::UI::ViewPorts> that contains all the UI elements
 for this Window. Use L<Reaction::UI::FocusStack/push_viewport> on this
 to create more elements. An empty FocusStack is created by the
-RootController when the Window is created.
-
-=head2 render_viewport
-
-=over
-
-=item Arguments: $viewport
-
-=back
-
-  $window->render_viewport($viewport);
-
-  [% window.render_viewport(self.inner) %]
-
-Calls render on the L<view> object used by this Window. The following
-arguments are given:
+Controller::Root when the Window is created.
 
-=over
-
-=item ctx
-
-The L<Catalyst> context object.
-
-=item self
-
-The ViewPort object to be rendered.
-
-=item window
-
-The Window object.
-
-=item type
-
-The string that describes the layout from L<Reaction::UI::ViewPort/layout>.
-
-=back
+=head1 METHODS
 
 =head2 flush
 
@@ -252,7 +226,7 @@ The string that describes the layout from L<Reaction::UI::ViewPort/layout>.
 
 Synchronize the current events with all the L<Reaction::UI::ViewPort>
 objects in the UI, then render the root ViewPort. This is called for
-you by L<Reaction::UI::RootController/end>.
+you by L<Reaction::UI::Controller::Root/end>.
 
 =head2 flush_events
 
@@ -277,9 +251,8 @@ is called by L<flush>.
 
 Renders the page into the L<Catalyst::Response> body, unless the
 response status is already set to 3xx, or the body has already been
-filled. This calls L<render_viewport> with the root
-L<Reaction::UI::ViewPort> from the L<focus_stack>. This method is
-called by L<flush>.
+filled. This is done via L<Reaction::UI::View/render_window>. This
+method is called by L<flush>.
 
 =head1 AUTHORS