diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Reaction/InterfaceModel/Action/User/Login.pm | 3 | ||||
-rw-r--r-- | lib/Reaction/UI/Controller.pm | 39 | ||||
-rw-r--r-- | lib/Reaction/UI/LayoutSet.pm | 2 | ||||
-rw-r--r-- | lib/Reaction/UI/ViewPort/Role/Actions.pm | 7 | ||||
-rw-r--r-- | lib/Reaction/UI/ViewPort/SearchableListViewContainer.pm | 15 | ||||
-rw-r--r-- | lib/Reaction/UI/Window.pm | 14 |
6 files changed, 68 insertions, 12 deletions
diff --git a/lib/Reaction/InterfaceModel/Action/User/Login.pm b/lib/Reaction/InterfaceModel/Action/User/Login.pm index 31abd8b..21c5e03 100644 --- a/lib/Reaction/InterfaceModel/Action/User/Login.pm +++ b/lib/Reaction/InterfaceModel/Action/User/Login.pm @@ -7,7 +7,8 @@ use Reaction::Types::Core qw(SimpleStr Password); use namespace::clean -except => [ qw(meta) ]; extends Action; - +# Avoid circular ref with target_model for Auth controller login actions. +sub BUILD { Scalar::Util::weaken($_[0]->{target_model}) } has 'username' => (isa => SimpleStr, is => 'rw', lazy_fail => 1); has 'password' => (isa => Password, is => 'rw', lazy_fail => 1); diff --git a/lib/Reaction/UI/Controller.pm b/lib/Reaction/UI/Controller.pm index d5c2b28..46456bd 100644 --- a/lib/Reaction/UI/Controller.pm +++ b/lib/Reaction/UI/Controller.pm @@ -184,6 +184,45 @@ controller. $captures and $args default to the current requests $captures and $args if not supplied. +=head2 make_context_closure + +The purpose of this method is to prevent memory leaks. +It weakens the context object, often denoted $c, and passes it as the +first argument to the sub{} that is passed to the make_context_closure method. +In other words, + +=over 4 + +make_context_closure returns sub { $sub_you_gave_it->($weak_c, @_) + +=back + +To further expound up this useful construct consider code written before +make_context_closure was created: + + on_apply_callback => + sub { + $self->after_search( $c, @_ ); + } + ), + +This could be rewritten as: + + on_apply_callback => $self->make_context_closure( + sub { + my $weak_c = shift; + $self->after_search( $weak_c, @_ ); + } + ), + +Or even more succintly: + + on_apply_callback => $self->make_context_closure( + sub { + $self->after_search( @_ ); + } + ), + =head1 AUTHORS See L<Reaction::Class> for authors. diff --git a/lib/Reaction/UI/LayoutSet.pm b/lib/Reaction/UI/LayoutSet.pm index a976d5b..1ebc646 100644 --- a/lib/Reaction/UI/LayoutSet.pm +++ b/lib/Reaction/UI/LayoutSet.pm @@ -55,6 +55,8 @@ sub has_layout { exists $_[0]->layouts->{$_[1]} }; sub _load_file { my ($self, $file, $build_args) = @_; my $data = $file->slurp; + utf8::decode($data) + unless utf8::is_utf8($data); my $layouts = $self->layouts; # cheesy match for "=for layout name ... =something" # final split group also handles last in file, (?==) is lookahead diff --git a/lib/Reaction/UI/ViewPort/Role/Actions.pm b/lib/Reaction/UI/ViewPort/Role/Actions.pm index 6f3cd6a..ebd2d3c 100644 --- a/lib/Reaction/UI/ViewPort/Role/Actions.pm +++ b/lib/Reaction/UI/ViewPort/Role/Actions.pm @@ -16,6 +16,10 @@ has action_order => ( isa => 'ArrayRef' ); +has action_filter => ( + isa => 'CodeRef', is => 'ro', +); + has action_prototypes => ( is => 'ro', isa => 'HashRef', @@ -35,7 +39,8 @@ sub _build_computed_action_order { ($self->has_action_order ? $self->action_order : []), [ keys %{ $self->action_prototypes } ] ); - return $ordered ; + return $self->has_action_filter ? + $self->action_filter->($ordered, $self->model) : $ordered; } sub _build_actions { diff --git a/lib/Reaction/UI/ViewPort/SearchableListViewContainer.pm b/lib/Reaction/UI/ViewPort/SearchableListViewContainer.pm index b9f919d..a5696c9 100644 --- a/lib/Reaction/UI/ViewPort/SearchableListViewContainer.pm +++ b/lib/Reaction/UI/ViewPort/SearchableListViewContainer.pm @@ -5,6 +5,7 @@ use Reaction::Class; use aliased 'Reaction::InterfaceModel::Action::Search::UpdateSpec', 'UpdateSearchSpec'; use aliased 'Reaction::UI::ViewPort::ListViewWithSearch'; use aliased 'Reaction::UI::ViewPort::Action' => 'ActionVP'; +use aliased 'Reaction::UI::ViewPort'; use aliased 'Reaction::UI::ViewPort::Collection::Role::Pager', 'PagerRole'; use Method::Signatures::Simple; @@ -14,18 +15,20 @@ use namespace::clean -except => 'meta'; extends 'Reaction::UI::ViewPort'; has 'listview' => ( - isa => ListViewWithSearch, + isa => ViewPort, is => 'ro', required => 1, ); -has 'search_form' => (isa => ActionVP, is => 'ro', required => 1); +has 'search_form' => (isa => ViewPort, is => 'ro', required => 1); override BUILDARGS => sub { my $args = super; my $spec_event_id = $args->{location}.':search-spec'; my $spec_class = $args->{spec_class} or confess "Argument spec_class is required"; + my $listview_class = $args->{'listview_class'} || ListViewWithSearch; + my $search_form_class = $args->{'search_form_class'} || ActionVP; my $action_class = $args->{action_class} or confess "Argument action_class is required"; # TODO: how do we autodiscover spec classes? @@ -39,15 +42,13 @@ override BUILDARGS => sub { } }; my $listview_location = $args->{location}.'-listview'; - # should this maybe use the listview class in $args->{listview}? - my $listview = $args->{listview} = ListViewWithSearch->new( + my $listview = $args->{listview} = $listview_class->new( %$args, - layout => 'list_view', + layout => $args->{'listview_layout'} || 'list_view', search_spec => $spec, location => $listview_location, ); - # same as with listview wrt. class name - $args->{search_form} = ActionVP->new( + $args->{search_form} = $search_form_class->new( model => $action_class->new(target_model => $spec), location => $args->{location}.'-search_form', apply_label => 'search', diff --git a/lib/Reaction/UI/Window.pm b/lib/Reaction/UI/Window.pm index 610a935..876a286 100644 --- a/lib/Reaction/UI/Window.pm +++ b/lib/Reaction/UI/Window.pm @@ -51,14 +51,22 @@ sub flush_events { foreach my $type (qw/query body/) { my $meth = "${type}_parameters"; my $param_hash = { %{$ctx->req->$meth} }; # yeah, FocusStack deletes it - $self->focus_stack->apply_events($param_hash) - if keys %$param_hash; + 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); + } } }; sub flush_view { my ($self) = @_; my $res = $self->ctx->res; - $res->body($self->view->render_window($self)); + 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); }; |