diff options
author | edenc <edenc@03d0b0b2-0e1a-0410-a411-fdb2f4bd65d7> | 2008-02-11 18:38:38 +0000 |
---|---|---|
committer | edenc <edenc@03d0b0b2-0e1a-0410-a411-fdb2f4bd65d7> | 2008-02-11 18:38:38 +0000 |
commit | 88c723592b7f440af37b1e4c26c708c7998e2d6c (patch) | |
tree | 788c2e88aa56f15e09162681620b3a2037e9bc82 | |
parent | ddd1dc657e6cf50128e94c103411d758538c6f99 (diff) | |
parent | 5d86015dcae72913eb60b0111961733213601873 (diff) | |
download | reaction-88c723592b7f440af37b1e4c26c708c7998e2d6c.tar.gz reaction-88c723592b7f440af37b1e4c26c708c7998e2d6c.zip |
r20434@hades (orig r549): groditi | 2008-01-30 18:09:54 -0300
better error messages / dont swallow error when a widget has compile errors
r20435@hades (orig r550): wreis | 2008-01-30 18:10:59 -0300
nuked CreditCard type
r20442@hades (orig r553): groditi | 2008-01-30 19:20:28 -0300
ChooseMany fix
r20443@hades (orig r554): matthewt | 2008-01-31 05:07:33 -0300
change dist name to Reaction
r20444@hades (orig r555): matthewt | 2008-01-31 07:07:29 -0300
added widget_search_path option (ignored), defaults.conf support and moved file extension to View
r20445@hades (orig r556): matthewt | 2008-01-31 07:47:10 -0300
remove vestigial override
r20446@hades (orig r557): matthewt | 2008-01-31 08:06:10 -0300
removed view arg to LayoutSet, moved to using skin to resolve widget class, added temporary proxy to View from Skin
r20447@hades (orig r558): matthewt | 2008-01-31 08:35:47 -0300
moved widget class search path to Skin
r20448@hades (orig r559): matthewt | 2008-01-31 09:40:10 -0300
defaults.conf support works much better if I commit the damn thing
r20449@hades (orig r560): matthewt | 2008-01-31 10:32:16 -0300
rework skin path handling
r20451@hades (orig r562): matthewt | 2008-01-31 13:23:08 -0300
get rid of the 'title is undef' error
r20452@hades (orig r563): matthewt | 2008-02-02 13:12:31 -0300
Collection field vp works again.
r20453@hades (orig r564): matthewt | 2008-02-02 13:18:31 -0300
vestigial classes, nuked
r20454@hades (orig r565): matthewt | 2008-02-02 13:33:15 -0300
sync_to_action not required, will trigger off value set
r20455@hades (orig r566): matthewt | 2008-02-02 14:07:10 -0300
add value_is_required, add logic for sync of clearer on !required attrs
r20456@hades (orig r567): wreis | 2008-02-02 14:52:14 -0300
fixed layout path for ArrayRef type
r20457@hades (orig r568): groditi | 2008-02-02 15:40:58 -0300
the forwards on basic_page and basic_model_action were breaking config merging at the push viewport stage
r20459@hades (orig r570): groditi | 2008-02-02 16:20:40 -0300
oops forward takes args as an arrayref and i forgot to remove that
r20461@hades (orig r572): matthewt | 2008-02-03 06:54:30 -0300
generate clearer for !required action attributes
r20462@hades (orig r573): matthewt | 2008-02-03 06:55:15 -0300
datetime now handles optional using a wrap on value_string
r20463@hades (orig r574): matthewt | 2008-02-03 09:44:08 -0300
make delayed setup components work so implements+does with required methods in the role works
r20464@hades (orig r575): matthewt | 2008-02-03 09:48:41 -0300
kill vestigial adopt_value method in Field (since 'value' doesn't get set on a non-mutable field anyway)
r20465@hades (orig r576): matthewt | 2008-02-03 10:48:49 -0300
vestigial widget class removed
r20466@hades (orig r577): matthewt | 2008-02-03 11:03:21 -0300
simple mutable fields now use value_string (ChooseMany unconverted)
r20467@hades (orig r578): matthewt | 2008-02-03 17:27:18 -0300
clean out pre-widget stuff
r20468@hades (orig r579): groditi | 2008-02-03 21:18:36 -0300
burnt out, so writing some docs to clear my brain
r20523@hades (orig r586): matthewt | 2008-02-07 05:52:10 -0300
better error on failed layout set lookup
r20524@hades (orig r587): matthewt | 2008-02-07 05:52:49 -0300
pass _parent to collections
r20525@hades (orig r588): matthewt | 2008-02-07 12:58:53 -0300
complete MooseX::Types port
r20526@hades (orig r589): wreis | 2008-02-07 18:12:22 -0300
added meta_info for VP::SiteLayout
r20530@hades (orig r590): matthewt | 2008-02-08 06:42:45 -0300
refactor Reflector a bit and eliminate some silent fail possibilities
r20534@hades (orig r594): matthewt | 2008-02-09 14:23:48 -0300
alter skin loading precedence (layoutset path search always starts from toip except for =extends NEXT
r20535@hades (orig r595): matthewt | 2008-02-09 14:24:23 -0300
prevent immutable creating new() methods for Reaction metaclasses
r20536@hades (orig r596): matthewt | 2008-02-09 14:26:50 -0300
was part of skin precedence changes but bungled the command
r20537@hades (orig r597): matthewt | 2008-02-09 14:27:38 -0300
avoid passwords going into <input> elements
r20539@hades (orig r599): matthewt | 2008-02-10 07:48:52 -0300
_ prefixed writer doth not mean rw
r20540@hades (orig r600): matthewt | 2008-02-10 07:49:18 -0300
fix method modifiers
r20541@hades (orig r601): matthewt | 2008-02-10 08:57:26 -0300
get rid of extraneous whitepsace in textaeras
r20542@hades (orig r602): matthewt | 2008-02-10 08:57:43 -0300
fix vp_args passing to actions
119 files changed, 591 insertions, 1968 deletions
diff --git a/Makefile.PL b/Makefile.PL index 5cb3833..167a9fa 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -1,6 +1,6 @@ use inc::Module::Install 0.64; -name 'ComponentUI'; +name 'Reaction'; all_from 'lib/ComponentUI.pm'; requires 'Catalyst' => '5.7002'; @@ -31,10 +31,10 @@ requires 'Email::MIME::Creator'; requires 'Text::CSV_XS'; requires 'Devel::Declare' => '0.001006'; requires 'MooseX::Types' => '0.04'; -requires 'Business::CreditCard' => '0.30'; requires 'Scalar::Util'; +requires 'File::ShareDir'; -catalyst; +install_share; install_script glob('script/*.pl'); diff --git a/lab/Reaction/Class.pm b/lab/Reaction/Class.pm deleted file mode 100644 index f961baf..0000000 --- a/lab/Reaction/Class.pm +++ /dev/null @@ -1,82 +0,0 @@ -=head1 NAME - -Reaction::Class - Reaction class declaration syntax - -=head1 SYNOPSIS - -In My/Person.pm: - -=for example My::Person setup - - package My::Person; - - use Reaction::Class; - use Reaction::Types::Core qw/Str/; - - class Person which { - - has 'name' => Str; - - has 'nickname' => optional Str; - - implements 'preferred_name' which { - accepts nothing; - returns Str; - guarantees when { $self->has_nickname } returns { $self->nickname }; - guarantees when { !$self->has_nickname } returns { $self->name }; - } with { - return ($self->has_nickname ? $self->nickname : $self->name); - }; - - }; - -=for example My::Person tests - -=begin tests - -my $meta = My::Person->meta; - -isa_ok($meta, 'Reaction::Meta::Class'); - -my $attr_map = $meta->get_attribute_map; - -foreach my $attr_name (qw/name nickname/) { - isa_ok($attr_map->{$attr_name}, 'Reaction::Meta::Attribute'); -} - -ok($attr_map->{name}->is_required, 'name is required'); -ok(!$attr_map->{nickname}->is_required, 'nickname is optional'); - -=end tests - -In your code - - -=for example My::Person usage - - my $jim = My::Person->new(name => 'Jim'); - - print $jim->name."\n"; # prints "Jim\n" - - print $jim->preferred_name."\n"; # prints "Jim\n" - - $jim->name('James'); # returns 'James' - - $jim->nickname('Jim'); # returns 'Jim' - - print $jim->preferred_name."\n"; # prints "Jim\n" - - $jim->preferred_name('foo'); # throws Reaction::Exception::MethodArgumentException - -=for example My::Person end - -=head1 DESCRIPTION - -=head1 AUTHORS - -See L<Reaction::Class> for authors. - -=head1 LICENSE - -See L<Reaction::Class> for the license. - -=cut diff --git a/lib/Reaction/Class.pm b/lib/Reaction/Class.pm index 7813f48..64116ce 100644 --- a/lib/Reaction/Class.pm +++ b/lib/Reaction/Class.pm @@ -147,15 +147,20 @@ sub setup_and_cleanup { shift if $_[0] eq 'as'; push(@methods, [ $name, shift ]); }; + my $s = $setup; foreach my $meth ($self->delayed_methods) { $save_delayed{$meth} = $package->can($meth); - local *{"${package}::${meth}"} = - Sub::Name::subname "${self}::${meth}" => sub { - push(@apply_after, [ $meth => @_ ]); - }; + my $s_copy = $s; + $s = sub { + local *{"${package}::${meth}"} = + Sub::Name::subname "${self}::${meth}" => sub { + push(@apply_after, [ $meth => @_ ]); + }; + $s_copy->(@_); + }; } # XXX - need additional fuckery to handle multi-class-per-file - $setup->(); # populate up the crap + $s->(); # populate up the crap } my %exports = $self->exports_for_package($package); { diff --git a/lib/Reaction/InterfaceModel/Action/DBIC/Result/Delete.pm b/lib/Reaction/InterfaceModel/Action/DBIC/Result/Delete.pm index 14ae6dc..4d81486 100644 --- a/lib/Reaction/InterfaceModel/Action/DBIC/Result/Delete.pm +++ b/lib/Reaction/InterfaceModel/Action/DBIC/Result/Delete.pm @@ -4,7 +4,7 @@ use Reaction::Types::DBIC 'Row'; use Reaction::Class; class Delete is 'Reaction::InterfaceModel::Action', which { - has '+target_model' => (isa => 'Row'); + has '+target_model' => (isa => Row); sub can_apply { 1 } diff --git a/lib/Reaction/InterfaceModel/Action/DBIC/Result/Update.pm b/lib/Reaction/InterfaceModel/Action/DBIC/Result/Update.pm index 34ac7f2..2a822e6 100644 --- a/lib/Reaction/InterfaceModel/Action/DBIC/Result/Update.pm +++ b/lib/Reaction/InterfaceModel/Action/DBIC/Result/Update.pm @@ -8,7 +8,7 @@ class Update is 'Reaction::InterfaceModel::Action', which { does 'Reaction::InterfaceModel::Action::DBIC::Role::CheckUniques'; - has '+target_model' => (isa => 'Row'); + has '+target_model' => (isa => Row); implements BUILD => as { my ($self) = @_; diff --git a/lib/Reaction/InterfaceModel/Action/DBIC/ResultSet/Create.pm b/lib/Reaction/InterfaceModel/Action/DBIC/ResultSet/Create.pm index 07e949b..3494f9b 100644 --- a/lib/Reaction/InterfaceModel/Action/DBIC/ResultSet/Create.pm +++ b/lib/Reaction/InterfaceModel/Action/DBIC/ResultSet/Create.pm @@ -9,7 +9,7 @@ class Create is 'Reaction::InterfaceModel::Action', which { does 'Reaction::InterfaceModel::Action::DBIC::Role::CheckUniques'; - has '+target_model' => (isa => 'ResultSet'); + has '+target_model' => (isa => ResultSet); implements do_apply => as { my $self = shift; diff --git a/lib/Reaction/InterfaceModel/Action/DBIC/ResultSet/DeleteAll.pm b/lib/Reaction/InterfaceModel/Action/DBIC/ResultSet/DeleteAll.pm index e6dfe3a..c26e287 100644 --- a/lib/Reaction/InterfaceModel/Action/DBIC/ResultSet/DeleteAll.pm +++ b/lib/Reaction/InterfaceModel/Action/DBIC/ResultSet/DeleteAll.pm @@ -6,7 +6,7 @@ use Reaction::InterfaceModel::Action; class DeleteAll is 'Reaction::InterfaceModel::Action', which { - has '+target_model' => (isa => 'ResultSet'); + has '+target_model' => (isa => ResultSet); sub can_apply { 1 } diff --git a/lib/Reaction/InterfaceModel/Action/User/ChangePassword.pm b/lib/Reaction/InterfaceModel/Action/User/ChangePassword.pm index fc8ff88..6546502 100644 --- a/lib/Reaction/InterfaceModel/Action/User/ChangePassword.pm +++ b/lib/Reaction/InterfaceModel/Action/User/ChangePassword.pm @@ -2,8 +2,10 @@ package Reaction::InterfaceModel::Action::User::ChangePassword; use Reaction::Class; +use Reaction::Types::Core qw(Password); + class ChangePassword is 'Reaction::InterfaceModel::Action::User::SetPassword', which { - has old_password => (isa => 'Password', is => 'rw', lazy_fail => 1); + has old_password => (isa => Password, is => 'rw', lazy_fail => 1); around error_for_attribute => sub { my $super = shift; diff --git a/lib/Reaction/InterfaceModel/Action/User/Login.pm b/lib/Reaction/InterfaceModel/Action/User/Login.pm index 781ec0f..0bc3d97 100644 --- a/lib/Reaction/InterfaceModel/Action/User/Login.pm +++ b/lib/Reaction/InterfaceModel/Action/User/Login.pm @@ -2,11 +2,12 @@ package Reaction::InterfaceModel::Action::User::Login; use Reaction::Class; use aliased 'Reaction::InterfaceModel::Action'; +use Reaction::Types::Core qw(SimpleStr Password); class Login, is Action, which { - has 'username' => (isa => 'SimpleStr', is => 'rw', lazy_fail => 1); - has 'password' => (isa => 'Password', is => 'rw', lazy_fail => 1); + has 'username' => (isa => SimpleStr, is => 'rw', lazy_fail => 1); + has 'password' => (isa => Password, is => 'rw', lazy_fail => 1); around error_for_attribute => sub { my $super = shift; diff --git a/lib/Reaction/InterfaceModel/Action/User/ResetPassword.pm b/lib/Reaction/InterfaceModel/Action/User/ResetPassword.pm index 3ef645d..2637dc0 100644 --- a/lib/Reaction/InterfaceModel/Action/User/ResetPassword.pm +++ b/lib/Reaction/InterfaceModel/Action/User/ResetPassword.pm @@ -7,12 +7,14 @@ use aliased 'Reaction::InterfaceModel::Action::User::Role::ConfirmationCodeSupport'; use aliased 'Reaction::InterfaceModel::Action::User::SetPassword'; +use Reaction::Types::Core qw(NonEmptySimpleStr); + class ResetPassword is SetPassword, which { does ConfirmationCodeSupport; has confirmation_code => - (isa => 'NonEmptySimpleStr', is => 'rw', lazy_fail => 1); + (isa => NonEmptySimpleStr, is => 'rw', lazy_fail => 1); around error_for_attribute => sub { my $super = shift; diff --git a/lib/Reaction/InterfaceModel/Action/User/SetPassword.pm b/lib/Reaction/InterfaceModel/Action/User/SetPassword.pm index fcf922a..14a561a 100644 --- a/lib/Reaction/InterfaceModel/Action/User/SetPassword.pm +++ b/lib/Reaction/InterfaceModel/Action/User/SetPassword.pm @@ -2,12 +2,13 @@ package Reaction::InterfaceModel::Action::User::SetPassword; use Reaction::Class; use Reaction::InterfaceModel::Action; +use Reaction::Types::Core qw(Password); class SetPassword is 'Reaction::InterfaceModel::Action', which { - has new_password => (isa => 'Password', is => 'rw', lazy_fail => 1); + has new_password => (isa => Password, is => 'rw', lazy_fail => 1); has confirm_new_password => - (isa => 'Password', is => 'rw', lazy_fail => 1); + (isa => Password, is => 'rw', lazy_fail => 1); around error_for_attribute => sub { my $super = shift; diff --git a/lib/Reaction/InterfaceModel/Reflector/DBIC.pm b/lib/Reaction/InterfaceModel/Reflector/DBIC.pm index 2d4e1a3..f4d98b7 100644 --- a/lib/Reaction/InterfaceModel/Reflector/DBIC.pm +++ b/lib/Reaction/InterfaceModel/Reflector/DBIC.pm @@ -161,8 +161,7 @@ class DBIC, which { unless($model && $schema); Class::MOP::load_class( $base ); Class::MOP::load_class( $schema ); - my $meta = eval { Class::MOP::load_class($model); } ? - $model->meta : $base->meta->create($model, superclasses => [ $base ]); + my $meta = $self->_load_or_create($model, $base); # sources => undef, #default to qr/./ # sources => [], #default to nothing @@ -333,7 +332,11 @@ class DBIC, which { domain_model => $dm_name, orig_attr_name => $source, default => sub { - $collection->new(_source_resultset => shift->$dm_name->resultset($source)); + my $self = $_[0]; + return $collection->new( + _source_resultset => $self->$dm_name->resultset($source), + _parent => $self, + ); }, ); @@ -380,8 +383,7 @@ class DBIC, which { Class::MOP::load_class( $base ); Class::MOP::load_class( $object ); - my $meta = eval { Class::MOP::load_class($class) } ? - $class->meta : $base->meta->create( $class, superclasses => [ $base ]); + my $meta = $self->_load_or_create($class, $base); my $make_immutable = $meta->is_immutable || $self->make_classes_immutable;; $meta->make_mutable if $meta->is_immutable; @@ -468,8 +470,7 @@ class DBIC, which { Class::MOP::load_class($schema) if $schema; Class::MOP::load_class($source_class); - my $meta = eval { Class::MOP::load_class($class) } ? - $class->meta : $base->meta->create($class, superclasses => [ $base ]); + my $meta = $self->_load_or_create($class, $base); #create the domain model $dm_name ||= $self->dm_name_from_source_name($source_name); @@ -761,8 +762,7 @@ class DBIC, which { my $attributes = $self->parse_reflect_rules($attr_rules, $attr_haystack); #create the class - my $meta = eval { Class::MOP::load_class($class) } ? - $class->meta : $base->meta->create($class, superclasses => [$base]); + my $meta = $self->_load_or_create($class, $base); my $make_immutable = $meta->is_immutable || $self->make_classes_immutable; $meta->make_mutable if $meta->is_immutable; @@ -773,7 +773,8 @@ class DBIC, which { my $s_attr = $s_meta->find_attribute_by_name($s_attr_name); confess("Unable to find attribute for '${s_attr_name}' via '${source}'") unless defined $s_attr; - next unless $s_attr->get_write_method; #only rw attributes! + next unless $s_attr->get_write_method + && $s_attr->get_write_method !~ /^_/; #only rw attributes! my $attr_params = $self->parameters_for_source_object_action_attribute ( @@ -809,6 +810,8 @@ class DBIC, which { is => 'rw', isa => $from_attr->_isa_metadata, required => $from_attr->is_required, + ($from_attr->is_required + ? () : (clearer => "clear_$attr_name}")), predicate => "has_${attr_name}", ); @@ -859,6 +862,24 @@ class DBIC, which { return \%attr_opts; }; + implements _load_or_create => as { + my ($self, $class, $base) = @_; + my $meta = $self->_maybe_load_class($class) ? + $class->meta : $base->meta->create($class, superclasses => [ $base ]); + return $meta; + }; + + implements _maybe_load_class => as { + my ($self, $class) = @_; + my $file = $class . '.pm'; + $file =~ s{::}{/}g; + my $ret = eval { Class::MOP::load_class($class) }; + if ($INC{$file} && $@) { + confess "Error loading ${class}: $@"; + } + return $ret; + }; + }; 1; diff --git a/lib/Reaction/Meta/Class.pm b/lib/Reaction/Meta/Class.pm index 27c084f..b2c3b9e 100644 --- a/lib/Reaction/Meta/Class.pm +++ b/lib/Reaction/Meta/Class.pm @@ -5,6 +5,8 @@ use Reaction::Meta::Attribute; extends 'Moose::Meta::Class'; +sub new { shift->SUPER::new(@_); } + around initialize => sub { my $super = shift; my $class = shift; diff --git a/lib/Reaction/Meta/InterfaceModel/Action/Class.pm b/lib/Reaction/Meta/InterfaceModel/Action/Class.pm index 0c83353..c09bdb6 100644 --- a/lib/Reaction/Meta/InterfaceModel/Action/Class.pm +++ b/lib/Reaction/Meta/InterfaceModel/Action/Class.pm @@ -5,6 +5,8 @@ use aliased 'Reaction::Meta::InterfaceModel::Action::ParameterAttribute'; class Class is 'Reaction::Meta::Class', which { + implements new => as { shift->SUPER::new(@_) }; + around initialize => sub { my $super = shift; my $class = shift; diff --git a/lib/Reaction/Meta/InterfaceModel/Object/Class.pm b/lib/Reaction/Meta/InterfaceModel/Object/Class.pm index da99ffe..8fad3dc 100644 --- a/lib/Reaction/Meta/InterfaceModel/Object/Class.pm +++ b/lib/Reaction/Meta/InterfaceModel/Object/Class.pm @@ -7,6 +7,8 @@ use Reaction::Class; class Class is 'Reaction::Meta::Class', which { + implements new => as { shift->SUPER::new(@_) }; + around initialize => sub { my $super = shift; my $class = shift; diff --git a/lib/Reaction/Types/Core.pm b/lib/Reaction/Types/Core.pm index 62d508c..afd7454 100644 --- a/lib/Reaction/Types/Core.pm +++ b/lib/Reaction/Types/Core.pm @@ -6,48 +6,48 @@ use MooseX::Types use MooseX::Types::Moose qw/Str Num Int/; -subtype SimpleStr - => as Str - => where { (length($_) <= 255) && ($_ !~ m/\n/) } - => message { "Must be a single line of no more than 255 chars" }; +subtype SimpleStr, + as Str, + where { (length($_) <= 255) && ($_ !~ m/\n/) }, + message { "Must be a single line of no more than 255 chars" }; -subtype NonEmptySimpleStr - => as SimpleStr - => where { length($_) > 0 } - => message { "Must be a non-empty single line of no more than 255 chars" }; +subtype NonEmptySimpleStr, + as SimpleStr, + where { length($_) > 0 }, + message { "Must be a non-empty single line of no more than 255 chars" }; # XXX duplicating constraint msges since moose only uses last message -subtype Password - => as NonEmptySimpleStr - => where { length($_) > 3 } - => message { "Must be between 4 and 255 chars" }; +subtype Password, + as NonEmptySimpleStr, + where { length($_) > 3 }, + message { "Must be between 4 and 255 chars" }; -subtype StrongPassword - => as Password - => where { (length($_) > 7) && (m/[^a-zA-Z]/) } - => message { +subtype StrongPassword, + as Password, + where { (length($_) > 7) && (m/[^a-zA-Z]/) }, + message { "Must be between 8 and 255 chars, and contain a non-alpha char" }; -subtype NonEmptyStr - => as Str - => where { length($_) > 0 } - => message { "Must not be empty" }; - -subtype PositiveNum - => as Num - => where { $_ >= 0 } - => message { "Must be a positive number" }; - -subtype PositiveInt - => as Int - => where { $_ >= 0 } - => message { "Must be a positive integer" }; - -subtype SingleDigit - => as PositiveInt - => where { $_ <= 9 } - => message { "Must be a single digit" }; +subtype NonEmptyStr, + as Str, + where { length($_) > 0 }, + message { "Must not be empty" }; + +subtype PositiveNum, + as Num, + where { $_ >= 0 }, + message { "Must be a positive number" }; + +subtype PositiveInt, + as Int, + where { $_ >= 0 }, + message { "Must be a positive integer" }; + +subtype SingleDigit, + as PositiveInt, + where { $_ <= 9 }, + message { "Must be a single digit" }; 1; diff --git a/lib/Reaction/Types/CreditCard.pm b/lib/Reaction/Types/CreditCard.pm deleted file mode 100644 index f733355..0000000 --- a/lib/Reaction/Types/CreditCard.pm +++ /dev/null @@ -1,49 +0,0 @@ -package Reaction::Types::CreditCard; - -use MooseX::Types - -declare => [qw/CardNumber CheckNumber/]; - -use Reaction::Types::Core qw/NonEmptySimpleStr PositiveInt/; -use Business::CreditCard (); - -subtype CardNumber - => as NonEmptySimpleStr - => where { Business::CreditCard::validate($_) } - => message {"Must be a valid card number"}; - -subtype CheckNumber - => as PositiveInt - => where { $_ <= 999 } - => message { "Must be a 3 digits number" }; - -1; - -=head1 NAME - -Reaction::Types::CreditCard - -=head1 DESCRIPTION - -=over - -=item * CardNumber - -=back - -=head1 SEE ALSO - -=over - -=item * L<Reaction::Types::Core> - -=back - -=head1 AUTHORS - -See L<Reaction::Class> for authors. - -=head1 LICENSE - -See L<Reaction::Class> for the license. - -=cut diff --git a/lib/Reaction/Types/DBIC.pm b/lib/Reaction/Types/DBIC.pm index 0dd1ff8..8f9a37d 100644 --- a/lib/Reaction/Types/DBIC.pm +++ b/lib/Reaction/Types/DBIC.pm @@ -11,8 +11,8 @@ subtype 'DBIx::Class::ResultSet' => as 'Object' => where { $_->isa('DBIx::Class::ResultSet') }; -subtype ResultSet - => as 'DBIx::Class::ResultSet'; +subtype ResultSet, + as 'DBIx::Class::ResultSet'; use DBIx::Class::Core; use DBIx::Class::Row; @@ -21,8 +21,8 @@ subtype 'DBIx::Class::Row' => as 'Object' => where { $_->isa('DBIx::Class::Row') }; -subtype Row - => as 'DBIx::Class::Row'; +subtype Row, + as 'DBIx::Class::Row'; 1; diff --git a/lib/Reaction/Types/DateTime.pm b/lib/Reaction/Types/DateTime.pm index 491ebe5..d6294d2 100644 --- a/lib/Reaction/Types/DateTime.pm +++ b/lib/Reaction/Types/DateTime.pm @@ -6,19 +6,19 @@ use MooseX::Types use MooseX::Types::Moose qw/Object ArrayRef/; use DateTime; -subtype DateTime - => as Object - => where { $_->isa('DateTime') } - => message { "Must be of the form YYYY-MM-DD HH:MM:SS" }; +subtype DateTime, + as Object, + where { $_->isa('DateTime') }, + message { "Must be of the form YYYY-MM-DD HH:MM:SS" }; use DateTime::SpanSet; -subtype SpanSet - => as Object - => where { $_->isa('DateTime::SpanSet') }; +subtype SpanSet, + as Object, + where { $_->isa('DateTime::SpanSet') }; -subtype TimeRangeCollection - => as ArrayRef; +subtype TimeRangeCollection, + as ArrayRef; 1; diff --git a/lib/Reaction/Types/Email.pm b/lib/Reaction/Types/Email.pm index a82d16f..01660a3 100644 --- a/lib/Reaction/Types/Email.pm +++ b/lib/Reaction/Types/Email.pm @@ -6,10 +6,10 @@ use MooseX::Types use Reaction::Types::Core 'NonEmptySimpleStr'; use Email::Valid; -subtype EmailAddress - => as NonEmptySimpleStr - => where { Email::Valid->address($_) } - => message { "Must be a valid e-mail address" }; +subtype EmailAddress, + as NonEmptySimpleStr, + where { Email::Valid->address($_) }, + message { "Must be a valid e-mail address" }; 1; diff --git a/lib/Reaction/UI/Controller/Collection.pm b/lib/Reaction/UI/Controller/Collection.pm index 77a0005..7caf276 100644 --- a/lib/Reaction/UI/Controller/Collection.pm +++ b/lib/Reaction/UI/Controller/Collection.pm @@ -47,17 +47,17 @@ sub object :Chained('base') :PathPart('id') :CaptureArgs(1) { sub list :Chained('base') :PathPart('') :Args(0) { my ($self, $c) = @_; - $c->forward(basic_page => [{ collection => $self->get_collection($c) }]); + $self->basic_page($c, { collection => $self->get_collection($c) }); } sub view :Chained('object') :Args(0) { my ($self, $c) = @_; - $c->forward(basic_page => [{ model => $c->stash->{object} }]); + $self->basic_page($c, { model => $c->stash->{object} }); } -sub basic_page : Private { +sub basic_page { my ($self, $c, $vp_args) = @_; - my $action_name = $c->stack->[-2]->name; + my $action_name = $c->stack->[-1]->name; return $self->push_viewport ( $self->action_viewport_map->{$action_name}, @@ -73,7 +73,7 @@ __END__; =head1 NAME -Reaction::UI::Widget::Controller +Reaction::UI::Controller =head1 DESCRIPTION @@ -84,12 +84,13 @@ Inherits from L<Reaction::UI::Controller>. =head2 model_name -The name of the model this controller will use as it's data source. Should be a name -that can be passed to C<$C-E<gt>model> +The name of the model this controller will use as it's data source. Should be a +name that can be passed to C<$C-E<gt>model> =head2 collection_name -The name of the collection whithin the model that this Controller will be utilizing. +The name of the collection whithin the model that this Controller will be +utilizing. =head2 action_viewport_map @@ -103,14 +104,14 @@ The name of the collection whithin the model that this Controller will be utiliz =back -Read-write lazy building hashref. The keys should match action names in the Controller -and the value should be the ViewPort class that this action should use. - See method C<basic_page> for more info. +Read-write lazy building hashref. The keys should match action names in the +Controller and the value should be the ViewPort class that this action should +use. See method C<basic_page> for more info. =head action_viewport_args -Read-write lazy building hashref. Additional ViewPort arguments for the action named -as the key in the controller. See method C<basic_page> for more info. +Read-write lazy building hashref. Additional ViewPort arguments for the action +named as the key in the controller. See method C<basic_page> for more info. =over 4 @@ -139,6 +140,14 @@ Provided builder for C<action_viewport_map>. Returns a hash with two items: Returns an empty hashref. +=head2 basic_page $c, \%vp_args + +Accepts two arguments, context, and a hashref of viewport arguments. It will +automatically determine the action name using the catalyst stack and call +C<push_viewport> with the ViewPort class name contained in the +C<action_viewport_map> with a set of options determined by merging C<$vp_args> +and the arguments contained in C<action_viewport_args>, if any. + =head1 ACTIONS =head2 base @@ -147,34 +156,31 @@ Chain link, no-op. =head2 list -Chain link, chained to C<base> forwards to basic page passing one custom argument, -C<collection> which includes an instance of the current collection. +Chain link, chained to C<base>. C<list> fetches the collection for the model +and calls C<basic_page> with a single argument, C<collection>. -The default ViewPort for this action is C<Reaction::UI::ViewPort::ListView> and can be -changed by altering the C<action_viewport_map> attribute hash. +The default ViewPort for this action is C<Reaction::UI::ViewPort::ListView> and +can be changed by altering the C<action_viewport_map> attribute hash. =head2 object -Chain link, chained to C<base>, captures one argument, 'id'. Attempts to find a single -object by searching for a member of the current collection which has a Primary Key or -Unique constraint matching that argument. If the object is found it is stored in the - stash under the C<object> key. +Chain link, chained to C<base>, captures one argument, 'id'. Attempts to find +a single object by searching for a member of the current collection which has a +Primary Key or Unique constraint matching that argument. If the object is found +it is stored in the stash under the C<object> key. =head2 view -Chain link, chained to C<object>. Forwards to C<basic page> with one custom vp argument - of C<object>, which is the object located in the previous chain link of the same name. +Chain link, chained to C<object>. Calls C<basic page> with one argument, +C<model>, which contains an instance of the object fetched by the C<object> +action link. -The default ViewPort for this action is C<Reaction::UI::ViewPort::Object> and can be -changed by altering the C<action_viewport_map> attribute hash. +The default ViewPort for this action is C<Reaction::UI::ViewPort::Object> and +can be changed by altering the C<action_viewport_map> attribute hash. -=head2 basic_page +=SEE ALSO -Private action, accepts one argument, a hashref of viewport arguments (C<$vp_args>). - It will automatically determine the action name using the catalyst stack and call -C<push_viewport> with the ViewPort class name contained in the C<action_viewport_map> -and arguments of C<$vp_args> and the arguments contained in C<action_viewport_args>, -if any. +L<Reaction::UI::Controller> =head1 AUTHORS diff --git a/lib/Reaction/UI/Controller/Collection/CRUD.pm b/lib/Reaction/UI/Controller/Collection/CRUD.pm index 877f118..04d46e9 100644 --- a/lib/Reaction/UI/Controller/Collection/CRUD.pm +++ b/lib/Reaction/UI/Controller/Collection/CRUD.pm @@ -56,12 +56,12 @@ sub create :Chained('base') :PathPart('create') :Args(0) { next_action => 'list', on_apply_callback => sub { $self->after_create_callback($c => @_); }, }; - $c->forward( basic_model_action => [$vp_args]); + $self->basic_model_action( $c, $vp_args); } sub delete_all :Chained('base') :PathPart('delete_all') :Args(0) { my ($self, $c) = @_; - $c->forward(basic_model_action => [{ next_action => 'list'}]); + $self->basic_model_action( $c, { next_action => 'list'}); } sub after_create_callback { @@ -76,33 +76,120 @@ sub update :Chained('object') :Args(0) { my @cap = @{$c->req->captures}; pop(@cap); # object id my $vp_args = { next_action => [ $self, 'redirect_to', 'list', \@cap ]}; - $c->forward(basic_model_action => [$vp_args]); + $self->basic_model_action( $c, $vp_args); } sub delete :Chained('object') :Args(0) { my ($self, $c) = @_; #this needs a better solution. currently thinking about it - my @cap = @{$c->req->captures}; + my @cap = @{$c->req->captures}; pop(@cap); # object id my $vp_args = { next_action => [ $self, 'redirect_to', 'list', \@cap ]}; - $c->forward(basic_model_action => [$vp_args]); + $self->basic_model_action( $c, $vp_args); } -sub basic_model_action :Private { +sub basic_model_action { my ($self, $c, $vp_args) = @_; my $target = exists $c->stash->{object} ? $c->stash->{object} : $self->get_collection($c); - my $cat_action_name = $c->stack->[-2]->name; - my $im_action_name = join('', (map{ ucfirst } split('_', $cat_action_name))); - return $self->push_viewport - ( - $self->action_viewport_map->{$cat_action_name}, - model => $self->get_model_action($c, $im_action_name, $target), - %{ $vp_args || {} }, - %{ $self->action_viewport_args->{$cat_action_name} || {} }, - ); + my $action_name = join('', map{ ucfirst } split('_', $c->stack->[-1]->name)); + my $model = $self->get_model_action($c, $action_name, $target); + return $self->basic_page($c, { model => $model, %{$vp_args||{}} }); } 1; + +__END__ + +=head1 NAME + +Reaction::UI::Controller::CRUD - Basic CRUD functionality for Reaction::InterfaceModel data + +=head1 DESCRIPTION + +Controller class which extends L<Reaction::UI::Controller::Collection> to +provide basic Create / Update / Delete / DeleteAll actions. + +Building on the base of the Collection controller this controller allows you to +easily create complex and highly flexible CRUD functionality for your +InterfaceModel models by providing a simple way to render and process your +custom InterfaceModel Actions and customize built-ins. + +=head1 METHODS + +=head2 get_model_action $c, $action_name, $target_im + +Get an instance of the C<$action_name> +L<InterfaceModel::Action|Reaction::InterfaceModel::Action> for model C<$target> +This action is suitable for passing to an +C<Action|Reaction::UI::ViewPort::Action> viewport + +=head2 after_create_callback $c, $vp, $result + +When a <create> action is applied, move the user to the new object's, +C<update> page. + +=head2 basic_model_action $c, \%vp_args + +Extension to C<basic_page> which automatically instantiates an +L<InterfaceModel::Action|Reaction::InterfaceModel::Action> with the right +data target using C<get_model_action> + +=head2 _build_action_viewport_map + +Map C<create>, C<update>, C<delete> and C<delete_all> to use the +C<Action|Reaction::UI::ViewPort::Action> viewport by default. + +=head2 _build_action_viewport_args + +Add action_prototypes to the C<list> action so that action links render correctly in L<ListView|Rection::UI::ViewPort::Listview>. + +=head1 ACTIONS + +=head2 create + +Chaned to C<base>. Create a new member of the collection represented by +this controller. By default it attaches the C<after_create_callback> to +DWIM after apply operations. + +See L<Create|Reaction::InterfaceModel::Action::DBIC::ResultSet::Create> + for more info. + +=head2 delete_all + +Chained to B<base>, delete all the members of the B<collection>. In most cases +this is very much like a C<TRUNCATE> operation. + +See L<DeleteAll|Reaction::InterfaceModel::Action::DBIC::ResultSet::DeleteAll> + for more info. + +=head2 update + +Chained to C<object>, update a single object. + +See L<Update|Reaction::InterfaceModel::Action::DBIC::Result::Update> + for more info. + +=head2 delete + +Chained to C<object>, deletee a single object. + + +See L<Delete|Reaction::InterfaceModel::Action::DBIC::Result::Delete> + for more info. + +=head1 SEE ALSO + +L<Reaction::UI::Controller::Collection>, L<Reaction::UI::Controller> + +=head1 AUTHORS + +See L<Reaction::Class> for authors. + +=head1 LICENSE + +See L<Reaction::Class> for the license. + +=cut diff --git a/lib/Reaction/UI/Controller/Root.pm b/lib/Reaction/UI/Controller/Root.pm index 51b0655..43c02da 100644 --- a/lib/Reaction/UI/Controller/Root.pm +++ b/lib/Reaction/UI/Controller/Root.pm @@ -9,9 +9,11 @@ __PACKAGE__->config( content_type => 'text/html', ); -has 'view_name' => (isa => 'Str', is => 'rw'); -has 'content_type' => (isa => 'Str', is => 'rw'); -has 'window_title' => (isa => 'Str', is => 'rw'); +has 'view_name' => (isa => 'Str', is => 'rw', required => 1); +has 'content_type' => (isa => 'Str', is => 'rw', required => 1); +has 'window_title' => ( + isa => 'Str', is => 'rw', predicate => 'has_window_title' +); sub begin :Private { my ($self, $ctx) = @_; @@ -20,7 +22,9 @@ sub begin :Private { ctx => $ctx, view_name => $self->view_name, content_type => $self->content_type, - title => $self->window_title, + ($self->has_window_title + ? (title => $self->window_title) + : ()), ) ); $ctx->stash(focus_stack => $ctx->stash->{window}->focus_stack); diff --git a/lib/Reaction/UI/LayoutSet.pm b/lib/Reaction/UI/LayoutSet.pm index 4185033..b424730 100644 --- a/lib/Reaction/UI/LayoutSet.pm +++ b/lib/Reaction/UI/LayoutSet.pm @@ -22,11 +22,11 @@ class LayoutSet which { implements 'BUILD' => as { my ($self, $args) = @_; my @path = @{$args->{search_path}||[]}; - confess "No view object provided" unless $args->{view}; confess "No skin object provided" unless $args->{skin}; + confess "No top skin object provided" unless $args->{top_skin}; $self->_load_file($self->source_file, $args); unless ($self->has_widget_class) { - $self->widget_class($args->{view}->widget_class_for($self)); + $self->widget_class($args->{skin}->widget_class_for($self)); } }; @@ -80,7 +80,7 @@ class LayoutSet which { $skin = $build_args->{next_skin}; $super_name = $self->name; } else { - $skin = $build_args->{skin}; + $skin = $build_args->{top_skin}; } $self->super($skin->create_layout_set($super_name)); } elsif ($data =~ /^widget (\S+)/) { diff --git a/lib/Reaction/UI/LayoutSet/TT.pm b/lib/Reaction/UI/LayoutSet/TT.pm index 7f9e2df..68d6749 100644 --- a/lib/Reaction/UI/LayoutSet/TT.pm +++ b/lib/Reaction/UI/LayoutSet/TT.pm @@ -8,8 +8,6 @@ class TT is LayoutSet, which { has 'tt_view' => (is => 'rw', isa => View, lazy_fail => 1); - implements file_extension => as { 'tt' }; - implements 'BUILD' => as { my ($self, $args) = @_; diff --git a/lib/Reaction/UI/Renderer/XHTML.pm b/lib/Reaction/UI/Renderer/XHTML.pm deleted file mode 100644 index af98521..0000000 --- a/lib/Reaction/UI/Renderer/XHTML.pm +++ /dev/null @@ -1,89 +0,0 @@ -package Reaction::UI::Renderer::XHTML; - -use strict; -use base qw/Catalyst::View::TT Reaction::Object/; -use Reaction::Class; - -use HTML::Entities; - -__PACKAGE__->config({ - CATALYST_VAR => 'ctx', - RECURSION => 1, -}); - -sub render_window { - my ($self, $window) = @_; - my $root_vp = $window->focus_stack->vp_head; - confess "Can't flush view for window with empty focus stack" - unless defined($root_vp); - $self->render_viewport($window, $root_vp); -} - -sub render_viewport { - my ($self, $window, $vp) = @_; - my $ctx = $window->ctx; - my %args = ( - self => $vp, - ctx => $ctx, - window => $window, - type => $vp->layout - ); - unless (length $args{type}) { - my $type = (split('::', ref($vp)))[-1]; - $args{type} = lc($type); - } - return $self->render($ctx, 'component', \%args); -} - -around 'render' => sub { - my $super = shift; - my ($self,$args) = @_[0,3]; - local $self->template->{SERVICE}{CONTEXT}{BLKSTACK}; - local $self->template->{SERVICE}{CONTEXT}{BLOCKS}; - $args->{process_attrs} = \&process_attrs; - return $super->(@_); -}; - -sub process_attrs{ - my $attrs = shift; - return $attrs unless ref $attrs eq 'HASH'; - - my @processed_attrs; - while( my($k,$v) = each(%$attrs) ){ - my $enc_v = $v; - next if ($enc_v eq ""); - if ($k eq 'class' && ref $v eq 'ARRAY'){ - $enc_v = join ' ', map { encode_entities($_) } @$v; - } elsif ($k eq 'style' && ref $v eq 'HASH'){ - $enc_v = join '; ', map{ "${_}: ".encode_entities($v->{$_}) } keys %{$v}; - } - push(@processed_attrs, "${k}=\"${enc_v}\""); - } - - return ' '.join ' ', @processed_attrs if (scalar(@processed_attrs) > 0); - return; -} - -1; - -=head1 NAME - -Reaction::UI::Renderer::XHTML - -=head1 DESCRIPTION - -=head1 METHODS - -=head2 render - -=head2 process_attrs - -=head1 AUTHORS - -See L<Reaction::Class> for authors. - -=head1 LICENSE - -See L<Reaction::Class> for the license. - -=cut diff --git a/lib/Reaction/UI/Skin.pm b/lib/Reaction/UI/Skin.pm index 7f3f1ca..a875366 100644 --- a/lib/Reaction/UI/Skin.pm +++ b/lib/Reaction/UI/Skin.pm @@ -5,14 +5,21 @@ use Reaction::Class; # declaring dependencies use Reaction::UI::LayoutSet; use Reaction::UI::RenderingContext; +use File::ShareDir; use aliased 'Path::Class::Dir'; class Skin which { has '_layout_set_cache' => (is => 'ro', default => sub { {} }); + has '_widget_class_cache' => (is => 'ro', default => sub { {} }); - has 'skin_base_path' => (is => 'ro', isa => Dir, required => 1); + has 'name' => (is => 'ro', isa => 'Str', required => 1); + has 'skin_dir' => (is => 'rw', isa => Dir, lazy_fail => 1); + + has 'widget_search_path' => ( + is => 'rw', isa => 'ArrayRef', requred => 1, default => sub { [] } + ); has 'view' => ( is => 'ro', required => 1, weak_ref => 1, @@ -24,51 +31,83 @@ class Skin which { ); sub BUILD { - my ($self) = @_; - $self->_load_skin_config; + my ($self, $args) = @_; + $self->_find_skin_dir($args); + $self->_load_skin_config($args); } - implements '_load_skin_config' => as { - my ($self) = @_; - my $base = $self->skin_base_path; + implements '_find_skin_dir' => as { + my ($self, $args) = @_; + my $skin_name = $self->name; + if ($skin_name =~ s!^/(.*?)/!!) { + my $dist = $1; + $args->{skin_base_dir} = + Dir->new(File::ShareDir::dist_dir($dist)) + ->subdir('skin'); + } + my $base = $args->{skin_base_dir}->subdir($skin_name); confess "No such skin base directory ${base}" unless -d $base; - if (-e (my $conf_file = $base->file('skin.conf'))) { - # we get [ { $file => $conf } ] - my ($cfg) = values %{ - Config::Any->load_files({ - files => [ $conf_file ], use_ext => 1 - })->[0] - }; - if (my $super_name = $cfg->{extends}) { - my $super_dir = $base->parent->subdir($super_name); - my $super = $self->new( - view => $self->view, skin_base_path => $super_dir - ); - $self->super($super); - } + $self->skin_dir($base); + }; + + implements '_load_skin_config' => as { + my ($self, $args) = @_; + my $base = $self->skin_dir; + my $lst = sub { (ref $_[0] eq 'ARRAY') ? $_[0] : [$_[0]] }; + my @files = ( + $args->{skin_base_dir}->file('defaults.conf'), $base->file('skin.conf') + ); + # we get [ { $file => $conf }, ... ] + my %cfg = (map { %{(values %{$_})[0]} } + @{Config::Any->load_files({ + files => [ grep { -e $_ } @files ], + use_ext => 1, + })} + ); + if (my $super_name = $cfg{extends}) { + my $super = $self->new( + name => $super_name, + view => $self->view, + skin_base_dir => $args->{skin_base_dir}, + ); + $self->super($super); + } + if (exists $cfg{widget_search_path}) { + $self->widget_search_path($lst->($cfg{widget_search_path})); + } else { + confess "No widget_search_path in defaults.conf or skin.conf" + ." and no search path provided from super skin" + unless $self->full_widget_search_path; } } implements 'create_layout_set' => as { my ($self, $name) = @_; + $self->_create_layout_set($name, [], $self); + }; + + implements '_create_layout_set' => as { + my ($self, $name, $tried, $top_skin) = @_; if (my $path = $self->layout_path_for($name)) { return $self->layout_set_class->new( $self->layout_set_args_for($name), source_file => $path, + top_skin => $top_skin, ); } + $tried = [ @{$tried}, $self->our_path_for_type('layout') ]; if ($self->has_super) { - return $self->super->create_layout_set($name); + return $self->super->_create_layout_set($name, $tried, $top_skin); } - confess "Couldn't find layout set file for ${name}"; + confess "Couldn't find layout set file for ${name}, tried " + .join(', ', @$tried); }; implements 'layout_set_args_for' => as { my ($self, $name) = @_; return ( name => $name, - view => $self->view, skin => $self, ($self->has_super ? (next_skin => $self->super) : ()), $self->view->layout_set_args_for($name), @@ -78,7 +117,7 @@ class Skin which { implements 'layout_path_for' => as { my ($self, $layout) = @_; my $file_name = join( - '.', $layout, $self->layout_set_class->file_extension + '.', $layout, $self->view->layout_set_file_extension ); my $path = $self->our_path_for_type('layout') ->file($file_name); @@ -98,7 +137,38 @@ class Skin which { implements 'our_path_for_type' => as { my ($self, $type) = @_; - return $self->skin_base_path->subdir($type) + return $self->skin_dir->subdir($type) + }; + + implements 'full_widget_search_path' => as { + my ($self) = @_; + return ( + @{$self->widget_search_path}, + ($self->has_super ? $self->super->full_widget_search_path : ()) + ); + }; + + implements 'widget_class_for' => as { + my ($self, $layout_set) = @_; + my $base = $self->blessed; + my $widget_type = $layout_set->widget_type; + return $self->_widget_class_cache->{$widget_type} ||= do { + + my @search_path = $self->full_widget_search_path; + my @haystack = map {join('::', $_, $widget_type)} @search_path; + + foreach my $class (@haystack) { + #if the class is already loaded skip the call to Installed etc. + return $class if Class::MOP::is_class_loaded($class); + next unless Class::Inspector->installed($class); + + my $ok = eval { Class::MOP::load_class($class) }; + confess("Failed to load widget '${class}': $@") if $@; + return $class; + } + confess "Couldn't locate widget '${widget_type}' for layout " + ."'${\$layout_set->name}': tried: ".join(", ", @haystack); + }; }; }; diff --git a/lib/Reaction/UI/View.pm b/lib/Reaction/UI/View.pm index 7a1ebc5..358fcf1 100644 --- a/lib/Reaction/UI/View.pm +++ b/lib/Reaction/UI/View.pm @@ -10,7 +10,6 @@ use aliased 'Path::Class::Dir'; class View which { - has '_widget_class_cache' => (is => 'ro', default => sub { {} }); has '_widget_cache' => (is => 'ro', default => sub { {} }); has '_layout_set_cache' => (is => 'ro', default => sub { {} }); @@ -42,8 +41,8 @@ class View which { my ($self) = @_; Skin->new( name => $self->skin_name, view => $self, - skin_base_path => # returns a File, not a Dir. Thanks, Catalyst. - Dir->new($self->app->path_to('share', 'skin', $self->skin_name)), + # path_to returns a File, not a Dir. Thanks, Catalyst. + skin_base_dir => Dir->new($self->app->path_to('share', 'skin')), ); }; @@ -77,38 +76,6 @@ class View which { ); }; - implements 'widget_class_for' => as { - my ($self, $layout_set) = @_; - my $base = $self->blessed; - my $widget_type = $layout_set->widget_type; - my $app_name = ref $self->app || $self->app; - return $self->_widget_class_cache->{$widget_type} ||= do { - - my @search_path = ($base, $app_name, 'Reaction::UI'); - my @haystack = map { join('::', $_, 'Widget', $widget_type) } - @search_path; - my $found; - foreach my $class (@haystack) { - #here we should throw if exits and error instead of eating the error - #only next when !exists - eval { Class::MOP::load_class($class) }; - #$@ ? next : return $class; - #warn "Loaded ${class}" unless $@; - #warn "Boom loading ${class}: $@" if $@; - unless ($@) { - $found = $class; - last; - } - } - unless ($found) { - confess "Couldn't load widget '${widget_type}'" - ." for layout '${\$layout_set->name}':" - ." tried: ".join(", ", @haystack); - } - $found; - }; - }; - implements 'layout_set_for' => as { my ($self, $vp) = @_; #print STDERR "Getting layoutset for VP ".(ref($vp) || "SC:".$vp)."\n"; @@ -126,6 +93,10 @@ class View which { return $cache->{$lset_name} ||= $self->create_layout_set($lset_name); }; + implements 'layout_set_file_extension' => as { + confess View." is abstract, you must subclass it"; + }; + implements 'find_related_class' => as { my ($self, $rel) = @_; my $own_class = ref($self) || $self; diff --git a/lib/Reaction/UI/View/TT.pm b/lib/Reaction/UI/View/TT.pm index 46d3135..af282e4 100644 --- a/lib/Reaction/UI/View/TT.pm +++ b/lib/Reaction/UI/View/TT.pm @@ -19,10 +19,7 @@ class TT is View, which { return (super(), tt_object => $self->_tt); }; - overrides 'rendering_context_args_for' => sub { - my ($self, %args) = @_; - return (); - }; + implements layout_set_file_extension => as { 'tt' }; implements 'serve_static_file' => as { my ($self, $c, $args) = @_; diff --git a/lib/Reaction/UI/ViewPort.pm b/lib/Reaction/UI/ViewPort.pm index 7d24efc..4f12b55 100644 --- a/lib/Reaction/UI/ViewPort.pm +++ b/lib/Reaction/UI/ViewPort.pm @@ -3,6 +3,8 @@ package Reaction::UI::ViewPort; use Reaction::Class; use Scalar::Util qw/blessed/; +sub DEBUG_EVENTS () { $ENV{REACTION_UI_VIEWPORT_DEBUG_EVENTS} } + class ViewPort which { has location => (isa => 'Str', is => 'rw', required => 1); @@ -89,8 +91,13 @@ class ViewPort which { my ($self, $events) = @_; foreach my $event ($self->accept_events) { if (exists $events->{$event}) { - #my $name = eval{$self->name}; - #$self->ctx->log->debug("Applying Event: $event on $name with value: ". $events->{$event}); + if (DEBUG_EVENTS) { + my $name = join(' at ', ref($self), $self->location); + $self->ctx->log->debug( + "Applying Event: $event on $name with value: " + .$events->{$event} + ); + } $self->$event($events->{$event}); } } diff --git a/lib/Reaction/UI/ViewPort/Action.pm b/lib/Reaction/UI/ViewPort/Action.pm index 20ae4ea..3468fab 100644 --- a/lib/Reaction/UI/ViewPort/Action.pm +++ b/lib/Reaction/UI/ViewPort/Action.pm @@ -2,6 +2,10 @@ package Reaction::UI::ViewPort::Action; use Reaction::Class; +use aliased 'Reaction::UI::ViewPort::Object'; + +BEGIN { *DEBUG_EVENTS = \&Reaction::UI::ViewPort::DEBUG_EVENTS; } + use aliased 'Reaction::UI::ViewPort::Field::Mutable::Text'; use aliased 'Reaction::UI::ViewPort::Field::Mutable::Array'; use aliased 'Reaction::UI::ViewPort::Field::Mutable::String'; @@ -16,7 +20,7 @@ use aliased 'Reaction::UI::ViewPort::Field::Mutable::ChooseMany'; use aliased 'Reaction::UI::ViewPort::Field::Mutable::File'; #use aliased 'Reaction::UI::ViewPort::Field::Mutable::TimeRange'; -class Action is 'Reaction::UI::ViewPort::Object', which { +class Action is Object, which { has model => (is => 'ro', isa => 'Reaction::InterfaceModel::Action', required => 1); #has '+model' => (isa => 'Reaction::InterfaceModel::Action'); @@ -44,11 +48,26 @@ class Action is 'Reaction::UI::ViewPort::Object', which { implements can_apply => as { my ($self) = @_; foreach my $field ( @{ $self->fields } ) { - return 0 if $field->needs_sync; + if ($field->needs_sync) { + if (DEBUG_EVENTS) { + $self->ctx->log->debug( + "Failing out of can_apply on ${\ref($self)} at ${\$self->location}" + ." because field for ${\$field->attribute->name} needs sync" + ); + } + } # if e.g. a datetime field has an invalid value that can't be re-assembled # into a datetime object, the action may be in a consistent state but # not synchronized from the fields; in this case, we must not apply } + if (DEBUG_EVENTS) { + my $ret = $self->model->can_apply; + $self->ctx->log->debug( + "model can_apply returned ${ret}" + ." on ${\ref($self)} at ${\$self->location}" + ); + return $ret; + } return $self->model->can_apply; }; @@ -121,7 +140,7 @@ class Action is 'Reaction::UI::ViewPort::Object', which { $self->_build_simple_field(attribute => $attr, class => Boolean, %$args); }; - implements _build_fields_for_type_SimpleStr => as { + implements _build_fields_for_type_Reaction_Types_Core_SimpleStr => as { my ($self, $attr, $args) = @_; $self->_build_simple_field(attribute => $attr, class => String, %$args); }; @@ -140,7 +159,7 @@ class Action is 'Reaction::UI::ViewPort::Object', which { } }; - implements _build_fields_for_type_Password => as { + implements _build_fields_for_type_Reaction_Types_Core_Password => as { my ($self, $attr, $args) = @_; $self->_build_simple_field(attribute => $attr, class => Password, %$args); }; @@ -171,7 +190,7 @@ class Action is 'Reaction::UI::ViewPort::Object', which { ( attribute => $attr, class => Array, - layout => 'interface_model/field/mutable/array/hidden', + layout => 'field/mutable/hidden_array', %$args); } }; diff --git a/lib/Reaction/UI/ViewPort/Collection/Grid/Member.pm b/lib/Reaction/UI/ViewPort/Collection/Grid/Member.pm index bbe1c49..ccfc02a 100644 --- a/lib/Reaction/UI/ViewPort/Collection/Grid/Member.pm +++ b/lib/Reaction/UI/ViewPort/Collection/Grid/Member.pm @@ -24,7 +24,7 @@ class Member is 'Reaction::UI::ViewPort::Object', which { $_[0]->(@_[1,2], { layout => 'value/string', %{ $_[3] || {} } }) }; - around _build_fields_for_type_SimpleStr => sub { + around _build_fields_for_type_Reaction_Types_Core_SimpleStr => sub { $_[0]->(@_[1,2], { layout => 'value/string', %{ $_[3] || {} } }) }; @@ -36,7 +36,7 @@ class Member is 'Reaction::UI::ViewPort::Object', which { $_[0]->(@_[1,2], { layout => 'value/date_time', %{ $_[3] || {} } }) }; - around _build_fields_for_type_Password => sub { return }; + around _build_fields_for_type_Reaction_Types_Core_Password => sub { return }; around _build_fields_for_type_ArrayRef => sub { return }; around _build_fields_for_type_Reaction_InterfaceModel_Collection => sub { return }; diff --git a/lib/Reaction/UI/ViewPort/Field.pm b/lib/Reaction/UI/ViewPort/Field.pm index 09857ff..f6da895 100644 --- a/lib/Reaction/UI/ViewPort/Field.pm +++ b/lib/Reaction/UI/ViewPort/Field.pm @@ -14,8 +14,6 @@ class Field is 'Reaction::UI::ViewPort', which { has model => (is => 'ro', isa => Object, required => 1); has attribute => (is => 'ro', isa => ParameterAttribute, required => 1); - implements adopt_value => as {}; - implements _build_name => as { shift->attribute->name }; implements _build_label => as { @@ -59,6 +57,10 @@ class Field is 'Reaction::UI::ViewPort', which { implements _empty_string_value => as { '' }; + implements value_is_required => as { + shift->attribute->is_required; + }; + }; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/ChooseMany.pm b/lib/Reaction/UI/ViewPort/Field/ChooseMany.pm deleted file mode 100644 index 8074fd8..0000000 --- a/lib/Reaction/UI/ViewPort/Field/ChooseMany.pm +++ /dev/null @@ -1,110 +0,0 @@ -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'); - - 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); - } - }; - - implements _empty_value => as { [] }; - - implements is_current_value => as { - my ($self, $check_value) = @_; - my @our_values = @{$self->value||[]}; - $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_value_choices => as { - my $self = shift; - my @all = grep { $self->is_current_value($_->{value}) } @{$self->value_choices}; - return [ @all ]; - }; - - implements available_value_choices => as { - my $self = shift; - my @all = grep { !$self->is_current_value($_->{value}) } @{$self->value_choices}; - return [ @all ]; - }; - - around handle_events => sub { - my $orig = shift; - my ($self, $events) = @_; - my $ev_value = $listify->($events->{value}); - if (delete $events->{add_all_values}) { - $events->{value} = [map {$self->obj_to_str($_)} @{$self->valid_values}]; - } elsif (exists $events->{add_values} && delete $events->{do_add_values}) { - my $add = $listify->(delete $events->{add_values}); - $events->{value} = [ @{$ev_value}, @$add ]; - } elsif (delete $events->{remove_all_values}) { - $events->{value} = []; - }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} ]; - } - 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 diff --git a/lib/Reaction/UI/ViewPort/Field/ChooseOne.pm b/lib/Reaction/UI/ViewPort/Field/ChooseOne.pm deleted file mode 100644 index a44314e..0000000 --- a/lib/Reaction/UI/ViewPort/Field/ChooseOne.pm +++ /dev/null @@ -1,122 +0,0 @@ -package Reaction::UI::ViewPort::Field::ChooseOne; - -use Reaction::Class; -use URI; -use Scalar::Util 'blessed'; - -class ChooseOne is 'Reaction::UI::ViewPort::Field', which { - - #has '+layout' => (default => 'select'); - - 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' }, - ); - - around value => sub { - my $orig = shift; - my $self = shift; - if (@_) { - my $value = shift; - if (defined $value) { - if (!ref $value) { - $value = $self->str_to_ident($value); - } - my $checked = $self->attribute->check_valid_value($self->action, $value); - confess "${value} is not a valid value" unless defined($checked); - $value = $checked; - } - $orig->($self, $value); - } else { - $orig->($self); - } - }; - - implements _build_valid_values => as { - my $self = shift; - return [ $self->attribute->all_valid_values($self->action) ]; - }; - - 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 { - my ($self, $check_value) = @_; - my $our_value = $self->value; - return unless ref($our_value); - $check_value = $self->obj_to_str($check_value) if ref($check_value); - return $self->obj_to_str($our_value) eq $check_value; - }; - - implements str_to_ident => as { - my ($self, $str) = @_; - my $u = URI->new('','http'); - $u->query($str); - return { $u->query_form }; - }; - - implements obj_to_str => as { - my ($self, $obj) = @_; - return $obj unless ref($obj); - confess "${obj} not an object" unless blessed($obj); - my $ident = $obj->ident_condition; - my $u = URI->new('', 'http'); - $u->query_form(%$ident); - 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; - -=head1 NAME - -Reaction::UI::ViewPort::Field::ChooseOne - -=head1 DESCRIPTION - -=head1 METHODS - -=head2 is_current_value - -=head2 value - -=head2 valid_values - -=head2 valid_value_names - -=head2 value_to_name_map - -=head2 name_to_value_map - -=head2 str_to_ident - -=head2 obj_to_str - -=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 diff --git a/lib/Reaction/UI/ViewPort/Field/Collection.pm b/lib/Reaction/UI/ViewPort/Field/Collection.pm index 8c46952..b772e02 100644 --- a/lib/Reaction/UI/ViewPort/Field/Collection.pm +++ b/lib/Reaction/UI/ViewPort/Field/Collection.pm @@ -6,6 +6,18 @@ use aliased 'Reaction::UI::ViewPort::Field::Array'; class Collection is Array, which { + has value => ( + is => 'rw', lazy_build => 1, + isa => 'Reaction::InterfaceModel::Collection' + ); + + implements _build_value_names => as { + my $self = shift; + my $meth = $self->value_map_method; + my @names = map { blessed($_) ? $_->$meth : $_ } $self->value->members; + return [ sort @names ]; + }; + }; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/DateTime.pm b/lib/Reaction/UI/ViewPort/Field/DateTime.pm index e89fc47..50d26cf 100644 --- a/lib/Reaction/UI/ViewPort/Field/DateTime.pm +++ b/lib/Reaction/UI/ViewPort/Field/DateTime.pm @@ -6,7 +6,7 @@ use Reaction::Types::DateTime; use aliased 'Reaction::UI::ViewPort::Field'; class DateTime is Field, which { - has '+value' => (isa => 'DateTime'); + has '+value' => (isa => DateTime); has value_string_default_format => ( isa => 'Str', is => 'rw', required => 1, default => sub { "%F %H:%M:%S" } diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/Array.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/Array.pm index 49e629b..0bf0104 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/Array.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/Array.pm @@ -11,7 +11,6 @@ class Array is 'Reaction::UI::ViewPort::Field::Array', which { return $orig->($self) unless @_; my $value = defined $_[0] ? $_[0] : []; $orig->($self, (ref $value eq 'ARRAY' ? $value : [ $value ])); - $self->sync_to_action; }; }; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/Boolean.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/Boolean.pm index 5293b11..633f910 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/Boolean.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/Boolean.pm @@ -3,7 +3,12 @@ package Reaction::UI::ViewPort::Field::Mutable::Boolean; use Reaction::Class; class Boolean is 'Reaction::UI::ViewPort::Field::Boolean', which{ - does 'Reaction::UI::ViewPort::Field::Role::Mutable'; + does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; + + implements adopt_value_string => as { + my ($self) = @_; + $self->value($self->value_string); + }; implements BUILD => as { my($self) = @_; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseMany.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseMany.pm index f799160..b3dca44 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseMany.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseMany.pm @@ -28,14 +28,16 @@ class ChooseMany is 'Reaction::UI::ViewPort::Field', which { $orig->($self, $checked); }; + around _value_string_from_value => sub { + my $orig = shift; my $self = shift; - join ", ", (map {$self->obj_to_name($_->{value}) } @{ $self->current_value_choices }) + join(", ", (map {$self->obj_to_name($_->{value}) } @{ $self->current_value_choices })); }; implements is_current_value => as { my ($self, $check_value) = @_; - return $self->_model_has_value; + return unless $self->_model_has_value; my @our_values = @{$self->value || []}; $check_value = $self->obj_to_str($check_value) if ref($check_value); return grep { $self->obj_to_str($_) eq $check_value } @our_values; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseOne.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseOne.pm index f16ea66..9033528 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseOne.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/ChooseOne.pm @@ -5,28 +5,23 @@ use Scalar::Util (); class ChooseOne is 'Reaction::UI::ViewPort::Field', which { - does 'Reaction::UI::ViewPort::Field::Role::Mutable'; + does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; does 'Reaction::UI::ViewPort::Field::Role::Choices'; - around value => sub { - my $orig = shift; - my $self = shift; - return $orig->($self) unless @_; - my $value = shift; - if (defined $value) { - $value = $self->str_to_ident($value) if (!ref $value); - my $attribute = $self->attribute; - my $checked = $attribute->check_valid_value($self->model, $value); - unless (defined $checked) { - require Data::Dumper; - my $serialised = Data::Dumper->new([ $value ])->Indent(0)->Dump; - $serialised =~ s/^\$VAR1 = //; $serialised =~ s/;$//; - confess "${serialised} is not a valid value for ${\$attribute->name} on " - ."${\$attribute->associated_class->name}"; - } - $value = $checked; + implements adopt_value_string => as { + my ($self) = @_; + my $value = $self->value_string; + $value = $self->str_to_ident($value) if (!ref $value); + my $attribute = $self->attribute; + my $checked = $attribute->check_valid_value($self->model, $value); + unless (defined $checked) { + require Data::Dumper; + my $serialised = Data::Dumper->new([ $value ])->Indent(0)->Dump; + $serialised =~ s/^\$VAR1 = //; $serialised =~ s/;$//; + confess "${serialised} is not a valid value for ${\$attribute->name} on " + ."${\$attribute->associated_class->name}"; } - $orig->($self, $value); + $self->value($checked); }; around _value_string_from_value => sub { @@ -47,7 +42,6 @@ class ChooseOne is 'Reaction::UI::ViewPort::Field', which { return $self->obj_to_str($our_value) eq $check_value; }; - }; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/DateTime.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/DateTime.pm index 71428e5..3b38d26 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/DateTime.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/DateTime.pm @@ -7,10 +7,7 @@ use DateTime; class 'Reaction::UI::ViewPort::Field::Mutable::DateTime', is 'Reaction::UI::ViewPort::Field::DateTime', which { - does 'Reaction::UI::ViewPort::Field::Role::Mutable'; - - has value_string => - ( is => 'rw', isa => 'Str', lazy_build => 1, trigger_adopt('value_string') ); + does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; implements adopt_value_string => as { my ($self) = @_; @@ -21,13 +18,9 @@ class 'Reaction::UI::ViewPort::Field::Mutable::DateTime', $self->value($dt); } else { $self->message("Could not parse date or time"); - $self->clear_value; - $self->needs_sync(1); } }; - around accept_events => sub { ('value_string', shift->(@_)) }; - }; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/Integer.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/Integer.pm index 4882f1e..958150a 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/Integer.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/Integer.pm @@ -3,7 +3,13 @@ package Reaction::UI::ViewPort::Field::Mutable::Integer; use Reaction::Class; class Integer is 'Reaction::UI::ViewPort::Field::Integer', which { - does 'Reaction::UI::ViewPort::Field::Role::Mutable'; + does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; + + implements adopt_value_string => as { + my ($self) = @_; + $self->value($self->value_string); + }; + }; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/Number.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/Number.pm index 41308f3..d2be595 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/Number.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/Number.pm @@ -3,7 +3,12 @@ package Reaction::UI::ViewPort::Field::Mutable::Number; use Reaction::Class; class Number is 'Reaction::UI::ViewPort::Field::Number', which { - does 'Reaction::UI::ViewPort::Field::Role::Mutable'; + does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; + + implements adopt_value_string => as { + my ($self) = @_; + $self->value($self->value_string); + }; }; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/Password.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/Password.pm index 79319f2..d009698 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/Password.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/Password.pm @@ -3,7 +3,13 @@ package Reaction::UI::ViewPort::Field::Mutable::Password; use Reaction::Class; class Password is 'Reaction::UI::ViewPort::Field::String', which { - does 'Reaction::UI::ViewPort::Field::Role::Mutable'; + does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; + + implements adopt_value_string => as { + my ($self) = @_; + $self->value($self->value_string); + }; + }; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/String.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/String.pm index 758673c..11d5d14 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/String.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/String.pm @@ -3,7 +3,13 @@ package Reaction::UI::ViewPort::Field::Mutable::String; use Reaction::Class; class String is 'Reaction::UI::ViewPort::Field::String', which { - does 'Reaction::UI::ViewPort::Field::Role::Mutable'; + does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; + + implements adopt_value_string => as { + my ($self) = @_; + $self->value($self->value_string); + }; + }; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Mutable/Text.pm b/lib/Reaction/UI/ViewPort/Field/Mutable/Text.pm index 31d3b04..09d2127 100644 --- a/lib/Reaction/UI/ViewPort/Field/Mutable/Text.pm +++ b/lib/Reaction/UI/ViewPort/Field/Mutable/Text.pm @@ -3,7 +3,13 @@ package Reaction::UI::ViewPort::Field::Mutable::Text; use Reaction::Class; class Text is 'Reaction::UI::ViewPort::Field::Text', which { - does 'Reaction::UI::ViewPort::Field::Role::Mutable'; + does 'Reaction::UI::ViewPort::Field::Role::Mutable::Simple'; + + implements adopt_value_string => as { + my ($self) = @_; + $self->value($self->value_string); + }; + }; 1; diff --git a/lib/Reaction/UI/ViewPort/Field/Password.pm b/lib/Reaction/UI/ViewPort/Field/Password.pm index bc86341..a80e71a 100644 --- a/lib/Reaction/UI/ViewPort/Field/Password.pm +++ b/lib/Reaction/UI/ViewPort/Field/Password.pm @@ -2,9 +2,11 @@ package Reaction::UI::ViewPort::Field::Password; use Reaction::Class; +use Reaction::Types::Core qw(SimpleStr); + class Password is 'Reaction::UI::ViewPort::Field::String', which { - has '+value' => (isa => 'SimpleStr'); + has '+value' => (isa => SimpleStr); #has '+layout' => (default => 'password'); }; diff --git a/lib/Reaction/UI/ViewPort/Field/Role/Mutable.pm b/lib/Reaction/UI/ViewPort/Field/Role/Mutable.pm index 8690603..42899c0 100644 --- a/lib/Reaction/UI/ViewPort/Field/Role/Mutable.pm +++ b/lib/Reaction/UI/ViewPort/Field/Role/Mutable.pm @@ -9,9 +9,16 @@ role Mutable, which { 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')); + has value => ( + is => 'rw', lazy_build => 1, trigger_adopt('value'), + clearer => 'clear_value', + ); has needs_sync => (is => 'rw', isa => 'Int', default => 0); - has message => (is => 'rw', isa => 'Str'); + has message => (is => 'rw', isa => 'Str'); + + after clear_value => sub { + shift->needs_sync(1); + }; implements adopt_value => as { my ($self) = @_; @@ -20,22 +27,33 @@ role Mutable, which { implements sync_to_action => as { my ($self) = @_; - return unless $self->needs_sync && $self->has_value; + return unless $self->needs_sync; my $attr = $self->attribute; - my $writer = $attr->get_write_method; - confess "No writer for attribute" unless defined($writer); - - my $value = $self->value; - if (my $tc = $attr->type_constraint) { - $value = $tc->coercion->coerce($value) if ($tc->has_coercion); - #my $error = $tc->validate($self->value); # should we be checking against $value? - my $error = $tc->validate($value); - if (defined $error) { - $self->message($error); - return; + + if ($self->has_value) { + my $value = $self->value; + if (my $tc = $attr->type_constraint) { + $value = $tc->coercion->coerce($value) if ($tc->has_coercion); + #my $error = $tc->validate($self->value); # should we be checking against $value? + my $error = $tc->validate($value); + if (defined $error) { + $self->message($error); + return; + } + } + my $writer = $attr->get_write_method; + confess "No writer for attribute" unless defined($writer); + $self->model->$writer($value); + } else { + my $predicate = $attr->predicate; + confess "No predicate for attribute" unless defined($predicate); + if ($self->model->$predicate) { + my $clearer = $attr->clearer; + confess "${predicate} returned true but no clearer for attribute" + unless defined($clearer); + $self->model->$clearer; } } - $self->model->$writer($value); $self->needs_sync(0); }; diff --git a/lib/Reaction/UI/ViewPort/Field/Role/Mutable/Simple.pm b/lib/Reaction/UI/ViewPort/Field/Role/Mutable/Simple.pm new file mode 100644 index 0000000..66fa464 --- /dev/null +++ b/lib/Reaction/UI/ViewPort/Field/Role/Mutable/Simple.pm @@ -0,0 +1,36 @@ +package Reaction::UI::ViewPort::Field::Role::Mutable::Simple; + +use Reaction::Role; + +use aliased 'Reaction::UI::ViewPort::Field::Role::Mutable'; + +role Simple which { + + does Mutable; + + has value_string => ( + is => 'rw', lazy_build => 1, trigger_adopt('value_string'), + clearer => 'clear_value', + ); + + around value_string => sub { + my $orig = shift; + my $self = shift; + if (@_ && defined($_[0]) && !ref($_[0]) && $_[0] eq '' + && !$self->value_is_required) { + $self->clear_value; + return undef; + } + return $self->$orig(@_); + }; + + # the user needs to implement this because, honestly, you're always going + # to need to do something custom and the only common thing really is + # "you probably set $self->value at the end" + requires 'adopt_value_string'; + + around accept_events => sub { ('value_string', shift->(@_)) }; + +}; + +1; diff --git a/lib/Reaction/UI/ViewPort/Field/TimeRange.pm b/lib/Reaction/UI/ViewPort/Field/TimeRange.pm index a63fdf4..ccf6e65 100644 --- a/lib/Reaction/UI/ViewPort/Field/TimeRange.pm +++ b/lib/Reaction/UI/ViewPort/Field/TimeRange.pm @@ -1,14 +1,14 @@ package Reaction::UI::ViewPort::Field::TimeRange; use Reaction::Class; -use Reaction::Types::DateTime; +use Reaction::Types::DateTime qw(SpanSet); use DateTime; use DateTime::SpanSet; use Time::ParseDate (); class TimeRange is 'Reaction::UI::ViewPort::Field', which { - has '+value' => (isa => 'SpanSet'); + has '+value' => (isa => SpanSet); #has '+layout' => (default => 'timerange'); diff --git a/lib/Reaction/UI/ViewPort/Object.pm b/lib/Reaction/UI/ViewPort/Object.pm index 765b601..5f71884 100644 --- a/lib/Reaction/UI/ViewPort/Object.pm +++ b/lib/Reaction/UI/ViewPort/Object.pm @@ -144,7 +144,7 @@ class Object is 'Reaction::UI::ViewPort', which { }; #XXX - implements _build_fields_for_type_Password => as { return }; + implements _build_fields_for_type_Reaction_Types_Core_Password => as { return }; implements _build_fields_for_type_Str => as { my ($self, $attr, $args) = @_; @@ -152,7 +152,7 @@ class Object is 'Reaction::UI::ViewPort', which { $self->_build_simple_field(attribute => $attr, class => String, %$args); }; - implements _build_fields_for_type_SimpleStr => as { + implements _build_fields_for_type_Reaction_Types_Core_SimpleStr => as { my ($self, $attr, $args) = @_; $self->_build_simple_field(attribute => $attr, class => String, %$args); }; diff --git a/lib/Reaction/UI/ViewPort/SiteLayout.pm b/lib/Reaction/UI/ViewPort/SiteLayout.pm index 4560dc6..a8ee133 100644 --- a/lib/Reaction/UI/ViewPort/SiteLayout.pm +++ b/lib/Reaction/UI/ViewPort/SiteLayout.pm @@ -9,6 +9,11 @@ class SiteLayout is ViewPort, which { has 'static_base_uri' => (isa => 'Str', is => 'rw', lazy_fail => 1); + has 'meta_info' => ( + is => 'rw', isa => 'HashRef', + required => '1', default => sub { {} } + ); + }; 1; diff --git a/lib/Reaction/UI/Widget/Field/Mutable.pm b/lib/Reaction/UI/Widget/Field/Mutable.pm index 5c245d8..7547799 100644 --- a/lib/Reaction/UI/Widget/Field/Mutable.pm +++ b/lib/Reaction/UI/Widget/Field/Mutable.pm @@ -5,8 +5,8 @@ use Reaction::UI::WidgetClass; class Mutable is 'Reaction::UI::Widget::Field', which { before fragment widget { - arg 'field_id' => event_id 'value'; - arg 'field_name' => event_id 'value' unless defined $_{field_name}; + arg 'field_id' => event_id 'value_string'; + arg 'field_name' => event_id 'value_string' unless defined $_{field_name}; arg 'field_type' => 'text'; }; diff --git a/lib/Reaction/UI/Widget/Field/Mutable/ChooseMany.pm b/lib/Reaction/UI/Widget/Field/Mutable/ChooseMany.pm index 2f938d6..4078bdc 100644 --- a/lib/Reaction/UI/Widget/Field/Mutable/ChooseMany.pm +++ b/lib/Reaction/UI/Widget/Field/Mutable/ChooseMany.pm @@ -15,6 +15,7 @@ class ChooseMany is 'Reaction::UI::Widget::Field::Mutable', which { implements fragment current_values { my $current_choices = $_{viewport}->current_value_choices; if( @$current_choices ){ + arg field_name => event_id 'value'; render hidden_value => over $current_choices; } else { arg field_name => event_id 'no_current_value'; diff --git a/lib/Reaction/UI/Widget/Field/Mutable/ChooseOne.pm b/lib/Reaction/UI/Widget/Field/Mutable/ChooseOne.pm index 68255bf..b0ab7b3 100644 --- a/lib/Reaction/UI/Widget/Field/Mutable/ChooseOne.pm +++ b/lib/Reaction/UI/Widget/Field/Mutable/ChooseOne.pm @@ -5,7 +5,7 @@ use Reaction::UI::WidgetClass; class ChooseOne is 'Reaction::UI::Widget::Field::Mutable', which { implements fragment option_is_required { - if ($_{viewport}->attribute->is_required) { + if ($_{viewport}->value_is_required) { render 'option_is_required_yes'; } else { render 'option_is_required_no'; diff --git a/lib/Reaction/UI/Widget/Field/Mutable/Password.pm b/lib/Reaction/UI/Widget/Field/Mutable/Password.pm index c11a909..890770e 100644 --- a/lib/Reaction/UI/Widget/Field/Mutable/Password.pm +++ b/lib/Reaction/UI/Widget/Field/Mutable/Password.pm @@ -7,6 +7,7 @@ class Password is 'Reaction::UI::Widget::Field::Mutable', which { around fragment widget { call_next; arg field_type => 'password'; + arg field_value => ''; # no sending password to user. really. }; }; diff --git a/lib/Reaction/UI/Widget/SiteLayout.pm b/lib/Reaction/UI/Widget/SiteLayout.pm index 73406a9..dc9574a 100644 --- a/lib/Reaction/UI/Widget/SiteLayout.pm +++ b/lib/Reaction/UI/Widget/SiteLayout.pm @@ -10,6 +10,15 @@ class SiteLayout is Container, which { arg title => $_{viewport}->title; }; + implements fragment meta_info { + render meta_member => over [keys %{$_{viewport}->meta_info}]; + }; + + implements fragment meta_member { + arg 'meta_name' => $_; + arg 'meta_value' => $_{viewport}->meta_info->{$_}; + }; + }; 1; diff --git a/lib/Reaction/UI/Widget/Value/List.pm b/lib/Reaction/UI/Widget/Value/List.pm deleted file mode 100644 index 89598d8..0000000 --- a/lib/Reaction/UI/Widget/Value/List.pm +++ /dev/null @@ -1,43 +0,0 @@ -package Reaction::UI::Widget::Value::List; - -use Reaction::UI::WidgetClass; - -class List, which { - fragment widget [ qw/list/ ]; - fragment list [ item => over func('viewport', 'value_names') ]; - fragment item [ string {""} ], { value => $_ }; -}; - -1; - -__END__; - -=head1 NAME - -Reaction::UI::Widget::Value::List - -=head1 DESCRIPTION - -=head1 FRAGMENTS - -=head2 widget - -renders C<label> passing additional variable "viewport" - -=head2 list - -renders fragment item over the viewport's C<value_names> - -=head2 item - -C<content> contains the value of the current item ($_ / $_{_}) - -=head1 AUTHORS - -See L<Reaction::Class> for authors. - -=head1 LICENSE - -See L<Reaction::Class> for the license. - -=cut diff --git a/root/bar_form b/root/bar_form deleted file mode 100644 index 1eece03..0000000 --- a/root/bar_form +++ /dev/null @@ -1,6 +0,0 @@ -[% - -attrs.enctype = 'multipart/form-data'; -PROCESS form_base; - -%] diff --git a/root/bar_list b/root/bar_list deleted file mode 100644 index ce57b74..0000000 --- a/root/bar_list +++ /dev/null @@ -1,21 +0,0 @@ -[% - -PROCESS listview; - -table_end_block = 'bar_list_table_end'; - -BLOCK bar_list_table_end; - - "\n</table>\n"; - include( 'create_link_block' ); - "\n<br />\n"; - - enctype = attrs.enctype || 'application/x-www-form-urlencoded'; - %]<form action="[% connect_form %]" method="post" enctype="[% enctype %]"[% - attrs.enctype = ''; process_attrs(self.attrs); '>'; - INCLUDE component type = 'search_base' attrs.value = 'xxx'; - "\n</form>"; - -END; - -%] diff --git a/root/base/actionform b/root/base/actionform deleted file mode 100644 index ab5755b..0000000 --- a/root/base/actionform +++ /dev/null @@ -1 +0,0 @@ -[% PROCESS form_base %] diff --git a/root/base/button b/root/base/button deleted file mode 100644 index 5e09c4d..0000000 --- a/root/base/button +++ /dev/null @@ -1,21 +0,0 @@ -[% - -PROCESS field_base; - -main_block = 'button_control'; - -BLOCK button_control; - - %]<input type="[% button_type || 'submit' %]" [% - IF attrs.value == ''; - 'value="'; loc(self.value) | html; '" '; - END; - connect_control(self, self.event); - process_attrs(attrs) %] />[% -# IF self.img_src; -# INCLUDE component type = 'image'; -# ELSE; - -END; - -%] diff --git a/root/base/cancelbtn b/root/base/cancelbtn deleted file mode 100644 index a9d8af0..0000000 --- a/root/base/cancelbtn +++ /dev/null @@ -1,13 +0,0 @@ -[% - -PROCESS button; - -control_block = 'cancelbtn_control'; - -BLOCK cancelbtn_control; - - INCLUDE button_control attrs.value = 'Cancel' self.event = 'close'; - -END; - -%] diff --git a/root/base/checkbox b/root/base/checkbox deleted file mode 100644 index dd80d86..0000000 --- a/root/base/checkbox +++ /dev/null @@ -1,22 +0,0 @@ -[% - -PROCESS field_base; - -control_block = 'checkbox_control'; - -BLOCK checkbox_control; - - %]<input type="checkbox" id="[% id_attr %]" [% - connect_control(self, 'value'); - process_attrs(attrs); - IF self.value; - ' checked="checked"'; - END; - UNLESS attrs.value; - ' value="1"'; - END; - %] />[% - -END; - -%] diff --git a/root/base/checkbox_group b/root/base/checkbox_group deleted file mode 100644 index 52660b0..0000000 --- a/root/base/checkbox_group +++ /dev/null @@ -1,19 +0,0 @@ -[% - -PROCESS field_base; - -control_block = 'checkbox_group_control'; - -BLOCK checkbox_group_control; - - FOREACH v_name IN self.valid_value_names; - v_val = self.name_to_value_map.$v_name; - %]<input type="checkbox" id="[% id_attr %]" [% connect_control(self, 'value'); - ' value="'; v_val; '"'; - IF self.is_current_value(v_val); ' checked="checked"'; END; - process_attrs(attrs); ' />'; v_name; "\n"; - END; - -END; - -%] diff --git a/root/base/component b/root/base/component deleted file mode 100644 index 4f455ce..0000000 --- a/root/base/component +++ /dev/null @@ -1,64 +0,0 @@ -[%- - -GLOBAL_DEBUG = ctx.debug; - -MACRO loc(text, args) BLOCK; - - ctx.localize(text, args); - -END; - -MACRO include(name, args) BLOCK; - - filename = ${name}; - - IF filename; - IF GLOBAL_DEBUG; - '<!-- Start block '; name | html; ' calling '; filename | html; " -->\n"; - END; - INCLUDE $filename args; - IF GLOBAL_DEBUG; - '<!-- End block '; name | html; " -->\n"; - END; - ELSE; - error = 'Chosen INCLUDE ' _ name _ ' is empty'; - THROW file error; - END; - -END; - -MACRO connect_form(vp, event) BLOCK; - - ''; - -END; - -MACRO connect_control(vp, event, value) BLOCK; - - 'name="'; vp.event_id_for(event); '"'; - -END; - -MACRO connect_href(vp, events) BLOCK; - - FOREACH event = events.keys; - evt_args.${vp.event_id_for(event)} = events.$event; - END; - 'href="'; ctx.req.uri_with(evt_args); '"'; - -END; - -UNLESS type; - errmsg = "type is empty rendering " _ self; - THROW file errmsg; -END; - -PROCESS $type; - -IF GLOBAL_DEBUG; '<!-- Rendering component '; type | html; " -->\n"; END; - -include( 'main_block' ); - -IF GLOBAL_DEBUG; '<!-- End component '; type | html; " -->\n"; END; - --%] diff --git a/root/base/displayfield/list b/root/base/displayfield/list deleted file mode 100644 index 2dcf066..0000000 --- a/root/base/displayfield/list +++ /dev/null @@ -1,17 +0,0 @@ -[% - -PROCESS displayfield_base; - -control_block = 'list_control'; - -BLOCK list_control; - - "<ul>\n"; - FOREACH v_val IN self.value_names; - ' <li>'; v_val | html; "</li>\n"; - END; - "</ul>\n"; - -END; - -%] diff --git a/root/base/displayfield/string b/root/base/displayfield/string deleted file mode 100644 index 7fa3075..0000000 --- a/root/base/displayfield/string +++ /dev/null @@ -1,13 +0,0 @@ -[% - -PROCESS displayfield_base; - -control_block = 'string_control'; - -BLOCK string_control; - - self.value | html; - -END; - -%] diff --git a/root/base/displayfield/text b/root/base/displayfield/text deleted file mode 100644 index dded894..0000000 --- a/root/base/displayfield/text +++ /dev/null @@ -1,13 +0,0 @@ -[% - -PROCESS displayfield_base; - -control_block = 'text_control'; - -BLOCK text_control; - - self.value | html; - -END; - -%] diff --git a/root/base/displayfield/value_string b/root/base/displayfield/value_string deleted file mode 100644 index 1277e83..0000000 --- a/root/base/displayfield/value_string +++ /dev/null @@ -1,13 +0,0 @@ -[% - -PROCESS displayfield_base; - -control_block = 'vstring_control'; - -BLOCK vstring_control; - - self.value_string | html; - -END; - -%] diff --git a/root/base/displayfield_base b/root/base/displayfield_base deleted file mode 100644 index 3fdcfca..0000000 --- a/root/base/displayfield_base +++ /dev/null @@ -1,23 +0,0 @@ -[%- - -main_block = 'displayfield_base_field'; - -control_block = 'displayfield_base_control'; - -BLOCK displayfield_base_field; - - IF self.label; - '<label>'; loc(self.label); '</label>: '; - END; - - include( 'control_block' ); - -END; - -BLOCK displayfield_base_control; - - "CONTROL"; - -END; - --%] diff --git a/root/base/dt_textfield b/root/base/dt_textfield deleted file mode 100644 index 749e3ca..0000000 --- a/root/base/dt_textfield +++ /dev/null @@ -1,16 +0,0 @@ -[% - -PROCESS field_base; - -control_block = 'textfield_control'; - -BLOCK textfield_control; - - attrs.maxlength = '255'; # SimpleStr requires <= 255 - %]<input type="text" [% IF id_attr; 'id="'; id_attr; '"'; END; connect_control(self, 'value_string'); - ' value="'; self.value_string | html; '"'; process_attrs(attrs) %] />[% - attrs.maxlength = ''; - -END; - -%] diff --git a/root/base/dual_select_group b/root/base/dual_select_group deleted file mode 100644 index 1cc5243..0000000 --- a/root/base/dual_select_group +++ /dev/null @@ -1,42 +0,0 @@ -[% - -PROCESS select_group; - -control_block = 'dual_select_group_control'; - -BLOCK dual_select_group_control; - - -%]</p><table[% process_attrs(attrs) %]> - <tr> - <td> -[%- self.label = ''; self.tmp_message = self.message; self.message = ''; - values_list_type = 'available_values'; - INCLUDE component type = 'select_group' self.hide_selected = 1 attrs.size = 10 attrs.name = 'add_values' | indent(4); - attrs.name = ''; attrs.size = ''; %] - </td><td align="center">[% - INCLUDE component type = 'submitbtn' attrs.value = '>>' self.event = 'add_all_values' | indent(4); - '<br />'; - INCLUDE component type = 'submitbtn' attrs.value = '>' self.event = 'do_add_values' | indent(4); - '<br />'; - INCLUDE component type = 'submitbtn' attrs.value = '<' self.event = 'do_remove_values' | indent(4); - '<br />'; - INCLUDE component type = 'submitbtn' attrs.value = '<<' self.event = 'remove_all_values' | indent(4); %] - </td><td> -[%- attrs.value = ''; - values_list_type = 'current_values'; - INCLUDE component type = 'select_group' self.hide_selected = 1 attrs.size = 10 attrs.name = 'remove_values' | indent(4); - attrs.name = ''; attrs.size = ''; - - FOREACH v_val IN self.current_values; - v_val = self.obj_to_str(v_val); - INCLUDE component type = 'hidden' self.val = v_val attrs = '' | indent(4); - END; - -# self.message = self.tmp_message; self.tmp_message = ''; %] - </td> - </tr>[% - %]</table><p>[% - -END; - -%] diff --git a/root/base/error_404 b/root/base/error_404 deleted file mode 100644 index 0177cba..0000000 --- a/root/base/error_404 +++ /dev/null @@ -1,17 +0,0 @@ -[% - -main_block = 'error_404_main'; - -BLOCK error_404_main; - - loc("404 Not Found"); - - %] <a href="[% ctx.uri_for(ctx.action.chain.0.attributes.Chained.0) %]">[% - - loc("Return to root"); - - %]</a>[% - -END; - -%] diff --git a/root/base/field_base b/root/base/field_base deleted file mode 100644 index 3605a8c..0000000 --- a/root/base/field_base +++ /dev/null @@ -1,27 +0,0 @@ -[%- - -main_block = 'field_base_field'; - -control_block = 'field_base_control'; - -BLOCK field_base_field; - - IF self.label; - '<label>'; loc(self.label); '</label>: '; - END; - - include( 'control_block' ); - - IF self.message; - "\n<span>"; loc(self.message); '</span>'; - END; - -END; - -BLOCK field_base_control; - - "CONTROL"; - -END; - --%] diff --git a/root/base/fieldset b/root/base/fieldset deleted file mode 100644 index 7daa8be..0000000 --- a/root/base/fieldset +++ /dev/null @@ -1,20 +0,0 @@ -[% - -PROCESS field_base; - -control_block = 'fieldset_control'; - -BLOCK fieldset_control; - - %]<fieldset id="[% self.field_name | html %]"[% process_attrs(attrs) %] />[% - IF self.text; - '<legend>'; self.text; '</legend>'; - END; - -# INCLUDE( 'control_block' ); - - %]</fieldset>[% - -END; - -%] diff --git a/root/base/file b/root/base/file deleted file mode 100644 index c89c397..0000000 --- a/root/base/file +++ /dev/null @@ -1,16 +0,0 @@ -[% - -PROCESS field_base; - -control_block = 'fileselect_control'; - -BLOCK fileselect_control; - - %]<input type="file" [% IF id_attr; 'id="'; id_attr; '"'; END; connect_control(self, 'value'); - # browsers ignore this for security reasons, can be uncommented for testing. - # ' value="'; self.value.filename | html; '"'; - process_attrs(attrs) %] />[% - -END; - -%] diff --git a/root/base/footer b/root/base/footer deleted file mode 100644 index aa00551..0000000 --- a/root/base/footer +++ /dev/null @@ -1,12 +0,0 @@ -[%- - -#main_block = 'footer'; - -#BLOCK footer; - - %]<p>FOOTER</p> - [% - -#END; - --%] diff --git a/root/base/form_base b/root/base/form_base deleted file mode 100644 index cb988ec..0000000 --- a/root/base/form_base +++ /dev/null @@ -1,77 +0,0 @@ -[% - -main_block = 'form_base_control'; - -control_block = 'form_base_control'; - -header_block = 'form_base_header'; -fields_block = 'form_base_fields'; -button_block = 'form_base_buttons'; -footer_block = 'form_base_footer'; - -form_id = 0; - -BLOCK form_base_control; - - form_id = form_id + 1; - - enctype = attrs.enctype || 'multipart/form-data'; - %]<form action="[% attrs.action || connect_form %]" method="post" id="element_[% form_id %]" enctype="[% enctype %]"[% - IF attrs.name != ""; ' name="'; attrs.name; attrs.name = ''; '"'; END; - attrs.enctype = ''; attrs.action = ''; - process_attrs(self.attrs) %]>[% "\n"; - - include( 'header_block' ); - include( 'fields_block' ); - - id_attr = ''; '<p>'; - include( 'button_block' ); - include( 'footer_block' ); - - "</p>\n</form>"; - -END; - -BLOCK form_base_header; - - ''; - -END; - -BLOCK form_base_fields; - - FOREACH f_name = self.field_names; - field = self.fields.$f_name; - id = form_id _ '_' _ loop.count; - '<p>'; window.render_viewport(field); "</p>\n"; - END; - -END; - -BLOCK form_base_buttons; - - allowed_events = self.accept_events; - - IF allowed_events.grep('^ok$').size; - INCLUDE component type = 'submitbtn' self.value = 'ok' self.event = 'ok' self.label = self.ok_label; - END; - - IF (self.field_names.size != 0) && (allowed_events.grep('^apply$').size); - INCLUDE component type = 'submitbtn' self.value = 'apply' self.event = 'apply' self.label = self.apply_label; - END; - - IF allowed_events.grep('^close$').size; - INCLUDE component type = 'cancelbtn' self.value = 'cancel' self.event = 'close' self.label = self.cancel_label; - END; - -END; - -BLOCK form_base_footer; - - IF self.message; - ' <span>'; self.message; '</span>'; - END; - -END; - -%] diff --git a/root/base/header b/root/base/header deleted file mode 100644 index 933457f..0000000 --- a/root/base/header +++ /dev/null @@ -1,11 +0,0 @@ -[%- - -#main_block = 'header_block'; - -#BLOCK header_block; - - %]<p>HEADER</p>[% - -#END; - --%] diff --git a/root/base/hidden b/root/base/hidden deleted file mode 100644 index 6b5f6c4..0000000 --- a/root/base/hidden +++ /dev/null @@ -1,15 +0,0 @@ -[% - -PROCESS field_base; - -control_block = 'hidden_control'; - -BLOCK hidden_control; - - name = attrs.name || 'value'; attrs.name = ''; - %]<input type="hidden" [% IF id_attr; 'id="'; id_attr; '"'; END; connect_control(self, name); - ' value="'; self.val; '"'; process_attrs(attrs) %] />[% - -END; - -%] diff --git a/root/base/hiddenarray b/root/base/hiddenarray deleted file mode 100644 index 8168ad3..0000000 --- a/root/base/hiddenarray +++ /dev/null @@ -1,17 +0,0 @@ -[% - -PROCESS field_base; - -control_block = 'hiddenarray_control'; - -BLOCK hiddenarray_control; - - name = attrs.name || 'value'; attrs.name = ''; - FOREACH val IN self.value; - %]<input type="hidden" [% IF id_attr; 'id="'; id_attr; '"'; END; connect_control(self, name); - ' value="'; val; '"'; process_attrs(attrs) %] />[% "\n"; - END; - -END; - -%] diff --git a/root/base/image b/root/base/image deleted file mode 100644 index 36cf927..0000000 --- a/root/base/image +++ /dev/null @@ -1,11 +0,0 @@ -[% - -main_block = 'image_base'; - -BLOCK image_base; - - %]<img src="[% self.img_src | html %]" alt="[% self.text | html %]"[% process_attrs(attrs) %] />[% - -END; - -%] diff --git a/root/base/label b/root/base/label deleted file mode 100644 index e380ba0..0000000 --- a/root/base/label +++ /dev/null @@ -1,17 +0,0 @@ -[% - -PROCESS field_base; - -control_block = 'label_control'; - -BLOCK label_control; - - %]<label id="[% self.field_name | html %]" [% connect_control(self, 'value') %] value="[% self.field_value | html %]" />[% - -# INCLUDE( 'control_block' ); - - '</label>'; - -END; - -%] diff --git a/root/base/listview b/root/base/listview deleted file mode 100644 index 382630d..0000000 --- a/root/base/listview +++ /dev/null @@ -1,60 +0,0 @@ -[% - -PROCESS listview_base; - -header_field_block = 'listview_header_field'; - -BLOCK listview_header_field; - - desc = 0; - IF (self.order_by == field_name && !self.order_by_desc); - desc = 1; - ELSE; - desc = 0; - END; - - "\n <th"; process_attrs(attrs); '><a '; connect_href(self, order_by => field_name, order_by_desc => desc); '>'; - loc(self.field_label(field_name)); '</a></th>'; - -END; - -header_block = 'listview_header'; - -BLOCK listview_header; - - INCLUDE listview_base_header; - IF self.row_action_prototypes.size; - %] - <th colspan="[% self.row_action_prototypes.size %]"[% - process_attrs(attrs); %]>[% loc('Actions'); %]</th>[% - END; - -END; - -row_block = 'listview_row'; - -BLOCK listview_row; - - INCLUDE listview_base_row; - FOREACH action IN self.row_actions_for(row); - %] <td[% process_attrs(attrs); %]><a href="[% action.uri %]">[% - loc(action.label) %]</a></td>[% - IF loop.last == 0; "\n"; END; - END; - -END; - -row_field_block = 'listview_row_field'; - -BLOCK listview_row_field; - - field_value = field_value || row.$f_name; - - IF field_value.isa('DateTime'); - field_value = field_value.strftime("%F %H:%M:%S"); - END; - INCLUDE listview_base_row_field; - -END; - -%] diff --git a/root/base/listview_base b/root/base/listview_base deleted file mode 100644 index 9b71c30..0000000 --- a/root/base/listview_base +++ /dev/null @@ -1,124 +0,0 @@ -[% - -main_block = 'listview_base_main'; - -table_start_block = 'listview_base_table_start'; -table_end_block = 'listview_base_table_end'; -row_block = 'listview_base_row'; -row_field_block = 'listview_base_row_field'; -header_block = 'listview_base_header'; -header_field_block = 'listview_base_header_field'; -footer_block = 'listview_base_footer'; -footer_field_block = 'listview_base_footer_field'; -create_link_block = 'listview_base_create'; - -show_footer = 1; - -BLOCK listview_base_main; - - include( 'table_start_block' ); %] - <thead> - <tr>[% include( 'header_block' ) | indent(4); %] - </tr> - </thead>[% - - IF show_footer && self.footer_field_names.size != ''; - "\n <tfoot>"; - include( 'footer_block' ) | indent(4); - "\n </tfoot>"; - END; - - %] - <tbody> - [% - - FOREACH row = self.current_rows; - "<tr>\n"; - include( 'row_block' ) | indent(4); - "\n </tr>"; - END; %] - </tbody>[% - - include( 'table_end_block' ); - -END; - -BLOCK listview_base_table_start; - - #IF self.has_per_page; - IF self.has_per_page && self.pager.last_page > self.pager.first_page; - INCLUDE component type = 'pager'; - END; - - %]<table>[% - -END; - -BLOCK listview_base_table_end; - - "\n</table>\n"; - include( 'create_link_block' ); - -END; - -BLOCK listview_base_row; - - FOREACH f_name = self.field_names; - include( 'row_field_block' ); - END; - -END; - -BLOCK listview_base_row_field; - - field_value = field_value || row.$f_name; - IF field_value.can('display_name'); field_value = field_value.display_name; END; - ' <td'; process_attrs(attrs); '>'; field_value || row.$f_name; "</td>\n"; - -END; - -BLOCK listview_base_header; - - FOREACH field_name = self.field_names; - include( 'header_field_block' ); - END; - -END; - -BLOCK listview_base_header_field; - - "\n<th>"; self.field_label(field_name); '</th>'; - -END; - -BLOCK listview_base_footer; - - "\n<tr>"; - - FOREACH footer_field_name = self.footer_field_names; - include( 'footer_field_block' ); - END; - - '</tr>'; - -END; - -BLOCK listview_base_footer_field; - - "\n <td>"; self.field_label(footer_field_name); '</td>'; - -END; - -BLOCK listview_base_create; - - '<p>'; - action = ctx.controller.action_for('create'); - IF action; - action = ctx.uri_for(action); - '<a href="'; action; '">'; loc("Create record"); '</a>'; - END; - '</p>'; - -END; - -%] diff --git a/root/base/objectview b/root/base/objectview deleted file mode 100644 index 567d3c8..0000000 --- a/root/base/objectview +++ /dev/null @@ -1 +0,0 @@ -[% PROCESS view_base %] diff --git a/root/base/pager b/root/base/pager deleted file mode 100644 index cde0ce4..0000000 --- a/root/base/pager +++ /dev/null @@ -1,128 +0,0 @@ -[% - -main_block = 'pager_main'; - -start_block = 'pager_start'; -prev_block = 'pager_prev'; -current_block = 'pager_current'; -next_block = 'pager_next'; -end_block = 'pager_end'; -list_block = 'pager_list'; - -start_label_block = 'pager_start_label'; -prev_label_block = 'pager_prev_label'; -current_label_block = 'pager_current_label'; -next_label_block = 'pager_next_label'; -end_label_block = 'pager_end_label'; -list_label_block = 'pager_list_label'; - -BLOCK pager_main; - - '<div>[ '; - data = []; - - str = BLOCK; include( 'start_block' ); END; - data.push(str) IF str; - - str = BLOCK; include( 'prev_block' ); END; - data.push(str) IF str; - - str = BLOCK; include( 'current_block' ); END; - data.push(str) IF str; - - str = BLOCK; include( 'next_block' ); END; - data.push(str) IF str; - - str = BLOCK; include( 'end_block' ); END; - data.push(str) IF str; - - data.join(" |\n"); - " ]</div>\n"; - -END; - -BLOCK pager_start; - - %]<a [% connect_href(self, 'page' => self.pager.first_page); process_attrs(attrs) %]>[% - include( 'start_label_block' ) %]</a>[% - -END; - -BLOCK pager_start_label; - - loc('Start'); ' ('; self.pager.first_page; ')'; - -END; - -BLOCK pager_prev; - - IF self.pager.current_page != 1; - %]<a [% connect_href(self, 'page' => self.pager.previous_page); process_attrs(attrs) %]>[% - include( 'prev_label_block' ) %]</a>[% - END; - -END; - -BLOCK pager_prev_label; - - loc('Previous'); ' ('; self.pager.previous_page; ')'; - -END; - -BLOCK pager_current; - - %]<a [% connect_href(self, 'page' => self.pager.current_page); process_attrs(attrs) %]>[% - include( 'current_label_block' ) %]</a>[% - -END; - -BLOCK pager_current_label; - - loc('Current'); ' ('; self.pager.current_page; ')'; - -END; - -BLOCK pager_next; - - IF self.pager.current_page != self.pager.last_page; - %]<a [% connect_href(self, 'page' => self.pager.next_page); process_attrs(attrs) %]>[% - include( 'next_label_block' ) %]</a>[% - END; - -END; - -BLOCK pager_next_label; - - loc('Next'); ' ('; self.pager.next_page; ')'; - -END; - -BLOCK pager_end; - - %]<a [% connect_href(self, 'page' => self.pager.last_page); process_attrs(attrs) %]>[% - include( 'end_label_block' ) %]</a>[% - -END; - -BLOCK pager_end_label; - - loc('End'); ' ('; self.pager.last_page; ')'; - -END; - -BLOCK pager_list; - - FOREACH page IN self.pager.list; - '<a'; connect_href(self, 'page' => page); process_attrs(attrs); '>'; - include( 'list_label_block' ); "</a>\n"; - END; - -END; - -BLOCK pager_list_label; - - page; - -END; - -%] diff --git a/root/base/password b/root/base/password deleted file mode 100644 index ba3f389..0000000 --- a/root/base/password +++ /dev/null @@ -1,14 +0,0 @@ -[% - -PROCESS field_base; - -control_block = 'passwordfield_control'; - -BLOCK passwordfield_control; - - %]<input type="password" [% IF id_attr; 'id="'; id_attr; '"'; END; connect_control(self, 'value'); - ' value="'; self.value | html; '"'; process_attrs(attrs) %] />[% - -END; - -%] diff --git a/root/base/radio b/root/base/radio deleted file mode 100644 index a4e897a..0000000 --- a/root/base/radio +++ /dev/null @@ -1,14 +0,0 @@ -[% - -PROCESS field_base; - -control_block = 'radio_control'; - -BLOCK radio_control; - - %]<input type="radio" id="[% id_attr %]" [% connect_control(self, 'value'); - process_attrs(attrs) %] />[% - -END; - -%] diff --git a/root/base/radio_group b/root/base/radio_group deleted file mode 100644 index b64e5b8..0000000 --- a/root/base/radio_group +++ /dev/null @@ -1,17 +0,0 @@ -[% - -PROCESS field_base; - -control_block = 'radiogroup_control'; - -BLOCK radiogroup_control; - - FOREACH value IN self.values.keys; - '<input type="radio" id="[% id_attr %]" [% connect_control(self, 'value'); - IF self.default == value; ' checked="checked"'; END; - process_attrs(attrs); " />\n"; - END; - -END; - -%] diff --git a/root/base/resetbtn b/root/base/resetbtn deleted file mode 100644 index 859d5c8..0000000 --- a/root/base/resetbtn +++ /dev/null @@ -1,13 +0,0 @@ -[% - -PROCESS button; - -control_block = 'resetbtn_control'; - -BLOCK resetbtn_control; - - INCLUDE button_control button_type = 'reset' attrs.value = 'Reset'; - -END; - -%] diff --git a/root/base/search_base b/root/base/search_base deleted file mode 100644 index 24bbfff..0000000 --- a/root/base/search_base +++ /dev/null @@ -1,14 +0,0 @@ -[% - -PROCESS field_base; - -control_block = 'search_base_control'; - -BLOCK search_base_control; - - INCLUDE component type = 'textfield'; - INCLUDE component type = 'submitbtn' attrs.value = 'Search'; - -END; - -%] diff --git a/root/base/select b/root/base/select deleted file mode 100644 index a387fa1..0000000 --- a/root/base/select +++ /dev/null @@ -1,38 +0,0 @@ -[% - -PROCESS field_base; - -control_block = 'select_control'; - -BLOCK select_control; - - IF values_list_type; - values_list = self.${values_list_type}; - ELSE; - values_list = self.valid_values; - END; - - name = attrs.name || 'value'; attrs.name = ''; - '<select '; - IF id_attr; 'id="'; id_attr; '"'; END; - connect_control(self, name); process_attrs(attrs); ">\n"; - - IF attrs.nullable == 1 || !(self.attribute.required); - attrs.nullable = ''; - " <option value=\"\">--</option>\n"; - END; - - FOREACH v_val IN values_list; - v_val = self.obj_to_str(v_val); - v_name = self.value_to_name_map.${v_val} || v_val; - ' <option value="'; v_val | html; '"'; - IF (self.is_current_value(v_val) || self.value == v_val ) && !self.hide_selected; - ' selected="selected"'; - END; - '>'; v_name | html; "</option>\n"; - END; - '</select>'; - -END; - -%] diff --git a/root/base/select_group b/root/base/select_group deleted file mode 100644 index f740d77..0000000 --- a/root/base/select_group +++ /dev/null @@ -1,14 +0,0 @@ -[% - -PROCESS select; - -control_block = 'select_group_control'; - -BLOCK select_group_control; - - INCLUDE select_control attrs.multiple = 'multiple'; - attrs.multiple = ''; - -END; - -%] diff --git a/root/base/submitbtn b/root/base/submitbtn deleted file mode 100644 index 6e2246c..0000000 --- a/root/base/submitbtn +++ /dev/null @@ -1,13 +0,0 @@ -[% - -PROCESS button; - -control_block = 'submitbtn_control'; - -BLOCK submitbtn_control; - - INCLUDE button_control button_type = 'submit' attrs.value = 'Submit' self.event = 'ok'; - -END; - -%] diff --git a/root/base/textarea b/root/base/textarea deleted file mode 100644 index 57114f9..0000000 --- a/root/base/textarea +++ /dev/null @@ -1,15 +0,0 @@ -[% - -PROCESS field_base; - -control_block = 'textarea_control'; - -BLOCK textarea_control; - - attrs.maxlength = ''; - %]<textarea id="[% id_attr %]" [% connect_control(self, 'value'); - process_attrs(attrs) %]>[% self.value | html; '</textarea>'; - -END; - -%] diff --git a/root/base/textfield b/root/base/textfield deleted file mode 100644 index a43f445..0000000 --- a/root/base/textfield +++ /dev/null @@ -1,17 +0,0 @@ -[% - -PROCESS field_base; - -control_block = 'textfield_control'; - -BLOCK textfield_control; - - attrs.maxlength = '255'; # SimpleStr requires <= 255 - name = attrs.name || 'value'; attrs.name = ''; - %]<input type="text" [% IF id_attr; 'id="'; id_attr; '"'; END; connect_control(self, name); - ' value="'; self.value | html; '"'; process_attrs(attrs) %] />[% - attrs.maxlength = ''; - -END; - -%] diff --git a/root/base/timerange b/root/base/timerange deleted file mode 100644 index a987cfd..0000000 --- a/root/base/timerange +++ /dev/null @@ -1,44 +0,0 @@ -[% - -main_block = 'timerange_field'; - -BLOCK timerange_field; - - include( 'control_block' ); - - IF self.message; - "\n<span>"; loc(self.message); '</span>'; - END; - -END; - -control_block = 'timerange_control'; - -BLOCK timerange_control; - - name = attrs.name || 'value_string'; attrs.name = ''; - self.label = ''; - data = self.value_string.split(','); - #USE dumper; dumper.dump(data); - data.0.replace('T', ' ') | ucfirst; ' to '; data.1.replace('T', ' '); - IF data.2 == 'none'; data.2 = ''; END; - IF data.2 != ''; - ' every '; data.4.replace('dai', 'day').replace('ly', ''); - ' between '; data.2.replace('T', ' '); ' and '; data.3.replace('T', ' '); - END; - inner = { - value => self.delete_label, - event => 'delete', - location => self.location, - }; -# INCLUDE component type = 'button' button_type = 'submit' self = inner; - '<input type="submit" value="'; self.delete_label; ;'" '; connect_control(self, 'delete'); ' />'; - "<br />\n"; - '<input type="hidden" '; connect_control(self, name); ' value="'; self.value_string; '"'; process_attrs(attrs); ' />'; - "\n"; - -# INCLUDE component type = 'hiddenarray' self.value = ctx.stash.ranges; - -END; - -%] diff --git a/root/base/timerangecollection b/root/base/timerangecollection deleted file mode 100644 index 2c0bf1a..0000000 --- a/root/base/timerangecollection +++ /dev/null @@ -1,60 +0,0 @@ -[% - -PROCESS form_base; - -fields_block = 'timerangecollection_control'; - -BLOCK timerangecollection_control; - - include( 'error_block' ); - include( 'results_block' ); - FOREACH f_name = self.field_names; - NEXT IF f_name.match('range'); - field = self.fields.$f_name; - '<p>'; window.render_viewport(field); "</p>\n"; - END; - -END; - -results_block = 'timerangecollection_results'; - -BLOCK timerangecollection_results; - - FOREACH field = self.range_vps; - '<p>'; window.render_viewport(field); "</p>\n"; - END; - '<input type="hidden"'; connect_control(self, 'max_range_vps'); ' value="'; self.range_vps.size; '" />'; -# INCLUDE component type = 'hidden' self.name = 'max_range_vps' self.val = self.range_vps.size; - -END; - -error_block = 'timerangecollection_error'; - -BLOCK timerangecollection_error; - - IF self.warning; - '<p>'; self.warning; '</p>'; - END; - IF self.error; - '<p>'; self.error; '</p>'; - END; - -END; - -button_block = 'timerangecollection_buttons'; - -BLOCK timerangecollection_buttons; - - INCLUDE component type = 'submitbtn' self.value = 'add' self.event = 'add_range_vp' self.label = ''; - - IF self.has_on_next_callback; - INCLUDE component type = 'submitbtn' self.value = 'next' self.event = 'next' self.label = ''; - END; - - IF self.is_changed; self.value = 'cancel'; ELSE; self.value = 'close'; END; - INCLUDE component type = 'cancelbtn' self.label = '' self.event = 'close'; - '<br />'; - -END; - -%] diff --git a/root/base/view_base b/root/base/view_base deleted file mode 100644 index e67ac8f..0000000 --- a/root/base/view_base +++ /dev/null @@ -1,22 +0,0 @@ -[% - -main_block = 'view_base_control'; -control_block = 'view_base_control'; -fields_block = 'view_base_fields'; - -BLOCK view_base_control; - - include( 'fields_block' ); - -END; - -BLOCK view_base_fields; - - FOREACH f_name = self.field_names; - field = self.fields.$f_name; - window.render_viewport(field); "<br />\n"; - END; - -END; - -%] diff --git a/root/base/xhtml b/root/base/xhtml deleted file mode 100644 index 0c0ea26..0000000 --- a/root/base/xhtml +++ /dev/null @@ -1,29 +0,0 @@ -[% BLOCK xhtml_main; -%] -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> - -<head> - <title>[% window.title %]</title> - - [%- FOREACH stylesheet IN stylesheets; -%] - <link rel="stylesheet" type="text/css" href="[% ctx.uri_for('/stylesheets', stylesheet) %]" /> - [%- END; -%] - [%- FOREACH javascript IN javascripts; -%] - <script src="[% ctx.uri_for('/javascript', javascript) %]" type="text/javascript"></script> - [%- END; -%] - - <meta http-equiv="Content-Type" content="text/html; charset=utf8" /> - <meta name="GENERATOR" content="Catalyst/TT" /> -</head> - -<body> -[% INCLUDE header; -window.render_viewport(self.inner); %] -[% INCLUDE footer; %] -</body> -</html> -[%- END; -main_block = 'xhtml_main'; --%] diff --git a/root/favicon.ico b/root/favicon.ico Binary files differdeleted file mode 100644 index 5ad723d..0000000 --- a/root/favicon.ico +++ /dev/null diff --git a/root/index b/root/index deleted file mode 100644 index 70d0472..0000000 --- a/root/index +++ /dev/null @@ -1,18 +0,0 @@ -[% - -main_block = 'index'; - -BLOCK index; - -%] - -<h2>Using InterfaceModel, Reflector</h2> -<p><a href="[% ctx.uri_for('/testmodel/foo') %]">foo</a></p> -<p><a href="[% ctx.uri_for('/testmodel/bar') %]">bar</a></p> -<p><a href="[% ctx.uri_for('/testmodel/baz') %]">baz</a></p> - -[% - -END; - -%] diff --git a/root/static/images/btn_120x50_built.png b/root/static/images/btn_120x50_built.png Binary files differdeleted file mode 100644 index c709fd6..0000000 --- a/root/static/images/btn_120x50_built.png +++ /dev/null diff --git a/root/static/images/btn_120x50_built_shadow.png b/root/static/images/btn_120x50_built_shadow.png Binary files differdeleted file mode 100644 index 15142fe..0000000 --- a/root/static/images/btn_120x50_built_shadow.png +++ /dev/null diff --git a/root/static/images/btn_120x50_powered.png b/root/static/images/btn_120x50_powered.png Binary files differdeleted file mode 100644 index 7249b47..0000000 --- a/root/static/images/btn_120x50_powered.png +++ /dev/null diff --git a/root/static/images/btn_120x50_powered_shadow.png b/root/static/images/btn_120x50_powered_shadow.png Binary files differdeleted file mode 100644 index e6876c0..0000000 --- a/root/static/images/btn_120x50_powered_shadow.png +++ /dev/null diff --git a/root/static/images/btn_88x31_built.png b/root/static/images/btn_88x31_built.png Binary files differdeleted file mode 100644 index 007b5db..0000000 --- a/root/static/images/btn_88x31_built.png +++ /dev/null diff --git a/root/static/images/btn_88x31_built_shadow.png b/root/static/images/btn_88x31_built_shadow.png Binary files differdeleted file mode 100644 index ccf4624..0000000 --- a/root/static/images/btn_88x31_built_shadow.png +++ /dev/null diff --git a/root/static/images/btn_88x31_powered.png b/root/static/images/btn_88x31_powered.png Binary files differdeleted file mode 100644 index 8f0cd9f..0000000 --- a/root/static/images/btn_88x31_powered.png +++ /dev/null diff --git a/root/static/images/btn_88x31_powered_shadow.png b/root/static/images/btn_88x31_powered_shadow.png Binary files differdeleted file mode 100644 index aa776fa..0000000 --- a/root/static/images/btn_88x31_powered_shadow.png +++ /dev/null diff --git a/root/static/images/catalyst_logo.png b/root/static/images/catalyst_logo.png Binary files differdeleted file mode 100644 index 21f1cac..0000000 --- a/root/static/images/catalyst_logo.png +++ /dev/null diff --git a/share/skin/default/layout/index.tt b/share/skin/componentui/layout/index.tt index 9a9bc9c..9a9bc9c 100644 --- a/share/skin/default/layout/index.tt +++ b/share/skin/componentui/layout/index.tt diff --git a/share/skin/componentui/skin.conf b/share/skin/componentui/skin.conf index a9827b2..0fa450d 100644 --- a/share/skin/componentui/skin.conf +++ b/share/skin/componentui/skin.conf @@ -1 +1,3 @@ extends default + +widget_search_path ComponentUI::View::Site::Widget diff --git a/share/skin/default/layout/field/mutable/text.tt b/share/skin/default/layout/field/mutable/text.tt index c038280..b4038aa 100644 --- a/share/skin/default/layout/field/mutable/text.tt +++ b/share/skin/default/layout/field/mutable/text.tt @@ -2,8 +2,8 @@ =for layout field -<textarea name="[% field_name %]" id="[% field_id %]"> - [% field_value %] -</textarea> +<textarea name="[% field_name %]" id="[% field_id %]">[% + field_value +%]</textarea> =cut diff --git a/share/skin/default/layout/site_layout.tt b/share/skin/default/layout/site_layout.tt index 1e7afa1..e9b70ca 100644 --- a/share/skin/default/layout/site_layout.tt +++ b/share/skin/default/layout/site_layout.tt @@ -24,6 +24,15 @@ =for layout head_meta <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> + [% meta_info %] + +=for layout meta_info + +[% call_next %] + +=for layout meta_member + +<meta name="[% meta_name %]" content="[% meta_value %]" />[% "\n" %] =for layout head_style diff --git a/share/skin/defaults.conf b/share/skin/defaults.conf new file mode 100644 index 0000000..b7d630e --- /dev/null +++ b/share/skin/defaults.conf @@ -0,0 +1 @@ +widget_search_path Reaction::UI::Widget |