X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FReaction%2FUI%2FViewPort%2FAction.pm;h=6a2ac58ffe685db2c22397a5961bbcdce4a9ed45;hb=f10fd4d2b52f757f758501448ade779036e16b19;hp=46ab85c6da74605f8f8606b7a2d6cc51b9b7112c;hpb=5976ddc40b95fb45edc007e8bb67d0db58d3bb2e;p=catagits%2FReaction.git diff --git a/lib/Reaction/UI/ViewPort/Action.pm b/lib/Reaction/UI/ViewPort/Action.pm index 46ab85c..6a2ac58 100644 --- a/lib/Reaction/UI/ViewPort/Action.pm +++ b/lib/Reaction/UI/ViewPort/Action.pm @@ -2,273 +2,109 @@ package Reaction::UI::ViewPort::Action; use Reaction::Class; -use aliased 'Reaction::UI::ViewPort::Field::Mutable::Text'; -use aliased 'Reaction::UI::ViewPort::Field::Mutable::Array'; -use aliased 'Reaction::UI::ViewPort::Field::Mutable::String'; -use aliased 'Reaction::UI::ViewPort::Field::Mutable::Number'; -use aliased 'Reaction::UI::ViewPort::Field::Mutable::Integer'; -use aliased 'Reaction::UI::ViewPort::Field::Mutable::Boolean'; -use aliased 'Reaction::UI::ViewPort::Field::Mutable::Password'; -use aliased 'Reaction::UI::ViewPort::Field::Mutable::DateTime'; -use aliased 'Reaction::UI::ViewPort::Field::Mutable::ChooseOne'; -use aliased 'Reaction::UI::ViewPort::Field::Mutable::ChooseMany'; - -#use aliased 'Reaction::UI::ViewPort::InterfaceModel::Field::Mutable::File'; -#use aliased 'Reaction::UI::ViewPort::InterfaceModel::Field::Mutable::TimeRange'; - -class Action is 'Reaction::UI::ViewPort::Object', which { - has model => (is => 'ro', isa => 'Reaction::InterfaceModel::Action', required => 1); - #has '+model' => (isa => 'Reaction::InterfaceModel::Action'); - - has next_action => (is => 'rw', isa => 'ArrayRef'); - has on_apply_callback => (is => 'rw', isa => 'CodeRef'); - - has ok_label => (is => 'rw', isa => 'Str', lazy_build => 1); - has apply_label => (is => 'rw', isa => 'Str', lazy_build => 1); - has close_label => (is => 'rw', isa => 'Str', lazy_fail => 1); - has close_label_close => (is => 'rw', isa => 'Str', lazy_build => 1); - has close_label_cancel => (is => 'rw', isa => 'Str', lazy_build => 1); - - has changed => (is => 'rw', isa => 'Int', reader => 'is_changed', default => sub{0}); - - implements BUILD => as{ - my $self = shift; - $self->close_label($self->close_label_close); - }; - - implements _build_ok_label => as{ 'ok' }; - implements _build_apply_label => as{ 'apply' }; - implements _build_close_label_close => as{ 'close' }; - implements _build_close_label_cancel => as{ 'cancel' }; - - implements can_apply => as { - my ($self) = @_; - foreach my $field ( @{ $self->fields } ) { - return 0 if $field->needs_sync; - # if e.g. a datetime field has an invalid value that can't be re-assembled - # into a datetime object, the action may be in a consistent state but - # not synchronized from the fields; in this case, we must not apply - } - return $self->model->can_apply; - }; - - implements do_apply => as { - shift->model->do_apply; - }; - - implements ok => as { - my $self = shift; - $self->close(@_) if $self->apply(@_); - }; - - implements apply => as { - my $self = shift; - if ($self->can_apply && (my $result = $self->do_apply)) { - $self->changed(0); - $self->close_label($self->close_label_close); - $self->on_apply_callback->($self => $result) if $self->has_on_apply_callback; - return 1; - } else { - $self->changed(1); - $self->close_label($self->close_label_cancel); - return 0; - } - }; - - implements close => as { - my $self = shift; - my ($controller, $name, @args) = @{$self->next_action}; - $controller->pop_viewport; - $controller->$name($self->ctx, @args); - }; - - implements can_close => as { 1 }; - - override accept_events => sub { - (($_[0]->has_next_action ? ('ok', 'close') : ()), 'apply', super()); - }; # can't do a close-type operation if there's nowhere to go afterwards - - after apply_child_events => sub { - # interrupt here because fields will have been updated - my ($self) = @_; - $self->sync_action_from_fields; - }; - - implements sync_action_from_fields => as { - my ($self) = @_; - foreach my $field (@{$self->fields}) { - $field->sync_to_action; # get the field to populate the $action if possible - } - $self->model->sync_all; - foreach my $field (@{$self->fields}) { - $field->sync_from_action; # get errors from $action if applicable - } - }; - - - implements _build_fields_for_type_Num => as { - my ($self, $attr, $args) = @_; - $self->_build_simple_field(attribute => $attr, class => Number, %$args); - }; - - implements _build_fields_for_type_Int => as { - my ($self, $attr, $args) = @_; - $self->_build_simple_field(attribute => $attr, class => Integer, %$args); - }; - - implements _build_fields_for_type_Bool => as { - my ($self, $attr, $args) = @_; - $self->_build_simple_field(attribute => $attr, class => Boolean, %$args); - }; - - implements _build_fields_for_type_SimpleStr => as { - my ($self, $attr, $args) = @_; - $self->_build_simple_field(attribute => $attr, class => String, %$args); - }; - - #implements _build_fields_for_type_File => as { - # my ($self, $attr, $args) = @_; - # $self->_build_simple_field(attribute => $attr, class => File, %$args); - #}; - - implements _build_fields_for_type_Str => as { - my ($self, $attr, $args) = @_; - if ($attr->has_valid_values) { # There's probably a better way to do this - $self->_build_simple_field(attribute => $attr, class => ChooseOne, %$args); - } else { - $self->_build_simple_field(attribute => $attr, class => Text, %$args); - } - }; - - implements _build_fields_for_type_Password => as { - my ($self, $attr, $args) = @_; - $self->_build_simple_field(attribute => $attr, class => Password, %$args); - }; - - implements _build_fields_for_type_DateTime => as { - my ($self, $attr, $args) = @_; - $self->_build_simple_field(attribute => $attr, class => DateTime, %$args); - }; - - implements _build_fields_for_type_Enum => as { - my ($self, $attr, $args) = @_; - $self->_build_simple_field(attribute => $attr, class => ChooseOne, %$args); - }; - - #this needs to be fixed. somehow. beats the shit our of me. really. - #implements build_fields_for_type_Reaction_InterfaceModel_Object => as { - implements _build_fields_for_type_DBIx_Class_Row => as { - my ($self, $attr, $args) = @_; - $self->_build_simple_field(attribute => $attr, class => ChooseOne, %$args); - }; - - implements _build_fields_for_type_ArrayRef => as { - my ($self, $attr, $args) = @_; - if ($attr->has_valid_values) { - $self->_build_simple_field(attribute => $attr, class => ChooseMany, %$args); - } else { - $self->_build_simple_field - ( - attribute => $attr, - class => Array, - layout => 'interface_model/field/mutable/array/hidden', - %$args); - } - }; - - #implements _build_fields_for_type_DateTime_Spanset => as { - # my ($self, $attr, $args) = @_; - # $self->_build_simple_field(attribute => $attr, class => TimeRange, %$args); - #}; - +use MooseX::Types::Moose qw/Int/; +use Reaction::Types::Core qw/NonEmptySimpleStr/; + +use namespace::clean -except => [ qw(meta) ]; + +extends 'Reaction::UI::ViewPort::Object::Mutable'; +with 'Reaction::UI::ViewPort::Action::Role::OK'; + +#this has to fucking go. it BLOWS. +has method => ( + is => 'rw', + isa => NonEmptySimpleStr, + default => sub { 'post' } +); + +has changed => ( + is => 'rw', + isa => Int, + reader => 'is_changed', + default => sub{0} +); + +sub can_apply { + my ($self) = @_; + foreach my $field ( @{ $self->fields } ) { + return 0 if $field->needs_sync; + # if e.g. a datetime field has an invalid value that can't be re-assembled + # into a datetime object, the action may be in a consistent state but + # not synchronized from the fields; in this case, we must not apply + } + return $self->model->can_apply; +} + +sub do_apply { + shift->model->do_apply; +} + +after apply_child_events => sub { + # interrupt here because fields will have been updated + my ($self) = @_; + $self->sync_action_from_fields; }; - 1; - -=head1 NAME - -Reaction::UI::ViewPort::InterfaceModel::Action - -=head1 SYNOPSIS - - use aliased 'Reaction::UI::ViewPort::Action'; - - $self->push_viewport(Action, - layout => 'register', - model => $action, - next_action => [ $self, 'redirect_to', 'accounts', $c->req->captures ], - ctx => $c, - field_order => [ - qw / contact_title company_name email address1 address2 address3 - city country post_code telephone mobile fax/ ], - ); +sub sync_action_from_fields { + my ($self) = @_; + foreach my $field (@{$self->fields}) { + $field->sync_to_action; # get the field to populate the $action if possible + } + $self->model->sync_all; + foreach my $field (@{$self->fields}) { + $field->sync_from_action; # get errors from $action if applicable + } +} -=head1 DESCRIPTION - -This subclass of L is used for rendering a -collection of C objects for user editing. - -=head1 ATTRIBUTES -=head2 model +__PACKAGE__->meta->make_immutable; -L +1; -=head2 ok_label +__END__; -Default: 'ok' - -=head2 apply_label - -Default: 'apply' - -=head2 close_label_close +=head1 NAME -Default: 'close' +Reaction::UI::ViewPort::Action -=head2 close_label_cancel +=head1 SYNOPSIS -This label is only shown when C is true. +=head1 DESCRIPTION -Default: 'cancel' +This subclass of L is used for +rendering a complete form supporting Apply, Close and OK. -=head2 fields +=head1 ATTRIBUTES -=head2 can_apply +=head2 method -=head2 can_close +post / get =head2 changed Returns true if a field has been edited. -=head2 next_action - -=head2 on_apply_callback - -CodeRef. - =head1 METHODS -=head2 ok +=head2 can_apply -Calls C, and then C if successful. +=head2 do_apply -=head2 close +=head2 sync_action_from_fields -Pop viewport and proceed to C. +=head1 SEE ALSO -=head2 apply +L -Attempt to save changes and update C attribute if required. +L -=head1 SEE ALSO +L -L +L -L +L -L +L =head1 AUTHORS @@ -279,3 +115,4 @@ See L for authors. See L for the license. =cut +