aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Reaction/UI/ViewPort/Field/ChooseMany.pm
blob: 0ea4ed06f76521f7efc2d50e06f089721f2d0f06 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package Reaction::UI::ViewPort::Field::ChooseMany;

use Reaction::Class;

class ChooseMany is 'Reaction::UI::ViewPort::Field::ChooseOne', which {

  has '+layout' => (default => 'dual_select_group');
  
  has '+value' => (isa => 'ArrayRef');
  
  has available_value_names => 
      (isa => 'ArrayRef', is => 'ro', lazy_build => 1);
  
  has value_names => (isa => 'ArrayRef', is => 'ro', lazy_build => 1);
  
  my $listify = sub {                  # quick utility function, $listify->($arg)
    return (defined($_[0])
             ? (ref($_[0]) eq 'ARRAY'
                 ? $_[0]               # \@arr => \@arr
                 : [$_[0]])            # $scalar => [$scalar]
             : []);                    # undef => []
  };
  
  around value => sub {
    my $orig = shift;
    my $self = shift;
    if (@_) {
      my $value = $listify->(shift);
      if (defined $value) {
	$_ = $self->str_to_ident($_) for @$value;
        my $checked = $self->attribute->check_valid_value($self->action, $value);
        # i.e. fail if any of the values fail
	confess "Not a valid set of values" 
	  if (@$checked < @$value || grep { !defined($_) } @$checked);

        $value = $checked;
      }
      $orig->($self, $value);
    } else {
      $orig->($self);
    }
  };
  
  override build_value => sub {
    return super() || [];
  };
  
  implements is_current_value => as {
    my ($self, $check_value) = @_;
    my @our_values = @{$self->value||[]};
    #$check_value = $check_value->id if ref($check_value);
    #return grep { $_->id eq $check_value } @our_values;
    $check_value = $self->obj_to_str($check_value) if ref($check_value);
    return grep { $self->obj_to_str($_) eq $check_value } @our_values;
  };
  
  implements current_values => as {
    my $self = shift;
    my @all = grep { $self->is_current_value($_) } @{$self->valid_values};
    return [ @all ];
  };
  
  implements available_values => as {
    my $self = shift;
    my @all = grep { !$self->is_current_value($_) } @{$self->valid_values};
    return [ @all ];
  };
  
  implements build_available_value_names => as {
    my $self = shift;
    my @all = @{$self->available_values};
    my $meth = $self->value_map_method;
    my @names = map { $_->$meth } @all;
    return [ sort @names ];
  };
  
  implements build_value_names => as {
    my $self = shift;
    my @all = @{$self->value||[]};
    my $meth = $self->value_map_method;
    my @names = map { $_->$meth } @all;
    return [ sort @names ];
  };
  
  around handle_events => sub {
    my $orig = shift;
    my ($self, $events) = @_;
    my $ev_value = $listify->($events->{value});
    if (delete $events->{add_all_values}) {
      $events->{value} = $self->valid_values;
    } 
    if (delete $events->{do_add_values} && exists $events->{add_values}) {
      my $add = $listify->(delete $events->{add_values});
      $events->{value} = [ @{$ev_value}, @$add ];
    }
    if (delete $events->{remove_all_values}) {
      $events->{value} = [];
    } 
    if (delete $events->{do_remove_values} && exists $events->{remove_values}) {
      my $remove = $listify->(delete $events->{remove_values});
      my %r = map { ($_ => 1) } @$remove;
      $events->{value} = [ grep { !$r{$_} } @{$ev_value} ];
    }
    return $orig->(@_);
  };

};

1;

=head1 NAME

Reaction::UI::ViewPort::Field::ChooseMany

=head1 DESCRIPTION

=head1 METHODS

=head2 is_current_value

=head2 current_values

=head2 available_values

=head2 available_value_names

=head1 SEE ALSO

=head2 L<Reaction::UI::ViewPort::Field>

=head1 AUTHORS

See L<Reaction::Class> for authors.

=head1 LICENSE

See L<Reaction::Class> for the license.

=cut