completely new way of handling action prototypes for actions in CRUD that is much...
groditi [Sat, 11 Oct 2008 21:15:47 +0000 (21:15 +0000)]
lib/ComponentUI/Controller/TestModel/Foo.pm
lib/Reaction/UI/Controller/Collection.pm
lib/Reaction/UI/Controller/Collection/CRUD.pm
lib/Reaction/UI/ViewPort/Collection/Grid.pm
lib/Reaction/UI/ViewPort/Role/Actions.pm

index b5dfe5b..e8e2318 100644 (file)
@@ -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;
index e0328fe..204edd9 100644 (file)
@@ -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
index 285947b..7552077 100644 (file)
@@ -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 => @_) }
   });
 }
index 95e341e..6d8e0a1 100644 (file)
@@ -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;
 };
index 7da0072..a8e6e28 100644 (file)
@@ -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;