isa => 'Reaction::InterfaceModel::Action', is => 'ro', required => 1
);
- has field_names => (isa => 'ArrayRef', is => 'rw', lazy_build => 1);
+ has ordered_fields => (is => 'rw', isa => 'ArrayRef', lazy_build => 1);
has _field_map => (
- isa => 'HashRef', is => 'rw', init_arg => 'fields',
- predicate => '_has_field_map', set_or_lazy_build('field_map'),
+ isa => 'HashRef', is => 'rw', init_arg => 'fields', lazy_build => 1,
);
has changed => (
foreach my $attr ($action->parameter_attributes) {
push(@field_map, $self->build_fields_for($attr => $args));
}
-
- my %field_map = @field_map;
- my @field_names = @{ $self->sort_by_spec(
- $args->{column_order}, [keys %field_map] )};
-
- $self->_field_map(\%field_map);
- $self->field_names(\@field_names);
+ $self->_field_map({ @field_map });
}
$self->close_label($self->close_label_close);
};
confess "Lazy field map building not supported by default";
};
+ implements build_ordered_fields => as {
+ my $self = shift;
+ $self->sort_by_spec($self->column_order, [keys %{$self->_field_map_}])};
+ };
+
implements can_apply => as {
my ($self) = @_;
foreach my $field (values %{$self->_field_map}) {
=head2 fields
-=head2 field_names
-
-Returns: Arrayref of field names.
-
=head2 can_apply
=head2 can_close
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'
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 {
+ implements current_value_choices => as {
my $self = shift;
- my @all = grep { $self->is_current_value($_) } @{$self->valid_values};
+ my @all = grep { $self->is_current_value($_->{value}) } @{$self->value_choices};
return [ @all ];
};
- implements available_values => as {
+ implements available_value_choices => as {
my $self = shift;
- my @all = grep { !$self->is_current_value($_) } @{$self->valid_values};
+ my @all = grep { !$self->is_current_value($_->{value}) } @{$self->value_choices};
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}) {
- delete $events->{add_values};
- delete $events->{remove_values};
$events->{value} = [map {$self->obj_to_str($_)} @{$self->valid_values}];
- }
- if (delete $events->{do_add_values} && exists $events->{add_values}) {
+ } elsif (exists $events->{add_values} && delete $events->{do_add_values}) {
my $add = $listify->(delete $events->{add_values});
$events->{value} = [ @{$ev_value}, @$add ];
- }
- if (delete $events->{remove_all_values}) {
- delete $events->{add_values};
- delete $events->{remove_values};
+ } elsif (delete $events->{remove_all_values}) {
$events->{value} = [];
- }
- if (delete $events->{do_remove_values} && exists $events->{remove_values}) {
+ }elsif (exists $events->{remove_values} && delete $events->{do_remove_values}) {
my $remove = $listify->(delete $events->{remove_values});
my %r = map { ($_ => 1) } @$remove;
$events->{value} = [ grep { !$r{$_} } @{$ev_value} ];
has '+layout' => (default => 'select');
- has valid_value_names => (isa => 'ArrayRef', is => 'ro', lazy_build => 1);
-
- has valid_values => (isa => 'ArrayRef', is => 'ro', lazy_build => 1);
-
- has name_to_value_map => (isa => 'HashRef', is => 'ro', lazy_build => 1);
-
- has value_to_name_map => (isa => 'HashRef', is => 'ro', lazy_build => 1);
+ has valid_values => (isa => 'ArrayRef', is => 'ro', lazy_build => 1);
+ has value_choices => (isa => 'ArrayRef', is => 'ro', lazy_build => 1);
has value_map_method => (
isa => 'Str', is => 'ro', required => 1, default => sub { 'display_name' },
return [ $self->attribute->all_valid_values($self->action) ];
};
- implements build_valid_value_names => as {
- my $self = shift;
- my $all = $self->valid_values;
- my $meth = $self->value_map_method;
- my @names = map { $_->$meth } @$all;
- return [ sort @names ];
- };
-
- implements build_name_to_value_map => as {
- my $self = shift;
- my $all = $self->valid_values;
- my $meth = $self->value_map_method;
- my %map;
- $map{$_->$meth} = $self->obj_to_str($_) for @$all;
- return \%map;
- };
-
- implements build_value_to_name_map => as {
- my $self = shift;
- my $all = $self->valid_values;
- my $meth = $self->value_map_method;
- my %map;
- $map{$self->obj_to_str($_)} = $_->$meth for @$all;
- return \%map;
+ implements build_value_choices => sub{
+ my $self = shift;
+ my @pairs = map{{value => $self->obj_to_str($_), name => $self->obj_to_name($_)}}
+ @{ $self->valid_values };
+ return [ sort { $a->{name} cmp $b->{name} } @pairs ];
};
implements is_current_value => as {
return $u->query;
};
+ implements obj_to_name => as {
+ my ($self, $obj) = @_;
+ return $obj unless ref($obj);
+ confess "${obj} not an object" unless blessed($obj);
+ my $meth = $self->value_map_method;
+ return $obj->$meth;
+ };
+
};
1;
isa => 'Reaction::InterfaceModel::Object', is => 'ro', required => 1
);
- has field_names => (isa => 'ArrayRef', is => 'rw', lazy_build => 1);
-
has _field_map => (
isa => 'HashRef', is => 'rw', init_arg => 'fields', lazy_build => 1,
);
has ordered_fields => (is => 'rw', isa => 'ArrayRef', lazy_build => 1);
-
implements fields => as { shift->_field_map };
implements BUILD => as {
push(@field_map, $self->build_fields_for($attr => $args));
}
- my %field_map = @field_map;
- my @field_names = @{ $self->sort_by_spec(
- $args->{column_order}, [keys %field_map] )};
-
- $self->_field_map(\%field_map);
- $self->field_names(\@field_names);
+ $self->_field_map({ @field_map });
}
};
implements build_ordered_fields => as {
my $self = shift;
- [ map{ $self->_field_map->{$_} } $self->field_names ];
+ $self->sort_by_spec($self->column_order, [keys %{$self->_field_map_}])};
};
implements build_simple_field => as {
--- /dev/null
+package Reaction::UI::Widget::ActionForm;
+
+use Reaction::UI::WidgetClass;
+
+class ActionForm, which {
+ widget renders [qw/header fields buttons footer/
+ => { viewport => func('self','viewport') } ];
+
+ fields renders [viewport over func('self','ordered_fields')];
+
+ buttons renders [ string {"DUMMY"} ], {message => func('viewport','message');
+ header renders [ string {"DUMMY"} ];
+ footer renders [ string {"DUMMY"} ];
+
+};
+
+1;
+
+__END__;
+
+=for layout widget
+
+ <form action="" method="post" enctype="multipart/form-data">
+ [% header %]
+ [% fields %]
+ [% buttons %]
+ [% footer %]
+ </form>
+
+=for layout header
+
+<h2>Le Header</h2>
+
+=for layout fields
+
+[% content %] <br />
+
+=for layout buttons
+
+ [% IF message; %]
+ <span>[% message %]</span> <br />
+ [% END; %]
+
+ [% allowed_events = viewport.accept_events; %]
+ [% IF allowed_events.grep('^ok$').size; %]
+ <input type="submit" name="[% viewport.event_id_for('ok') | html%]" value="ok" />
+ [% END; %]
+
+ [% IF (viewport.ordered_fields.size != 0) && allowed_events.grep('^apply$').size; %]
+ <input type="submit" name="[% viewport.event_id_for('apply') | html%]" value="apply" />
+ [% END; %]
+
+ [% IF allowed_events.grep('^close$').size; %]
+ <input type="submit" name="[% viewport.event_id_for('close') | html%]" value="cancel" />
+ [% END; %]
+ <br />
+
+=for layout footer
+
+ <h2>Le Footer</h2>
+
+=cut
=for layout field
+[%
+ IF content;
+ checked = 'checked="checked"';
+ ELSE;
+ checked = "";
+ END;
+%]
+
<!-- We need a replacement for process_attrs -->
-<input type="checkbox" name="[% name %]" id="[% id %]" />
- [% content | html %]
-</textarea>
+<input type="checkbox" id="[% id | html %]" name="[% name | html %]" value="1" [% checked %] />
=for layout label
class ChooseMany is 'Reaction::UI::Widget::Field', which {
+ field renders [qw/available_values action_buttons selected_values current_values/];
+
+ current_values renders [ hidden_value over func('viewport', 'current_value_choices') ];
+ hidden_value renders [ string { $_->{value} } ];
+
+ available_values renders [ option over func('viewport', 'available_value_choices') ];
+ selected_values renders [ option over func('viewport', 'current_value_choices') ];
+ option renders [string {"DUMMY"}], { v_value => sub {$_->{value}}, v_name => sub {$_->{name}} };
+
};
1;
=for layout widget
-[% label %] [% field %] [% message %] <br>
+[% label %]
+<br />
+[% message %]
+[% field %]
=for layout field
-TODO
+<table>
+ <tr>
+ <td> [% available_values %] </td>
+ <td> [% action_buttons %] </td>
+ <td>
+ [% selected_values %]
+ [% current_values %]
+ </td>
+ </tr>
+</table>
+
+=for layout available_values
+
+<select size="10" multiple="multiple" name="[% viewport.event_id_for('add_values') | html %]">
+ [% content %]
+</select>
+
+=for layout selected_values
+
+<select size="10" multiple="multiple" name="[% viewport.event_id_for('remove_values') | html %]">
+ [% content %]
+</select>
+
+=for layout current_values
+
+[% content %]
+
+=for layout hidden_value
+
+<input type="hidden" name="[% viewport.event_id_for('value') | html %]" value="[% content | html %]">
+
+=for layout option
+
+<option value="[% v_value | html %]">[% v_name | html %]</option>
+
+=for layout action_buttons
+
+<input type="submit" value=">>" name="[% viewport.event_id_for('add_all_values') | html %]" />
+<input type="submit" value=">" name="[% viewport.event_id_for('do_add_values') | html %]" /> <br />
+<input type="submit" value="<" name="[% viewport.event_id_for('do_remove_values') | html %]" /> <br />
+<input type="submit" value="<<" name="[% viewport.event_id_for('remove_all_values') | html %]" /> <br />
=for layout label
<!-- This conditional goes away when mst comes up with something better -->
[% IF content %]
- <label for="[% id %]"> [% content | html %]: </label>
+ <label> [% content | html %]: </label>
[% END %]
=for layout message
<!-- This conditional goes away when mst comes up with something better -->
[% IF content %]
- <span> [% content | html %] </span>
+ <span> [% content | html %] </span> <br />
[% END %]
=cut
class ChooseOne is 'Reaction::UI::Widget::Field', which {
- field renders [ option over func('viewport', 'values_list') ,
- {name_map => func('viewport', 'value_to_name_map') }
- ],
- { is_required => sub{ $_{viewport}->attribute->required } };
-
- option renders
- [
- { v_value => sub { $_{viewport}->obj_to_str($_) },
- v_name => sub { $_{name_map}->{ $_{viewport}->obj_to_str($_) } },
- is_selected => sub { my $v_value = $_{viewport}->obj_to_str($_);
- $_{viewport}->is_current_value($v_value) ||
- $_{viewport}->value eq $v_value;
- }
- }
- ];
+ field renders [ option over func('viewport', 'value_choices') ],
+ { is_required => sub{ $_{viewport}->attribute->required } };
+
+ option renders [string {"DUMMY"}],
+ {
+ v_value => sub { $_->{value} },
+ v_name => sub { $_->{name} },
+ is_selected => sub { $_{viewport}->is_current_value($_->{value}) },
+ };
};
=for layout widget
-[% label %] [% field %] [% message %] <br>
+[% label %] [% field %] [% message %]
=for layout field
<!-- We need a replacement for process_attrs -->
-<select name="[% name %]" id="[% id %]">
+<select name="[% name | html %]" id="[% id | html %]">
[% IF is_required %]
- <option value="">--</option>
+ <option value="">--</option>
+ [% END %]
[% content %]
</select>
<!-- This conditional goes away when mst comes up with something better -->
[% IF content %]
- <label for="[% id %]"> [% content | html %]: </label>
+ <label for="[% id | html %]"> [% content | html %]: </label>
[% END %]
=for layout message
=for layout widget
-[% label %] [% field %] [% message %] <br>
+[% label %] [% field %] [% message %]
=for layout field
<!-- We need a replacement for process_attrs -->
-<input type="text" name="[% name %]" id="[% id %]" value="[% content | html %]" />
+<input type="text" name="[% name | html %]" id="[% id | html%]" value="[% content | html %]" />
=for layout label
<!-- This conditional goes away when mst comes up with something better -->
[% IF content %]
- <label for="[% id %]"> [% content | html %]: </label>
+ <label for="[% id | html %]"> [% content | html %]: </label>
[% END %]
=for layout message
=for layout widget
-[% label %] [% field %] [% message %] <br>
+[% label %] [% field %] [% message %]
=for layout field
-TODO
+<input type="file" name="[% name | html%]" id="[% id | html %]" />
=for layout label
<!-- This conditional goes away when mst comes up with something better -->
[% IF content %]
- <label for="[% id %]"> [% content | html %]: </label>
+ <label for="[% id | html %]"> [% content | html %]: </label>
[% END %]
=for layout message
class HiddenArray is 'Reaction::UI::Widget::Field', which {
+ field renders [ item over func('viewport', 'value') ];
+ item renders [ string { $_ } ];
+
};
1;
=for layout widget
-[% label %] [% field %] [% message %] <br>
+[% field %]
=for layout field
-TODO
+[% item %]
-=for layout label
+=for layout item
-<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <label for="[% id %]"> [% content | html %]: </label>
-[% END %]
+<input type="hidden" name="[% name | html %]" value="[% content | html %]" />
-=for layout message
+=for layout label
-<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <span> [% content | html %] </span>
-[% END %]
+=for layout message
=cut
=for layout widget
-[% label %] [% field %] [% message %] <br>
+[% label %] [% field %] [% message %]
=for layout field
<!-- We need a replacement for process_attrs -->
-<input type="text" name="[% name %]" id="[% id %]" value="[% content | html %]" />
+<input type="text" name="[% name | html%]" id="[% id | html %]" value="[% content | html %]" />
=for layout label
<!-- This conditional goes away when mst comes up with something better -->
[% IF content %]
- <label for="[% id %]"> [% content | html %]: </label>
+ <label for="[% id | html %]"> [% content | html %]: </label>
[% END %]
=for layout message
=for layout widget
-[% label %] [% field %] [% message %] <br>
+[% label %] [% field %] [% message %]
=for layout field
<!-- We need a replacement for process_attrs -->
-<input type="password" name="[% name %]" id="[% id %]" value="[% content | html %]" />
+<input type="password" name="[% name | html %]" id="[% id | html %]" value="[% content | html %]" />
=for layout label
<!-- This conditional goes away when mst comes up with something better -->
[% IF content %]
- <label for="[% id %]"> [% content | html %]: </label>
+ <label for="[% id | html %]"> [% content | html %]: </label>
[% END %]
=for layout message
=for layout widget
-[% label %] [% field %] [% message %] <br>
+[% label %] [% field %] [% message %]
=for layout field
<!-- We need a replacement for process_attrs -->
-<input type="text" name="[% name %]" id="[% id %]" value="[% content | html %]" />
+<input type="text" name="[% name | html %]" id="[% id | html %]" value="[% content | html %]" />
=for layout label
<!-- This conditional goes away when mst comes up with something better -->
[% IF content %]
- <label for="[% id %]"> [% content | html %]: </label>
+ <label for="[% id | html %]"> [% content | html %]: </label>
[% END %]
=for layout message
=for layout widget
-[% label %] [% field %] [% message %] <br>
+[% label %] [% field %] [% message %]
=for layout field
<!-- We need a replacement for process_attrs -->
-<textarea name="[% name %]" id="[% id %]">
+<textarea name="[% name | html %]" id="[% id | html %]">
[% content | html %]
</textarea>
<!-- This conditional goes away when mst comes up with something better -->
[% IF content %]
- <label for="[% id %]"> [% content | html %]: </label>
+ <label for="[% id | html %]"> [% content | html %]: </label>
[% END %]
=for layout message
=for layout widget
-[% label %] [% field %] [% message %] <br>
+[% label %] [% field %] [% message %]
=for layout field
<!-- This conditional goes away when mst comes up with something better -->
[% IF content %]
- <label for="[% id %]"> [% content | html %]: </label>
+ <label for="[% id | html %]"> [% content | html %]: </label>
[% END %]
=for layout message