more Widget updates. this breaks old-style templates, also changed how VPs behave...
groditi [Wed, 26 Sep 2007 22:39:13 +0000 (22:39 +0000)]
16 files changed:
lib/Reaction/UI/ViewPort/ActionForm.pm
lib/Reaction/UI/ViewPort/Field/ChooseMany.pm
lib/Reaction/UI/ViewPort/Field/ChooseOne.pm
lib/Reaction/UI/ViewPort/ObjectView.pm
lib/Reaction/UI/Widget/ActionForm.pm [new file with mode: 0644]
lib/Reaction/UI/Widget/Field/Boolean.pm
lib/Reaction/UI/Widget/Field/ChooseMany.pm
lib/Reaction/UI/Widget/Field/ChooseOne.pm
lib/Reaction/UI/Widget/Field/DateTime.pm
lib/Reaction/UI/Widget/Field/File.pm
lib/Reaction/UI/Widget/Field/HiddenArray.pm
lib/Reaction/UI/Widget/Field/Number.pm
lib/Reaction/UI/Widget/Field/Password.pm
lib/Reaction/UI/Widget/Field/String.pm
lib/Reaction/UI/Widget/Field/Text.pm
lib/Reaction/UI/Widget/Field/TimeRange.pm

index 713357e..bb97bf3 100644 (file)
@@ -19,11 +19,10 @@ class ActionForm is 'Reaction::UI::ViewPort', which {
     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 => (
@@ -67,13 +66,7 @@ class ActionForm is 'Reaction::UI::ViewPort', which {
       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);
   };
@@ -130,6 +123,11 @@ class ActionForm is 'Reaction::UI::ViewPort', which {
     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}) {
@@ -350,10 +348,6 @@ Default: 'cancel'
 
 =head2 fields
 
-=head2 field_names
-
-Returns: Arrayref of field names.
-
 =head2 can_apply
 
 =head2 can_close
index f4f004c..35f6710 100644 (file)
@@ -5,14 +5,8 @@ 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'
@@ -48,59 +42,34 @@ class ChooseMany is 'Reaction::UI::ViewPort::Field::ChooseOne', which {
   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} ];
index 73d197a..0d44fd7 100644 (file)
@@ -8,13 +8,8 @@ class ChooseOne is 'Reaction::UI::ViewPort::Field', which {
 
   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' },
@@ -44,30 +39,11 @@ class ChooseOne is 'Reaction::UI::ViewPort::Field', which {
     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 {
@@ -95,6 +71,14 @@ class ChooseOne is 'Reaction::UI::ViewPort::Field', which {
     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;
index 6aa21b1..cbb4c7b 100644 (file)
@@ -16,8 +16,6 @@ class ObjectView is 'Reaction::UI::ViewPort', which {
     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,
   );
@@ -27,7 +25,6 @@ class ObjectView is 'Reaction::UI::ViewPort', which {
 
   has ordered_fields => (is => 'rw', isa => 'ArrayRef', lazy_build => 1);
 
-
   implements fields => as { shift->_field_map };
 
   implements BUILD => as {
@@ -40,12 +37,7 @@ class ObjectView is 'Reaction::UI::ViewPort', which {
         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 });
     }
   };
 
@@ -102,7 +94,7 @@ class ObjectView is 'Reaction::UI::ViewPort', which {
 
   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 {
diff --git a/lib/Reaction/UI/Widget/ActionForm.pm b/lib/Reaction/UI/Widget/ActionForm.pm
new file mode 100644 (file)
index 0000000..484453c
--- /dev/null
@@ -0,0 +1,62 @@
+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
index 764b7e0..c6afaff 100644 (file)
@@ -14,10 +14,16 @@ class Boolean is 'Reaction::UI::Widget::Field', which {
 
 =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
 
index 9cfa1f3..6d10b3f 100644 (file)
@@ -4,6 +4,15 @@ use Reaction::UI::WidgetClass;
 
 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;
@@ -11,24 +20,67 @@ class ChooseMany is 'Reaction::UI::Widget::Field', which {
 
 =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="&gt;&gt;" name="[% viewport.event_id_for('add_all_values') | html %]" />
+<input type="submit" value="&gt;" name="[% viewport.event_id_for('do_add_values') | html %]" /> <br />
+<input type="submit" value="&lt;" name="[% viewport.event_id_for('do_remove_values') | html %]" /> <br />
+<input type="submit" value="&lt;&lt;" 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
index 3a79ea9..3422261 100644 (file)
@@ -4,21 +4,15 @@ use Reaction::UI::WidgetClass;
 
 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}) },
+    };
 
 };
 
@@ -26,14 +20,15 @@ class ChooseOne is 'Reaction::UI::Widget::Field', which {
 
 =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>
 
@@ -52,7 +47,7 @@ class ChooseOne is 'Reaction::UI::Widget::Field', which {
 
 <!-- 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
index 024c793..f328cd7 100644 (file)
@@ -12,18 +12,18 @@ class DateTime is 'Reaction::UI::Widget::Field', which {
 
 =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
index 0e4d375..b0c11cc 100644 (file)
@@ -11,17 +11,17 @@ class File is 'Reaction::UI::Widget::Field', which {
 
 =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
index 54004de..010e458 100644 (file)
@@ -4,6 +4,9 @@ use Reaction::UI::WidgetClass;
 
 class HiddenArray is 'Reaction::UI::Widget::Field', which {
 
+  field renders [ item over func('viewport', 'value') ];
+  item  renders [ string { $_ } ];
+
 };
 
 1;
@@ -11,24 +14,18 @@ class HiddenArray is 'Reaction::UI::Widget::Field', which {
 
 =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
index a2a24c3..2cd371f 100644 (file)
@@ -10,18 +10,18 @@ class Number is 'Reaction::UI::Widget::Field', which {
 
 =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
index f08fb77..1b794e0 100644 (file)
@@ -10,18 +10,18 @@ class Password is 'Reaction::UI::Widget::Field', which {
 
 =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
index 99247bc..f2380dd 100644 (file)
@@ -10,18 +10,18 @@ class String is 'Reaction::UI::Widget::Field', which {
 
 =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
index f58cf16..9bc152c 100644 (file)
@@ -10,12 +10,12 @@ class Text is 'Reaction::UI::Widget::Field', which {
 
 =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>
 
@@ -23,7 +23,7 @@ class Text is 'Reaction::UI::Widget::Field', which {
 
 <!-- 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
index 6961b6d..a23e951 100644 (file)
@@ -11,7 +11,7 @@ class TimeRange is 'Reaction::UI::Widget::Field', which {
 
 =for layout widget
 
-[% label %] [% field %] [% message %] <br>
+[% label %] [% field %] [% message %]
 
 =for layout field
 
@@ -21,7 +21,7 @@ TODO
 
 <!-- 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