argh! missed DEBUG_EVENTS
[catagits/Reaction.git] / lib / Reaction / UI / ViewPort / Action.pm
CommitLineData
ddccc6a2 1package Reaction::UI::ViewPort::Action;
2
3use Reaction::Class;
4
7b5e71ad 5use MooseX::Types::URI qw/Uri/;
e29819c4 6use MooseX::Types::Moose qw/Int Str/;
7b5e71ad 7use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
08451970 8
9use namespace::clean -except => [ qw(meta) ];
b343a983 10
11extends 'Reaction::UI::ViewPort::Object::Mutable';
08451970 12with 'Reaction::UI::ViewPort::Action::Role::OK';
13
29c740ee 14sub DEBUG_EVENTS () { $ENV{REACTION_UI_VIEWPORT_DEBUG_EVENTS} }
15
e29819c4 16has message => (is => 'rw', isa => Str);
eb52e595 17has '+model' => (handles => [qw/error_message has_error_message/]);
e29819c4 18
b343a983 19#this has to fucking go. it BLOWS.
20has method => (
21 is => 'rw',
22 isa => NonEmptySimpleStr,
23 default => sub { 'post' }
24);
08451970 25
7b5e71ad 26has action => ( is => 'rw', isa => Uri );
27
08451970 28has changed => (
29 is => 'rw',
30 isa => Int,
31 reader => 'is_changed',
32 default => sub{0}
b343a983 33);
08451970 34
35sub can_apply {
36 my ($self) = @_;
37 foreach my $field ( @{ $self->fields } ) {
38 return 0 if $field->needs_sync;
39 # if e.g. a datetime field has an invalid value that can't be re-assembled
40 # into a datetime object, the action may be in a consistent state but
41 # not synchronized from the fields; in this case, we must not apply
42 }
43 return $self->model->can_apply;
44}
45
46sub do_apply {
47 shift->model->do_apply;
48}
49
50after apply_child_events => sub {
51 # interrupt here because fields will have been updated
52 my ($self) = @_;
53 $self->sync_action_from_fields;
54};
55
56sub sync_action_from_fields {
57 my ($self) = @_;
58 foreach my $field (@{$self->fields}) {
59 $field->sync_to_action; # get the field to populate the $action if possible
60 }
61 $self->model->sync_all;
62 foreach my $field (@{$self->fields}) {
63 $field->sync_from_action; # get errors from $action if applicable
64 }
65}
66
5aec9cb9 67after handle_events => sub {
68 my ($self, $events) = @_;
69 foreach my $event ($self->accept_events) {
70 unless (exists $events->{$event} ) {
71 # for <input type="image"... buttons
72 if ( exists $events->{"${event}.x"} && exists $events->{"${event}.y"} ) {
1ca3c638 73 $self->_dump_event($event, $events->{$event}) if DEBUG_EVENTS;
5aec9cb9 74 $self->$event($events->{$event});
75 }
76 }
77 }
78};
81393881 79
80__PACKAGE__->meta->make_immutable;
81
114916fc 821;
ddccc6a2 83
114916fc 84__END__;
ddccc6a2 85
08451970 86=head1 NAME
87
63bb30b4 88Reaction::UI::ViewPort::Action - Provide user with a form with OK, Apply and Close.
08451970 89
90=head1 SYNOPSIS
91
63bb30b4 92 $controller->push_viewport('Reaction::UI::ViewPort::Action',
93 model => $interface_model_action,
94 field_order => [qw( firstname lastname )],
95 excluded_fields => [qw( password )],
96 );
97
08451970 98=head1 DESCRIPTION
99
599c1172 100This subclass of L<Reaction::UI::ViewPort::Object::Mutable> is used for
101rendering a complete form supporting Apply, Close and OK.
08451970 102
103=head1 ATTRIBUTES
104
63bb30b4 105=head2 message
106
107=head2 model
108
109Inherited from L<Reaction::UI::ViewPort::Object::Mutable>. Must be a
110L<Reaction::InterfaceModel::Action>.
111
112Also handles C<error_message> and C<has_error_message> methods.
113
599c1172 114=head2 method
08451970 115
599c1172 116post / get
08451970 117
118=head2 changed
119
120Returns true if a field has been edited.
121
08451970 122=head1 METHODS
123
599c1172 124=head2 can_apply
08451970 125
63bb30b4 126Returns true if no field C<needs_sync> and the L</model> C<can_apply>.
127
599c1172 128=head2 do_apply
08451970 129
63bb30b4 130Delegates to C<do_apply> on the L</model>, which is a
131L<Reaction::InterfaceModel::Action>.
132
599c1172 133=head2 sync_action_from_fields
08451970 134
63bb30b4 135Firstly calls C<sync_to_action> on every L<Reaction::UI::ViewPort::Field::Mutable>
136in L<fields|Reaction::UI::ViewPort::Object/fields>. Then it calls C<sync_all> on
137the L<Reaction::InterfaceModel::Action> in L</model>. Next it will call
138C<sync_from_action> on every field to repopulate them from the L</model>.
139
140=head1 SUBCLASSING
141
142 package MyApp::UI::ViewPort::Action;
143 use Reaction::Class;
144 use MooseX::Types::Moose qw( Int );
145
146 use namespace::clean -except => 'meta';
147
148 extends 'Reaction::UI::ViewPort::Action';
149
150 has render_timestamp => (
151 is => 'ro',
152 isa => Int,
153 default => sub { time },
154 required => 1,
155 );
156
157 has '+field_order' => (default => sub {[qw( firstname lastname )]});
158
159 1;
160
599c1172 161=head1 SEE ALSO
08451970 162
599c1172 163L<Reaction::UI::ViewPort>
08451970 164
599c1172 165L<Reaction::UI::ViewPort::Object>
08451970 166
599c1172 167L<Reaction::UI::ViewPort::Object::Mutable>
08451970 168
599c1172 169L<Reaction::InterfaceModel::Action::Role::Apply>
08451970 170
599c1172 171L<Reaction::InterfaceModel::Action::Role::Close>
08451970 172
599c1172 173L<Reaction::InterfaceModel::Action::Role::OK>
08451970 174
175=head1 AUTHORS
176
177See L<Reaction::Class> for authors.
178
179=head1 LICENSE
180
181See L<Reaction::Class> for the license.
182
183=cut
184