diff options
author | groditi <groditi@03d0b0b2-0e1a-0410-a411-fdb2f4bd65d7> | 2008-10-11 21:15:47 +0000 |
---|---|---|
committer | groditi <groditi@03d0b0b2-0e1a-0410-a411-fdb2f4bd65d7> | 2008-10-11 21:15:47 +0000 |
commit | 37728bbad6840485e4d0e3a504dfdc851e7378c3 (patch) | |
tree | 0b971b7451c5fff6e554090f22ff881005729d5f | |
parent | 487c32080762a25ad34c785dc39753cbc941d355 (diff) | |
download | reaction-37728bbad6840485e4d0e3a504dfdc851e7378c3.tar.gz reaction-37728bbad6840485e4d0e3a504dfdc851e7378c3.zip |
completely new way of handling action prototypes for actions in CRUD that is much saner and less reliant on $ctx. also more flexible and configurable
-rw-r--r-- | lib/ComponentUI/Controller/TestModel/Foo.pm | 11 | ||||
-rw-r--r-- | lib/Reaction/UI/Controller/Collection.pm | 73 | ||||
-rw-r--r-- | lib/Reaction/UI/Controller/Collection/CRUD.pm | 53 | ||||
-rw-r--r-- | lib/Reaction/UI/ViewPort/Collection/Grid.pm | 17 | ||||
-rw-r--r-- | lib/Reaction/UI/ViewPort/Role/Actions.pm | 61 |
5 files changed, 147 insertions, 68 deletions
diff --git a/lib/ComponentUI/Controller/TestModel/Foo.pm b/lib/ComponentUI/Controller/TestModel/Foo.pm index b5dfe5b..e8e2318 100644 --- a/lib/ComponentUI/Controller/TestModel/Foo.pm +++ b/lib/ComponentUI/Controller/TestModel/Foo.pm @@ -11,6 +11,10 @@ __PACKAGE__->config( list => { ViewPort => { excluded_fields => [qw/id/], + action_order => [qw/delete_all create/], + Member => { + action_order => [qw/view update delete/], + }, }, }, view => { @@ -40,4 +44,11 @@ for my $action (qw/view create update/){ ); } +sub _build_action_viewport_args { + my $self = shift; + my $args = $self->next::method(@_); + $args->{list}{action_prototypes}{delete_all}{label} = 'Delete All Records'; + return $args; +} + 1; diff --git a/lib/Reaction/UI/Controller/Collection.pm b/lib/Reaction/UI/Controller/Collection.pm index e0328fe..204edd9 100644 --- a/lib/Reaction/UI/Controller/Collection.pm +++ b/lib/Reaction/UI/Controller/Collection.pm @@ -8,21 +8,77 @@ use Reaction::Class; use aliased 'Reaction::UI::ViewPort::Collection::Grid'; use aliased 'Reaction::UI::ViewPort::Object'; -has 'model_name' => (isa => 'Str', is => 'rw', required => 1); -has 'collection_name' => (isa => 'Str', is => 'rw', required => 1); +has model_name => (isa => 'Str', is => 'rw', required => 1); +has collection_name => (isa => 'Str', is => 'rw', required => 1); -has action_viewport_map => (isa => 'HashRef', is => 'rw', lazy_build => 1); +has action_viewport_map => (isa => 'HashRef', is => 'rw', lazy_build => 1); has action_viewport_args => (isa => 'HashRef', is => 'rw', lazy_build => 1); +has default_member_actions => ( + isa => 'ArrayRef', + is => 'rw', + lazy_build => 1 +); + +has default_collection_actions => ( + isa => 'ArrayRef', + is => 'rw', + lazy_build => 1 +); + +sub _build_default_member_actions { ['view'] } + +sub _build_default_collection_actions { [] } + sub _build_action_viewport_map { - return { - list => Grid, - view => Object, - }; + my $self = shift; + my %map; + $map{list} = Grid; + $map{view} = Object if grep {$_ eq 'view'} @{$self->default_member_actions}; + return \%map; } sub _build_action_viewport_args { - return { }; + my $self = shift; + my $args = { list => { Member => {} } }; + + my $m_protos = $args->{list}{Member}{action_prototypes} = {}; + for my $action_name( @{ $self->default_member_actions }){ + my $label = ucfirst(join(' ', split(/_/, $action_name))); + my $proto = $self->_build_member_action_prototype($label, $action_name); + $m_protos->{$action_name} = $proto; + } + + my $c_protos = $args->{list}{action_prototypes} = {}; + for my $action_name( @{ $self->default_collection_actions }){ + my $label = ucfirst(join(' ', split(/_/, $action_name))); + my $proto = $self->_build_collection_action_prototype($label, $action_name); + $c_protos->{$action_name} = $proto; + } + + return $args; +} + +sub _build_member_action_prototype { + my ($self, $label, $action_name) = @_; + return { + label => $label, + uri => sub { + my $action = $self->action_for($action_name); + $_[1]->uri_for($action, [ @{$_[1]->req->captures}, $_[0]->__id ]); + }, + }; +} + +sub _build_collection_action_prototype { + my ($self, $label, $action_name) = @_; + return { + label => $label, + uri => sub { + my $action = $self->action_for($action_name); + $_[1]->uri_for($action, $_[1]->req->captures); + }, + }; } #XXX candidate for futre optimization, should cache reader? @@ -74,7 +130,6 @@ sub basic_page { 1; - __END__; =head1 NAME diff --git a/lib/Reaction/UI/Controller/Collection/CRUD.pm b/lib/Reaction/UI/Controller/Collection/CRUD.pm index 285947b..7552077 100644 --- a/lib/Reaction/UI/Controller/Collection/CRUD.pm +++ b/lib/Reaction/UI/Controller/Collection/CRUD.pm @@ -9,47 +9,30 @@ use aliased 'Reaction::UI::ViewPort::Action'; use aliased 'Reaction::UI::ViewPort::ListView'; sub _build_action_viewport_map { - my $map = shift->next::method(@_); - $map->{list} = ListView; - $map->{$_} = Action for qw/create update delete delete_all/; + my $self = shift; + my $map = $self->next::method(@_); + $map->{list} = ListView if exists $map->{list}; + + my %allowed = map { $_ => undef } + ( @{$self->default_member_actions}, @{$self->default_collection_actions} ); + + my @local_actions = qw/create update delete delete_all/; + $map->{$_} = Action for grep { exists $allowed{$_} } @local_actions; + return $map; } -sub _build_action_viewport_args { - my $args = shift->next::method(@_); - $args->{list} = - { action_prototypes => - [ { label => 'Create', action => sub { - [ '', 'create', $_[1]->req->captures ] } }, - { label => 'Delete all', action => sub { - [ '', 'delete_all', $_[1]->req->captures ] } }, - ], - Member => - { action_prototypes => - [ { label => 'View', action => sub { - [ '', 'view', [ @{$_[1]->req->captures}, $_[0]->__id ] ] } }, - { label => 'Edit', action => sub { - [ '', 'update', [ @{$_[1]->req->captures}, $_[0]->__id ] ] } }, - { label => 'Delete', action => sub { - [ '', 'delete', [ @{$_[1]->req->captures}, $_[0]->__id ] ] } }, - ], - }, - }; - return $args; +sub _build_default_member_actions { + [ @{shift->next::method(@_)}, qw/update delete/ ]; +} + +sub _build_default_collection_actions { + [ @{shift->next::method(@_)}, qw/create delete_all/ ]; } sub get_model_action { my ($self, $c, $name, $target) = @_; - - if ($target->can('action_for')) { - return $target->action_for($name, ctx => $c); - } - - #can we please kill this already? - my $model_name = "Action::${name}".$self->model_name; - my $model = $c->model($model_name); - confess "no such Model $model_name" unless $model; - return $model->new(target_model => $target, ctx => $c); + return $target->action_for($name, ctx => $c); } sub create :Chained('base') :PathPart('create') :Args(0) { @@ -63,7 +46,7 @@ sub create :Chained('base') :PathPart('create') :Args(0) { sub delete_all :Chained('base') :PathPart('delete_all') :Args(0) { my ($self, $c) = @_; - $self->basic_model_action( $c, { + $self->basic_model_action( $c, { on_close_callback => sub { $self->on_delete_all_close_callback($c => @_) } }); } diff --git a/lib/Reaction/UI/ViewPort/Collection/Grid.pm b/lib/Reaction/UI/ViewPort/Collection/Grid.pm index 95e341e..6d8e0a1 100644 --- a/lib/Reaction/UI/ViewPort/Collection/Grid.pm +++ b/lib/Reaction/UI/ViewPort/Collection/Grid.pm @@ -35,8 +35,7 @@ has member_action_count => ( my $self = shift; for (@{ $self->members }) { my $protos = $_->action_prototypes; - return scalar(@$protos); - #return scalar(keys(%$protos)); + return scalar(keys(%$protos)); } return 1; }, @@ -83,16 +82,16 @@ around _build_members => sub { my $orig = shift; my $self = shift; $self->member_args->{computed_field_order} ||= $self->computed_field_order; -# $self->member_args->{computed_action_order} ||= []; + $self->member_args->{computed_action_order} ||= []; my $members = $self->$orig(@_); # cache everything yo -# for my $member (@$members){ -# $member->clear_computed_action_order; -# my $order = $member->computed_action_order; -# @{ $self->member_args->{computed_action_order} } = @$order; -# last; -# } + for my $member (@$members){ + $member->clear_computed_action_order; + my $order = $member->computed_action_order; + @{ $self->member_args->{computed_action_order} } = @$order; + last; + } return $members; }; diff --git a/lib/Reaction/UI/ViewPort/Role/Actions.pm b/lib/Reaction/UI/ViewPort/Role/Actions.pm index 7da0072..a8e6e28 100644 --- a/lib/Reaction/UI/ViewPort/Role/Actions.pm +++ b/lib/Reaction/UI/ViewPort/Role/Actions.pm @@ -1,33 +1,64 @@ package Reaction::UI::ViewPort::Role::Actions; use Reaction::Role; -use Reaction::UI::ViewPort::Action::Link; +use Reaction::UI::ViewPort::URI; use namespace::clean -except => [ qw(meta) ]; +has actions => ( + is => 'ro', + isa => 'ArrayRef', + lazy_build => 1 +); + +has action_order => ( + is => 'ro', + isa => 'ArrayRef' +); + +has action_prototypes => ( + is => 'ro', + isa => 'HashRef', + required => 1, + default => sub{ {} } +); + +has computed_action_order => ( + is => 'ro', + isa => 'ArrayRef', + lazy_build => 1 +); + +sub _build_computed_action_order { + my $self = shift; + my $ordered = $self->sort_by_spec( + ($self->has_action_order ? $self->action_order : []), + [ keys %{ $self->action_prototypes } ] + ); + return $ordered ; +} -has actions => (is => 'ro', isa => 'ArrayRef', lazy_build => 1); -has action_prototypes => (is => 'ro', isa => 'ArrayRef', lazy_build => 1); -sub _build_action_prototypes { [] }; sub _build_actions { my ($self) = @_; my (@act, $i); my $ctx = $self->ctx; my $loc = $self->location; - foreach my $proto (@{ $self->action_prototypes }) { - my $action = Reaction::UI::ViewPort::Action::Link->new - ( - ctx => $ctx, - target => $self->model, - location => join ('-', $loc, 'action', $i++), - %$proto, - ); + my $target = $self->model; + + foreach my $proto_name ( @{ $self->computed_action_order } ) { + my $proto = $self->action_prototypes->{$proto_name}; + my $uri = $proto->{uri} or confess('uri is required in prototype action'); + my $label = exists $proto->{label} ? $proto->{label} : $proto_name; + + my $action = Reaction::UI::ViewPort::URI->new( + location => join ('-', $loc, 'action', $i++), + uri => ( ref($uri) eq 'CODE' ? $uri->($target, $ctx) : $uri ), + display => ( ref($label) eq 'CODE' ? $label->($target, $ctx) : $label ), + ); push(@act, $action); } return \@act; -}; - - +} 1; |