diff options
31 files changed, 168 insertions, 70 deletions
diff --git a/Makefile.PL b/Makefile.PL index 705461c..da2cb84 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -46,11 +46,12 @@ requires 'namespace::clean' => '0.11'; requires 'metaclass' => '0.81'; requires 'Method::Signatures::Simple' => '0.03'; requires 'signatures' => '0.05'; +requires 'MooseX::Role::Parameterized' => '0.13'; test_requires 'Test::Class' => '0.31'; test_requires 'Test::WWW::Mechanize::Catalyst' => '0.51'; test_requires 'Test::Memory::Cycle' => '1.04'; -test_requires 'SQL::Translator' => '0.09004'; +test_requires 'SQL::Translator' => '0.11002'; install_share; diff --git a/lib/ComponentUI/Controller/TestModel/Foo.pm b/lib/ComponentUI/Controller/TestModel/Foo.pm index 2fb994c..d636c6c 100644 --- a/lib/ComponentUI/Controller/TestModel/Foo.pm +++ b/lib/ComponentUI/Controller/TestModel/Foo.pm @@ -3,6 +3,10 @@ package ComponentUI::Controller::TestModel::Foo; use base 'Reaction::UI::Controller::Collection::CRUD'; use Reaction::Class; +use aliased 'Reaction::UI::ViewPort::SearchableListViewContainer'; +use aliased 'ComponentUI::TestModel::Foo::SearchSpec'; +use aliased 'ComponentUI::TestModel::Foo::Action::SearchSpec::Update'; + __PACKAGE__->config( model_name => 'TestModel', collection_name => 'Foo', @@ -49,11 +53,19 @@ for my $action (qw/view create update/){ ); } -# sub _build_action_viewport_args { -# my $self = shift; -# my $args = $self->next::method(@_); -# # $args->{list}{action_prototypes}{delete_all}{label} = 'Delete All Records'; -# return $args; -# } +override _build_action_viewport_map => sub { + my $map = super(); + $map->{list} = SearchableListViewContainer; + $map; +}; + +sub _build_action_viewport_args { + my $self = shift; + my $args = $self->next::method(@_); + $args->{list}{action_prototypes}{delete_all}{label} = 'Delete All Records'; + $args->{list}{spec_class} = SearchSpec; + $args->{list}{action_class} = Update; + return $args; +} 1; diff --git a/lib/ComponentUI/TestModel/Foo/Action/SearchSpec/Update.pm b/lib/ComponentUI/TestModel/Foo/Action/SearchSpec/Update.pm new file mode 100644 index 0000000..97d2feb --- /dev/null +++ b/lib/ComponentUI/TestModel/Foo/Action/SearchSpec/Update.pm @@ -0,0 +1,15 @@ +package ComponentUI::TestModel::Foo::Action::SearchSpec::Update; +use Reaction::Class; +use namespace::autoclean; + +use MooseX::Types::Common::String qw/NonEmptySimpleStr/; + +extends 'Reaction::InterfaceModel::Action'; +with 'Reaction::InterfaceModel::Search::UpdateSpec'; + +has 'first_name' => (isa => NonEmptySimpleStr, is => 'rw', required => 0); +has 'last_name' => (isa => NonEmptySimpleStr, is => 'rw', required => 0); + +sub _reflection_info {{ normal => [qw/first_name last_name/] }} + +1; diff --git a/lib/ComponentUI/TestModel/Foo/SearchSpec.pm b/lib/ComponentUI/TestModel/Foo/SearchSpec.pm new file mode 100644 index 0000000..4664ec6 --- /dev/null +++ b/lib/ComponentUI/TestModel/Foo/SearchSpec.pm @@ -0,0 +1,24 @@ +package ComponentUI::TestModel::Foo::SearchSpec; +use Reaction::Class; +use namespace::autoclean; + +use MooseX::Types::Common::String qw/NonEmptySimpleStr/; + +with 'Reaction::InterfaceModel::Search::Spec'; + +has 'first_name' => (isa => NonEmptySimpleStr, is => 'rw', required => 0); +has 'last_name' => (isa => NonEmptySimpleStr, is => 'rw', required => 0); + +sub _build__search_spec { + my($self) = @_; + my %search; + $search{first_name} = $self->first_name if $self->has_first_name; + $search{last_name} = $self->last_name if $self->has_last_name; + return [\%search]; +} + +# no special packing/unpacking required for Foo +sub _to_string_pack_value { $_[1] } +sub _from_string_unpack_value { $_[1] } + +1; diff --git a/lib/Reaction/Class.pm b/lib/Reaction/Class.pm index a57dcdf..9f61bbf 100644 --- a/lib/Reaction/Class.pm +++ b/lib/Reaction/Class.pm @@ -233,6 +233,8 @@ sub next_import { sub next_import_package { 'Moose' } +__PACKAGE__->meta->make_immutable; + 1; #---------#---------#---------#---------#---------#---------#---------#--------# diff --git a/lib/Reaction/InterfaceModel/Reflector/DBIC.pm b/lib/Reaction/InterfaceModel/Reflector/DBIC.pm index 38d9025..96bc262 100644 --- a/lib/Reaction/InterfaceModel/Reflector/DBIC.pm +++ b/lib/Reaction/InterfaceModel/Reflector/DBIC.pm @@ -153,7 +153,7 @@ sub reflect_schema { superclasses => [$base], ( @$roles ? (roles => $roles) : ()), ); - + # sources => undef, #default to qr/./ # sources => [], #default to nothing # sources => qr//, #DWIM, treated as [qr//] diff --git a/lib/Reaction/Object.pm b/lib/Reaction/Object.pm index 7440bd3..de4c740 100644 --- a/lib/Reaction/Object.pm +++ b/lib/Reaction/Object.pm @@ -7,6 +7,8 @@ use Moose qw(extends); extends 'Moose::Object'; +__PACKAGE__->meta->make_immutable; + no Moose; 1; diff --git a/lib/Reaction/UI/Controller.pm b/lib/Reaction/UI/Controller.pm index 8ed781f..f428941 100644 --- a/lib/Reaction/UI/Controller.pm +++ b/lib/Reaction/UI/Controller.pm @@ -11,7 +11,8 @@ with 'Catalyst::Component::InstancePerContext'; sub build_per_context_instance { my ($self, $c, @args) = @_; - my $newself = $self->new($self->_application, {%$self, context => $c, @args}); + my $class = ref($self) || $self; + my $newself = $class->new($self->_application, {%{$self || {}}, context => $c, @args}); return $newself; } @@ -135,7 +136,7 @@ controller configuration. For example to override the default number of items in a CRUD list action: __PACKAGE__->config( - action => { + action => { list => { ViewPort => { per_page => 50 } }, } ); @@ -159,7 +160,7 @@ TODO: explain how next_action as a scalar gets converted to the redirect arrayre =head2 pop_viewport_to $vp Call L<Reaction::UI::FocusStack/pop_viewport> or -L<Reaction::UI::FocusStack/pop_viewport_to> on +L<Reaction::UI::FocusStack/pop_viewport_to> on the C<< $c->stash->{focus_stack} >>. =head2 redirect_to $c, $to, $captures, $args, $attrs @@ -185,7 +186,7 @@ $args if not supplied. =head2 make_context_closure The purpose of this method is to prevent memory leaks. -It weakens the context object, often denoted $c, and passes it as the +It weakens the context object, often denoted $c, and passes it as the first argument to the sub{} that is passed to the make_context_closure method. In other words, @@ -198,7 +199,7 @@ make_context_closure returns sub { $sub_you_gave_it->($weak_c, @_) To further expound up this useful construct consider code written before make_context_closure was created: - on_apply_callback => + on_apply_callback => sub { $self->after_search( $c, @_ ); } diff --git a/lib/Reaction/UI/Skin.pm b/lib/Reaction/UI/Skin.pm index 237279d..0683258 100644 --- a/lib/Reaction/UI/Skin.pm +++ b/lib/Reaction/UI/Skin.pm @@ -71,6 +71,7 @@ sub _find_skin_dir { }; sub _load_skin_config { my ($self, $args) = @_; + my $class = ref($self) || $self; my $base = $self->skin_dir; my $lst = sub { (ref $_[0] eq 'ARRAY') ? $_[0] : [$_[0]] }; my @files = ( @@ -84,7 +85,7 @@ sub _load_skin_config { })} ); if (my $super_name = $cfg{extends}) { - my $super = $self->new( + my $super = $class->new( name => $super_name, view => $self->view, skin_base_dir => $args->{skin_base_dir}, diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseMany.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseMany.pm index 1b7a411..227ad33 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseMany.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseMany.pm @@ -11,11 +11,11 @@ use namespace::clean -except => [ qw(meta) ]; use MooseX::Types::Moose qw/ArrayRef/; extends 'Reaction::UI::ViewPort::Field'; -with 'Reaction::UI::ViewPort::Field::Role::Mutable'; +with 'Reaction::UI::ViewPort::Field::Role::Mutable' => { value_type => 'ArrayRef' }; with 'Reaction::UI::ViewPort::Field::Role::Choices'; #MUST BE HERE, BELOW THE 'does', OR THE TRIGGER WILL NOT HAPPEN! -has '+value' => (isa => ArrayRef); +#has '+value' => (isa => ArrayRef); around value => sub { my $orig = shift; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/File.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/File.pm index 4318eee..5c1b35d 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/File.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/File.pm @@ -6,9 +6,8 @@ use Reaction::Class; use namespace::clean -except => [ qw(meta) ]; extends 'Reaction::UI::ViewPort::Field'; -with 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; - -has '+value' => (isa => Upload); +with 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple' + => { value_type => Upload }; override apply_our_events => sub { my ($self, $events) = @_; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/HiddenArray.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/HiddenArray.pm index 77df3de..a54dfc5 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/HiddenArray.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/HiddenArray.pm @@ -6,9 +6,9 @@ use MooseX::Types::Moose qw/ArrayRef/; extends 'Reaction::UI::ViewPort::Field'; -with 'Reaction::UI::ViewPort::Field::Role::Mutable'; +with 'Reaction::UI::ViewPort::Field::Role::Mutable' => { value_type => 'ArrayRef' }; -has '+value' => (isa => ArrayRef); +#has '+value' => (isa => ArrayRef); around value => sub { my $orig = shift; diff --git a/lib/Reaction/UI/ViewPort/Field/Role/Mutable.pm b/lib/Reaction/UI/ViewPort/Field/Role/Mutable.pm index 94953f4..16ae93f 100644 --- a/lib/Reaction/UI/ViewPort/Field/Role/Mutable.pm +++ b/lib/Reaction/UI/ViewPort/Field/Role/Mutable.pm @@ -1,26 +1,46 @@ package Reaction::UI::ViewPort::Field::Role::Mutable; -use Reaction::Role; +use MooseX::Role::Parameterized; use aliased 'Reaction::InterfaceModel::Action'; use aliased 'Reaction::Meta::InterfaceModel::Action::ParameterAttribute'; use MooseX::Types::Moose qw/Int Str/; - use namespace::clean -except => [ qw(meta) ]; +=pod + +15:24 mst:» I'm not sure I understand why the +foo is overwriting my after'ed clear_value +15:24 mst:» but I would argue it shouldn't do that +15:25 @doy:» because has '+foo' is creating an entirely new attribute +15:25 @doy:» and just copying the meta-attribute's attributes into it +15:25 @doy:» so it's creating a new clearer sub in the subclass +15:27 rafl:» mst: for that case, i tend to just parameterize the role on whatever i might want to override in its attribute definitions + +=cut + +parameter value_type => ( + predicate => 'has_value_type' +); + +role { + +my $p = shift; + has model => (is => 'ro', isa => Action, required => 1); has attribute => (is => 'ro', isa => ParameterAttribute, required => 1); has value => ( - is => 'rw', lazy_build => 1, trigger_adopt('value'), + is => 'rw', lazy_build => 1, trigger => sub { shift->adopt_value }, clearer => 'clear_value', + $p->has_value_type? (isa => $p->value_type) : () ); + has needs_sync => (is => 'rw', isa => Int, default => 0); #should be bool? has message => (is => 'rw', isa => Str, clearer => 'clear_message'); has is_modified => ( #sould be bool? - is => 'ro', writer => '_set_modified', + is => 'ro', writer => '_set_modified', required => 1, default => 1, init_arg => undef ); @@ -111,6 +131,7 @@ sub sync_from_action { around accept_events => sub { ('value', shift->(@_)) }; +}; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Role/Mutable/Simple.pm b/lib/Reaction/UI/ViewPort/Field/Role/Mutable/Simple.pm index e19fa61..d8ca473 100644 --- a/lib/Reaction/UI/ViewPort/Field/Role/Mutable/Simple.pm +++ b/lib/Reaction/UI/ViewPort/Field/Role/Mutable/Simple.pm @@ -1,14 +1,23 @@ package Reaction::UI::ViewPort::Field::Role::Mutable::Simple; -use Reaction::Role; +use MooseX::Role::Parameterized; use aliased 'Reaction::UI::ViewPort::Field::Role::Mutable'; use namespace::clean -except => [ qw(meta) ]; -with Mutable; + +parameter value_type => ( + predicate => 'has_value_type' +); + +role { + +my $p = shift; + +with Mutable, $p->has_value_type ? { value_type => $p->value_type } : (); has value_string => ( - is => 'rw', lazy_build => 1, trigger_adopt('value_string'), + is => 'rw', lazy_build => 1, trigger => sub { shift->adopt_value_string }, clearer => 'clear_value', ); @@ -44,6 +53,6 @@ around accept_events => sub { ('value_string', shift->(@_)) }; around force_events => sub { (value_string => '', shift->(@_)) }; - +}; 1; diff --git a/lib/Reaction/UI/ViewPort/ListViewWithSearch.pm b/lib/Reaction/UI/ViewPort/ListViewWithSearch.pm index ee5f738..c199f7d 100644 --- a/lib/Reaction/UI/ViewPort/ListViewWithSearch.pm +++ b/lib/Reaction/UI/ViewPort/ListViewWithSearch.pm @@ -6,8 +6,6 @@ extends 'Reaction::UI::ViewPort::Collection::Grid'; with 'Reaction::UI::ViewPort::Collection::Role::UseSearchSpec'; with 'Reaction::UI::ViewPort::Collection::Role::Order'; -with 'Reaction::UI::ViewPort::Collection::Role::Pager'; -with 'Reaction::UI::ViewPort::Role::Actions'; __PACKAGE__->meta->make_immutable; diff --git a/lib/Reaction/UI/ViewPort/Role/Actions.pm b/lib/Reaction/UI/ViewPort/Role/Actions.pm index 32c7bbb..ceb9bfe 100644 --- a/lib/Reaction/UI/ViewPort/Role/Actions.pm +++ b/lib/Reaction/UI/ViewPort/Role/Actions.pm @@ -67,7 +67,7 @@ sub _build_actions { location => join ('-', $loc, 'action', $i++), uri => ( ref($uri) eq 'CODE' ? $uri->($target, $ctx) : $uri ), display => ( ref($label) eq 'CODE' ? $label->($target, $ctx) : $label ), - layout => ( ref($layout) eq 'CODE' ? $layout->($target, $ctx) : $layout ), + layout => $layout, ); push(@act, $action); } diff --git a/lib/Reaction/UI/ViewPort/SearchableListViewContainer.pm b/lib/Reaction/UI/ViewPort/SearchableListViewContainer.pm index d83941b..4468275 100644 --- a/lib/Reaction/UI/ViewPort/SearchableListViewContainer.pm +++ b/lib/Reaction/UI/ViewPort/SearchableListViewContainer.pm @@ -74,7 +74,7 @@ override BUILDARGS => sub { }; override child_event_sinks => method () { - ((map $self->$_, 'listview', 'search_form'), super); + ((map $self->$_, 'search_form', 'listview'), super); }; 1; diff --git a/lib/Reaction/UI/Widget/Field/Mutable/HiddenArray.pm b/lib/Reaction/UI/Widget/Field/Mutable/HiddenArray.pm index e4e1c10..a65f3cb 100644 --- a/lib/Reaction/UI/Widget/Field/Mutable/HiddenArray.pm +++ b/lib/Reaction/UI/Widget/Field/Mutable/HiddenArray.pm @@ -11,6 +11,10 @@ implements fragment hidden_list { }; implements fragment hidden_field { + # this needs to go here in order to override the field_name from + # Widget::Field::Mutable::Simple which defaults to value_string and does not + # make sense for HiddenArray + arg field_name => event_id 'value'; arg field_value => $_; }; diff --git a/share/skin/base/layout/action.tt b/share/skin/base/layout/action.tt index b5cb708..dba41d0 100644 --- a/share/skin/base/layout/action.tt +++ b/share/skin/base/layout/action.tt @@ -1,13 +1,11 @@ =for layout widget -<div class="action_form"> - <form action="[% action %]" id="[% form_id %]" method="[% method %]" enctype="multipart/form-data"> - [% header %] - [% container_list %] - [% buttons %] - [% footer %] - </form> -</div> +<form action="[% action %]" id="[% form_id %]" method="[% method %]" enctype="multipart/form-data"> + [% header %] + [% container_list %] + [% buttons %] + [% footer %] +</form> =for layout header diff --git a/share/skin/base/layout/collection.tt b/share/skin/base/layout/collection.tt index 6becfb1..da0cd2f 100644 --- a/share/skin/base/layout/collection.tt +++ b/share/skin/base/layout/collection.tt @@ -6,9 +6,7 @@ =for layout body -<div class="collection_members"> - [% members %] -</div> +[% members %] =for layout footer diff --git a/share/skin/base/layout/field/array.tt b/share/skin/base/layout/field/array.tt index cd9c0c2..ac62db7 100644 --- a/share/skin/base/layout/field/array.tt +++ b/share/skin/base/layout/field/array.tt @@ -9,11 +9,9 @@ =for layout list -<div class="array_list"> <ul> -[% content %] + [% content %] </ul> -</div> =for layout item diff --git a/share/skin/base/layout/field/collection.tt b/share/skin/base/layout/field/collection.tt index 2203344..1f6ae9e 100644 --- a/share/skin/base/layout/field/collection.tt +++ b/share/skin/base/layout/field/collection.tt @@ -9,11 +9,9 @@ =for layout list -<div class="collection_list"> <ul> -[% call_next %] + [% call_next %] </ul> -</div> =for layout item diff --git a/share/skin/base/layout/field/container.tt b/share/skin/base/layout/field/container.tt index c504e55..d9e0ced 100644 --- a/share/skin/base/layout/field/container.tt +++ b/share/skin/base/layout/field/container.tt @@ -11,8 +11,6 @@ =for layout field -<div class="field_container_field"> - [% call_next %] -</div> +[% call_next %] =cut diff --git a/share/skin/base/layout/field/mutable.tt b/share/skin/base/layout/field/mutable.tt index d21e979..c4ef2e1 100644 --- a/share/skin/base/layout/field/mutable.tt +++ b/share/skin/base/layout/field/mutable.tt @@ -1,6 +1,6 @@ =for layout widget -<div class="[% field_class %]">[% label_fragment %] [% field %] [% message_fragment %]</div> +[% label_fragment %] [% field %] [% message_fragment %] =for layout label @@ -18,8 +18,7 @@ class="required_field" =for layout field -<input type="[% field_type %]" name="[% field_name %]" id="[% field_id %]" - [% field_body %] /> +<input type="[% field_type %]" name="[% field_name %]" id="[% field_id %]" [% field_body %] /> =for layout field_body diff --git a/share/skin/base/layout/field/mutable/choose_many.tt b/share/skin/base/layout/field/mutable/choose_many.tt index 51f315e..9d19fff 100644 --- a/share/skin/base/layout/field/mutable/choose_many.tt +++ b/share/skin/base/layout/field/mutable/choose_many.tt @@ -8,7 +8,6 @@ =for layout field -<div class="choose_many_field"> <table> <tr> <td> [% available_values %] </td> @@ -19,7 +18,6 @@ </td> </tr> </table> -</div> =for layout available_values @@ -43,12 +41,10 @@ =for layout action_buttons -<div class="choose_many_buttons"> - <input type="submit" value=">>" name="[% event_id_add_all_values %]" /> - <input type="submit" value=">" name="[% event_id_do_add_values %]" /> - <input type="submit" value="<" name="[% event_id_do_remove_values %]" /> - <input type="submit" value="<<" name="[% event_id_remove_all_values %]" /> -</div> +<input type="submit" value=">>" name="[% event_id_add_all_values %]" /> +<input type="submit" value=">" name="[% event_id_do_add_values %]" /> +<input type="submit" value="<" name="[% event_id_do_remove_values %]" /> +<input type="submit" value="<<" name="[% event_id_remove_all_values %]" /> =for layout message diff --git a/share/skin/base/layout/field/mutable/choose_one.tt b/share/skin/base/layout/field/mutable/choose_one.tt index 0db3ffd..c366a86 100644 --- a/share/skin/base/layout/field/mutable/choose_one.tt +++ b/share/skin/base/layout/field/mutable/choose_one.tt @@ -15,8 +15,7 @@ =for layout option - <option value="[% option_value %]" [% option_is_selected %] - > [% option_name %]</option> + <option value="[% option_value %]" [% option_is_selected %]>[% option_name %]</option> =for layout option_is_selected_yes diff --git a/share/skin/default/layout/action.tt b/share/skin/default/layout/action.tt index a18e51d..e1b003f 100644 --- a/share/skin/default/layout/action.tt +++ b/share/skin/default/layout/action.tt @@ -1,5 +1,11 @@ =extends NEXT +=for layout widget + +<div class="action_form"> + [% call_next %] +</div> + =for layout container [% call_next %] <br /> diff --git a/share/skin/default/layout/field/array.tt b/share/skin/default/layout/field/array.tt index acb2cce..60c86b1 100644 --- a/share/skin/default/layout/field/array.tt +++ b/share/skin/default/layout/field/array.tt @@ -4,4 +4,10 @@ <span class="field_array_label"><strong > [% content | html %]: </strong></span> +=for layout list + +<div class="array_list"> + [% call_next %] +</div> + =cut diff --git a/share/skin/default/layout/field/collection.tt b/share/skin/default/layout/field/collection.tt index f513e94..16789bf 100644 --- a/share/skin/default/layout/field/collection.tt +++ b/share/skin/default/layout/field/collection.tt @@ -4,4 +4,10 @@ <span class="field_collection_label_box"><strong> [% label %]: </strong></span> +=for layout list + +<div class="collection_list"> + [% call_next %] +</div> + =cut diff --git a/share/skin/default/layout/field/mutable.tt b/share/skin/default/layout/field/mutable.tt index 615e14e..ec10a4c 100644 --- a/share/skin/default/layout/field/mutable.tt +++ b/share/skin/default/layout/field/mutable.tt @@ -1,5 +1,9 @@ =extends NEXT +=for layout widget + +<div class="[% field_class %]">[% call_next %]</div> + =for layout message [% call_next %]<br /> diff --git a/share/skin/default/layout/field/mutable/choose_many.tt b/share/skin/default/layout/field/mutable/choose_many.tt index e01a1ba..117f39e 100644 --- a/share/skin/default/layout/field/mutable/choose_many.tt +++ b/share/skin/default/layout/field/mutable/choose_many.tt @@ -6,13 +6,16 @@ [% message_fragment %] [% field %] +=for layout field + +<div class="choose_many_field"> + [% call_next %] +</div> + =for layout action_buttons <div class="choose_many_buttons"> -<input type="submit" value=">>" name="[% event_id_add_all_values %]" /> <br /> -<input type="submit" value=">" name="[% event_id_do_add_values %]" /> <br /> -<input type="submit" value="<" name="[% event_id_do_remove_values %]" /> <br /> -<input type="submit" value="<<" name="[% event_id_remove_all_values %]" /> <br /> + [% call_next %] </div> =cut |