</ViewPort>
</Action>
</Controller>
+
+<View Site>
+ skin_name default
+</View>
\ No newline at end of file
# Static::Simple: will serve static files from the application's root
# directory
-use Catalyst qw/-Debug ConfigLoader Static::Simple I18N/;
+use Catalyst qw/ ConfigLoader -Debug Static::Simple I18N /;
our $VERSION = '0.01';
# so they function identically to actions created in MyApp.pm
#
__PACKAGE__->config(
- view_name => 'XHTML',
+ view_name => 'Site',
window_title => 'Reaction Test App',
- content_type => 'text/html',
- namespace => '',
+ namespace => ''
);
sub base :Chained('/') :PathPart('') :CaptureArgs(0) {
my ($self, $c) = @_;
- $self->push_viewport(ViewPort, layout => 'xhtml');
+ $self->push_viewport(ViewPort, layout => 'layout');
}
sub root :Chained('base') :PathPart('') :Args(0) {
$self->push_viewport(ViewPort, layout => 'index');
}
+sub static :Chained('base') :PathPart('static') :Args {
+ my ($self, $c, @args) = @_;
+ return if $c->stash->{window}->view->serve_static_file($c, \@args);
+ $c->forward('error_404');
+}
+
+sub error_404 :Private {
+ my ($self, $c) = @_;
+ $c->res->body("Error 404");
+ $c->res->status(404);
+}
+
1;
--- /dev/null
+package ComponentUI::View::Site;
+
+use Reaction::Class;
+use aliased 'Reaction::UI::View::TT';
+
+class Site is TT, which {
+
+};
+
+
+use Class::MOP;
+
+{
+ my @reflect_widgets = qw(ActionForm ObjectView ListView
+ Field::File
+ Field::Password
+ Field::Text DisplayField::Text
+ Field::Number DisplayField::Number
+ Field::String DisplayField::String
+ Field::Boolean DisplayField::Boolean
+ Field::DateTime DisplayField::DateTime
+ Field::ChooseOne DisplayField::RelatedObject
+ Field::ChooseMany DisplayField::Collection
+ Field::HiddenArray DisplayField::List
+ );
+
+
+ for (@reflect_widgets){
+ my $base = "Reaction::UI::Widget::${_}";
+ my $target = "ComponentUI::View::Site::Widget::${_}";
+ Class::MOP::load_class( $base );
+ $base->meta->create($target, superclasses => [$base]);
+ }
+}
+
+1;
--- /dev/null
+package ComponentUI::View::Site::Widget::Index;
+
+use Reaction::UI::WidgetClass;
+
+class Index which {
+
+ widget renders [ string {"DUMMY"} ];
+
+};
+
+1;
--- /dev/null
+package ComponentUI::View::Site::Widget::Layout;
+
+use Reaction::UI::WidgetClass;
+
+class Layout which {
+
+ widget renders [ qw(menu sidebar header main_content) =>
+ { viewport => func('self', 'viewport') } ];
+
+ menu renders [ string { "DUMMY" } ];
+ sidebar renders [ string { "Sidebar Shit" } ];
+ header renders [ string { "DUMMY" } ];
+ main_content renders [ viewport over func('viewport', 'inner')];
+
+};
+
+1;
my $found;
SEARCH: foreach my $path (@path) {
my $cand = $path->file($self->name);
+ print STDERR $cand,"\n";
if ($cand->stat) {
$self->_load_file($cand);
$found = 1;
implements 'widget_type' => as {
my ($self) = @_;
- return join('', map { ucfirst($_) } split('_', $self->name));
+ my $widget = join('', map { ucfirst($_) } split('_', $self->name));
+ $widget = join('::', map { ucfirst($_) } split('/', $widget));
+
+ print STDERR "--- ", $self->name, " maps to widget $widget \n";
+
+ return $widget;
};
};
|| confess "tt_object not provided to new()";
my $tt_args = { data => {} };
my $name = $self->name;
+ $name =~ s/\//__/g; #slashes are not happy here...
my $fragments = $self->fragments;
my $tt_source = qq{[% VIEW ${name};\n\n}.
join("\n\n",
return $tt_args->{data}{view};
};
-};
+};
1;
my $base = $self->blessed;
my $tail = $layout_set->widget_type;
my $class = join('::', $base, 'Widget', $tail);
- Class::MOP::load_class($class);
+ eval { Class::MOP::load_class($class) };
+ confess "Couldn't load widget '$class': $@" if $@;
return $class;
};
implements 'layout_set_for' => as {
my ($self, $vp) = @_;
+ print STDERR "Getting layoutset for VP ".(ref($vp) || "SC:".$vp)."\n";
my $lset_name = eval { $vp->layout };
confess "Couldn't call layout method on \$vp arg ${vp}: $@" if $@;
unless (length($lset_name)) {
- my $last = (split('::', ref($vp)))[-1];
- #previously: join("_", map { lc($_) } split(/(?=[A-Z])/, $last))
- $last =~ s/([a-z0-9])([A-Z])/${1}_${2}/g
- $lset_name = lc($last);
+ my $vp_class = ref($vp) || $vp;
+ my ($last) = ($vp_class =~ /.*(?:::ViewPort::)(.+?)$/);
+ my @fragments = split('::', $last);
+ $_ = join("_", split(/(?=[A-Z])/, $_)) for @fragments;
+ $lset_name = lc(join('/', @fragments));
+ print STDERR "--- $vp_class is rendered as $lset_name\n";
}
my $cache = $self->_layout_set_cache;
return $cache->{$lset_name} ||= $self->create_layout_set($lset_name);
implements 'find_related_class' => as {
my ($self, $rel) = @_;
- my $own_class = ref($self)||$self;
+ my $own_class = ref($self) || $self;
confess View." is abstract, you must subclass it" if $own_class eq View;
foreach my $super ($own_class->meta->class_precedence_list) {
next if $super eq View;
class ActionForm is 'Reaction::UI::ViewPort', which {
has action => (
- isa => 'Reaction::InterfaceModel::Action', is => 'ro', required => 1
- );
+ isa => 'Reaction::InterfaceModel::Action', is => 'ro', required => 1
+ );
has ordered_fields => (is => 'rw', isa => 'ArrayRef', lazy_build => 1);
has _field_map => (
- isa => 'HashRef', is => 'rw', init_arg => 'fields', lazy_build => 1,
- );
+ isa => 'HashRef', is => 'rw', init_arg => 'fields', lazy_build => 1,
+ );
has changed => (
- isa => 'Int', is => 'rw', reader => 'is_changed', default => sub { 0 }
- );
+ isa => 'Int', is => 'rw', reader => 'is_changed', default => sub { 0 }
+ );
has next_action => (
- isa => 'ArrayRef', is => 'rw', required => 0, predicate => 'has_next_action'
- );
+ isa => 'ArrayRef', is => 'rw', required => 0, predicate => 'has_next_action'
+ );
has on_apply_callback => (
- isa => 'CodeRef', is => 'rw', required => 0,
- predicate => 'has_on_apply_callback'
- );
+ isa => 'CodeRef', is => 'rw', required => 0,
+ predicate => 'has_on_apply_callback'
+ );
has ok_label => (
- isa => 'Str', is => 'rw', required => 1, default => sub { 'ok' }
- );
+ isa => 'Str', is => 'rw', required => 1, default => sub { 'ok' }
+ );
has apply_label => (
- isa => 'Str', is => 'rw', required => 1, default => sub { 'apply' }
- );
+ isa => 'Str', is => 'rw', required => 1, default => sub { 'apply' }
+ );
has close_label => (isa => 'Str', is => 'rw', lazy_fail => 1);
has close_label_close => (
- isa => 'Str', is => 'rw', required => 1, default => sub { 'close' }
- );
+ isa => 'Str', is => 'rw', required => 1, default => sub { 'close' }
+ );
has close_label_cancel => (
- isa => 'Str', is => 'rw', required => 1, default => sub { 'cancel' }
- );
+ isa => 'Str', is => 'rw', required => 1, default => sub { 'cancel' }
+ );
sub fields { shift->_field_map }
my $constraint = $attr->type_constraint;
my $base_name = $constraint->name;
my $tried_isa = 0;
- CONSTRAINT: while (defined($constraint)) {
+ CONSTRAINT: while (defined($constraint)) {
my $name = $constraint->name;
if (eval { $name->can('meta') } && !$tried_isa++) {
foreach my $class ($name->meta->class_precedence_list) {
implements build_ordered_fields => as {
my $self = shift;
- $self->sort_by_spec($self->column_order, [keys %{$self->_field_map_}])};
+ my $ordered = $self->sort_by_spec($self->column_order, [keys %{$self->_field_map}]);
+ return [@{$self->_field_map}{@$ordered}];
};
implements can_apply => as {
my ($self) = @_;
- foreach my $field (values %{$self->_field_map}) {
+ foreach my $field ( @{ $self->ordered_fields } ) {
return 0 if $field->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 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
}
return $self->action->can_apply;
};
%extra = %$config;
}
my $field = $class->new(
- action => $self->action,
- attribute => $attr,
- name => $attr->name,
- location => join('-', $self->location, 'field', $attr->name),
- ctx => $self->ctx,
- %extra
- );
+ action => $self->action,
+ attribute => $attr,
+ name => $attr->name,
+ location => join('-', $self->location, 'field', $attr->name),
+ ctx => $self->ctx,
+ %extra
+ );
return ($attr_name => $field);
};
};
-1;
+ 1;
=head1 NAME
class Boolean, is DisplayField, which {
has '+value' => (isa => 'Bool');
- has '+layout' => (default => 'displayfield/value_string');
+ #has '+layout' => (default => 'displayfield/value_string');
has value_string => (isa => 'Str', is => 'rw', lazy_build => 1);
class Collection is 'Reaction::UI::ViewPort::DisplayField', which {
has '+value' => (isa => 'ArrayRef');
- has '+layout' => (default => 'displayfield/list');
+ #has '+layout' => (default => 'displayfield/list');
has value_names => (isa => 'ArrayRef', is => 'ro', lazy_build => 1);
class DateTime is DisplayField, which {
has '+value' => (isa => 'DateTime');
- has '+layout' => (default => 'displayfield/value_string');
+ #has '+layout' => (default => 'displayfield/value_string');
has value_string => (isa => 'Str', is => 'rw', lazy_build => 1);
class List is DisplayField, which {
has '+value' => (isa => 'ArrayRef');
- has '+layout' => (default => 'displayfield/list');
+ #has '+layout' => (default => 'displayfield/list');
has value_names => (isa => 'ArrayRef', is => 'ro', lazy_build => 1);
use aliased 'Reaction::UI::ViewPort::DisplayField';
class Number is DisplayField, which {
- has '+layout' => (default => 'displayfield/string');
+ #has '+layout' => (default => 'displayfield/string');
};
1;
class RelatedObject is DisplayField, which {
- has '+layout' => (default => 'displayfield/value_string');
+ #has '+layout' => (default => 'displayfield/value_string');
has value_string => (isa => 'Str', is => 'ro', lazy_build => 1);
class String is DisplayField, which {
has '+value' => (isa => 'Str');
- has '+layout' => (default => 'displayfield/string');
+ #has '+layout' => (default => 'displayfield/string');
};
1;
class Text is DisplayField, which {
has '+value' => (isa => 'Str');
- has '+layout' => (default => 'displayfield/text');
+ #has '+layout' => (default => 'displayfield/text');
};
1;
implements build_label => as {
my ($self) = @_;
- return join(' ', map { ucfirst } split('_', $self->name));
+ my $label = join(' ', map { ucfirst } split('_', $self->name));
+ print STDERR "Field " . $self->name . " has label '$label'\n";
+ return $label;
};
implements build_value => as {
class Boolean is 'Reaction::UI::ViewPort::Field', which {
has '+value' => (isa => 'Bool');
- has '+layout' => (default => 'checkbox');
+ #has '+layout' => (default => 'checkbox');
};
-1;
+1;
=head1 NAME
class ChooseMany is 'Reaction::UI::ViewPort::Field::ChooseOne', which {
- has '+layout' => (default => 'dual_select_group');
+ #has '+layout' => (default => 'dual_select_group');
has '+value' => (isa => 'ArrayRef');
my $listify = sub { # quick utility function, $listify->($arg)
class ChooseOne is 'Reaction::UI::ViewPort::Field', which {
- has '+layout' => (default => 'select');
+ #has '+layout' => (default => 'select');
has valid_values => (isa => 'ArrayRef', is => 'ro', lazy_build => 1);
has value_choices => (isa => 'ArrayRef', is => 'ro', lazy_build => 1);
class DateTime is 'Reaction::UI::ViewPort::Field', which {
has '+value' => (isa => 'DateTime');
-
- has '+layout' => (default => 'dt_textfield');
-
+
+ #has '+layout' => (default => 'dt_textfield');
+
has value_string => (
isa => 'Str', is => 'rw', lazy_build => 1,
trigger_adopt('value_string')
);
-
+
has value_string_default_format => (
isa => 'Str', is => 'rw', required => 1, default => sub { "%F %H:%M:%S" }
);
-
+
implements build_value_string => as {
my $self = shift;
#<mst> eval { $self->value } ... is probably the best solution atm
my $value = eval { $self->value };
return '' unless $self->has_value;
- my $format = $self->value_string_default_format;
+ my $format = $self->value_string_default_format;
return $value->strftime($format) if $value;
return '';
};
-
+
implements adopt_value_string => as {
my ($self) = @_;
my $value = $self->value_string;
$self->needs_sync(1);
}
};
-
+
override accept_events => sub {
('value_string', super());
};
};
-1;
+1;
=head1 NAME
class File is 'Reaction::UI::ViewPort::Field', which {
has '+value' => (isa => 'File', required => 0);
-
- has '+layout' => (default => 'file');
-
+
+ #has '+layout' => (default => 'file');
+
override apply_our_events => sub {
my ($self, $ctx, $events) = @_;
my $value_key = join(':', $self->location, 'value');
class Number is 'Reaction::UI::ViewPort::Field', which {
- has '+layout' => (default => 'textfield');
+ #has '+layout' => (default => 'textfield');
};
-1;
+1;
=head1 NAME
class Password is 'Reaction::UI::ViewPort::Field::String', which {
has '+value' => (isa => 'SimpleStr');
- has '+layout' => (default => 'password');
+ #has '+layout' => (default => 'password');
};
-1;
+1;
=head1 NAME
has '+value' => (isa => 'Str'); # accept over 255 chars in case, upstream
# constraint from model should catch it
-
- has '+layout' => (default => 'textfield');
+
+ #has '+layout' => (default => 'textfield');
};
-1;
+1;
=head1 NAME
class Text is 'Reaction::UI::ViewPort::Field', which {
has '+value' => (isa => 'Str');
- has '+layout' => (default => 'textarea');
+ #has '+layout' => (default => 'textarea');
};
-1;
+1;
=head1 NAME
class TimeRange is 'Reaction::UI::ViewPort::Field', which {
has '+value' => (isa => 'DateTime::SpanSet');
-
- has '+layout' => (default => 'timerange');
-
- has value_string =>
+
+ #has '+layout' => (default => 'timerange');
+
+ has value_string =>
(isa => 'Str', is => 'rw', lazy_fail => 1, trigger_adopt('value_string'));
-
+
has delete_label => (
isa => 'Str', is => 'rw', required => 1, default => sub { 'Delete' },
);
-
+
has parent => (
isa => 'Reaction::UI::ViewPort::TimeRangeCollection',
is => 'ro',
required => 1,
is_weak_ref => 1
);
-
+
implements build_value_string => as {
my $self = shift;
#return '' unless $self->has_value;
#return $self->value_string;
};
-
+
implements value_array => as {
my $self = shift;
return split(',', $self->value_string);
};
-
+
implements adopt_value_string => as {
my ($self) = @_;
my @values = $self->value_array;
if (length $values[$idx]) {
my ($epoch) = Time::ParseDate::parsedate($values[$idx], UK => 1);
$values[$idx] = DateTime->from_epoch( epoch => $epoch );
- }
+ }
}
$self->value($self->range_to_spanset(@values));
};
-
+
implements range_to_spanset => as {
my ($self, $time_from, $time_to, $repeat_from, $repeat_to, $pattern) = @_;
my $spanset = DateTime::SpanSet->empty_set;
hours => $time_from->hour,
minutes => $time_from->minute,
seconds => $time_from->second );
-
+
delete $args{'days'} if ($pattern eq 'daily');
delete @args{qw/hours days/} if ($pattern eq 'hourly');
$args{'days'} = $time_from->day if ($pattern eq 'monthly');
}
return $spanset;
};
-
+
implements delete => as {
my ($self) = @_;
$self->parent->remove_range_vp($self);
};
-
+
override accept_events => sub { ('value_string', 'delete', super()) };
};
-1;
+1;
=head1 NAME
push(@field_map, $self->build_fields_for($attr => $args));
}
- $self->_field_map({ @field_map });
+ my %field_map = @field_map;
+ $self->_field_map( \%field_map );
}
};
implements build_ordered_fields => as {
my $self = shift;
- $self->sort_by_spec($self->column_order, [keys %{$self->_field_map_}])};
+ my $ordered = $self->sort_by_spec($self->column_order, [keys %{$self->_field_map}]);
+ return [@{$self->_field_map}{@$ordered}];
};
implements build_simple_field => as {
return $self->build_simple_field(String, $attr, $args);
};
-
implements build_fields_for_type_ArrayRef => as {
my ($self, $attr, $args) = @_;
return $self->build_simple_field(List, $attr, $args)
return $self->build_simple_field(RelatedObject, $attr, $args);
};
-
no Moose;
no strict 'refs';
class TimeRangeCollection is 'Reaction::UI::ViewPort', which {
- has '+layout' => (default => 'timerangecollection');
-
+ #has '+layout' => (default => 'timerangecollection');
+
has '+column_order' => (
default => sub{[ qw/ time_from time_to pattern repeat_from repeat_to / ]},
);
-
+
has time_from => (
isa => 'Reaction::UI::ViewPort::Field::DateTime',
is => 'rw', lazy_build => 1,
);
-
+
has time_to => (
isa => 'Reaction::UI::ViewPort::Field::DateTime',
is => 'rw', lazy_build => 1,
);
-
+
has repeat_from => (
isa => 'Reaction::UI::ViewPort::Field::DateTime',
is => 'rw', lazy_build => 1,
);
-
+
has repeat_to => (
isa => 'Reaction::UI::ViewPort::Field::DateTime',
is => 'rw', lazy_build => 1,
);
-
+
has pattern => (
isa => 'Reaction::UI::ViewPort::Field::String',
# valid_values => [ qw/none daily weekly monthly/ ],
is => 'rw', lazy_build => 1,
);
-
+
has range_vps => (isa => 'ArrayRef', is => 'rw', lazy_build => 1,);
-
+
has max_range_vps => (isa => 'Int', is => 'rw', lazy_build => 1,);
-
+
has error => (
isa => 'Str',
is => 'rw',
required => 0,
);
-
+
has field_names => (
isa => 'ArrayRef', is => 'rw',
lazy_build => 1, clearer => 'clear_field_names',
);
-
+
has _field_map => (
isa => 'HashRef', is => 'rw', init_arg => 'fields',
clearer => '_clear_field_map',
predicate => '_has_field_map',
set_or_lazy_build('field_map'),
);
-
+
has on_next_callback => (
isa => 'CodeRef',
is => 'rw',
predicate => 'has_on_next_callback',
);
-
+
implements fields => as { shift->_field_map };
-
+
implements build_range_vps => as { [] };
-
+
implements spanset => as {
my ($self) = @_;
my $spanset = DateTime::SpanSet->empty_set;
$spanset = $spanset->union($_->value) for @{$self->range_vps};
return $spanset;
};
-
+
implements range_strings => as {
my ($self) = @_;
return [ map { $_->value_string } @{$self->range_vps} ];
};
-
+
implements remove_range_vp => as {
- my ($self, $to_remove) = @_;
+ my ($self, $to_remove) = @_;
$self->range_vps([ grep { $_ != $to_remove } @{$self->range_vps} ]);
$self->_clear_field_map;
$self->clear_field_names;
};
-
+
implements add_range_vp => as {
my ($self) = @_;
if ($self->can_add) {
push(@{$self->range_vps}, $field);
}
};
-
+
implements build_field_map => as {
my ($self) = @_;
my %map;
}
return \%map;
};
-
+
implements build_field_names => as {
my ($self) = @_;
return [
@{$self->column_order}
];
};
-
+
implements can_add => as {
my ($self) = @_;
my $error;
if ($self->time_to->has_value && $self->time_from->has_value) {
my $time_to = $self->time_to->value;
my $time_from = $self->time_from->value;
-
+
my ($pattern, $repeat_from, $repeat_to) = ('','','');
$pattern = $self->pattern->value if $self->pattern->has_value;
$repeat_from = $self->repeat_from->value if $self->repeat_from->has_value;
$repeat_to = $self->repeat_to->value if $self->repeat_to->has_value;
-
+
my $duration = $time_to - $time_from;
if ($time_to < $time_from) {
$error = 'Please make sure that the Time To is after the Time From.';
$self->error($error);
return !defined($error);
};
-
+
implements build_simple_field => as {
my ($self, $class, $name, $args) = @_;
return $class->new(
%$args
);
};
-
+
implements build_time_to => as {
my ($self) = @_;
return $self->build_simple_field(DateTime, 'time_to', {});
};
-
+
implements build_time_from => as {
my ($self) = @_;
return $self->build_simple_field(DateTime, 'time_from', {});
};
-
+
implements build_repeat_to => as {
my ($self) = @_;
return $self->build_simple_field(DateTime, 'repeat_to', {});
};
-
+
implements build_repeat_from => as {
my ($self) = @_;
return $self->build_simple_field(DateTime, 'repeat_from', {});
};
-
+
implements build_pattern => as {
my ($self) = @_;
return $self->build_simple_field(String, 'pattern', {});
};
-
+
implements next => as {
$_[0]->on_next_callback->(@_);
};
-
+
override accept_events => sub {
my $self = shift;
('add_range_vp', ($self->has_on_next_callback ? ('next') : ()), super());
};
-
+
override child_event_sinks => sub {
my ($self) = @_;
return ((grep { ref($_) =~ 'Hidden' } values %{$self->_field_map}),
(grep { ref($_) !~ 'Hidden' } values %{$self->_field_map}),
super());
};
-
+
override apply_events => sub {
my ($self, $ctx, $events) = @_;
-
+
# auto-inflate range fields based on number from hidden field
-
+
my $max = $events->{$self->location.':max_range_vps'};
my @range_vps = map {
TimeRange->new(
$self->range_vps(\@range_vps);
$self->_clear_field_map;
$self->clear_field_names;
-
+
# call original event handling
-
+
super();
-
- # repack range VPs in case of deletion
-
+
+ # repack range VPs in case of deletion
+
my $prev_idx = -1;
-
+
foreach my $vp (@{$self->range_vps}) {
my $cur_idx = ($vp->name =~ m/range-(\d+)/);
if (($cur_idx - $prev_idx) > 1) {
};
-1;
+1;
=head1 NAME
Returns: ArrayRef of Str consisting of the value_strings of all TimeRange
VPs
-
+
=head2 remove_range_vp
Arguments: $to_remove
-
+
=head2 add_range_vp
Arguments: $to_add
widget renders [qw/header fields buttons footer/
=> { viewport => func('self','viewport') } ];
- fields renders [viewport over func('viewport','ordered_fields')];
+ fields renders [field over func('viewport','ordered_fields')];
+ field renders [ 'viewport' ];
- buttons renders [ string {"DUMMY"} ], {message => func('viewport','message');
+ buttons renders [ string {"DUMMY"} ],
+ {message => sub{ $_{viewport}->can('message') ? $_{viewport}->message : "" } };
header renders [ string {"DUMMY"} ];
footer renders [ string {"DUMMY"} ];
__END__;
-
=head1 NAME
Reaction::UI::Widget::ActionForm
use Reaction::UI::WidgetClass;
-class Text, which {
+class DisplayField, which {
widget renders [ qw/label value/ => { viewport => func(self => 'viewport') } ];
label renders [ string { $_{viewport}->label } ];
value renders [ string { $_{viewport}->value } ];
1;
+__END__;
+
=head1 NAME
Reaction::UI::Widget::DisplayField
1;
+__END__;
+
=head1 NAME
Reaction::UI::Widget::Field
1;
+__END__;
+
=head1 NAME
Reaction::UI::Widget::Field::Boolean
available_values renders [ option over func('viewport', 'available_value_choices') ];
selected_values renders [ option over func('viewport', 'current_value_choices') ];
option renders [string {"DUMMY"}], { v_value => sub {$_->{value}}, v_name => sub {$_->{name}} };
+ action_buttons renders [ string {"DUMMY"} ];
};
1;
+__END__;
=head1 NAME
1;
+__END__;
+
=head1 NAME
Reaction::UI::Widget::Field::String
use Reaction::UI::WidgetClass;
use aliased 'Reaction::UI::ViewPort::ListView' => 'ListView_VP';
-class ListView which {
+class ListView, which {
has 'viewport' => (isa => ListView_VP, is => 'ro', required => 1);
widget renders [
qw(header body) => { viewport => func(self => 'viewport') }
];
-
+
header renders [ header_entry over func(viewport => 'field_names') ];
-
+
header_entry renders [ string { $_{viewport}->field_label_map->{ $_ } } ];
-
+
body renders [ row over func(viewport => 'current_page_collection') ];
-
+
row renders [
col_entry over func(viewport => 'field_names') => { row => $_ }
];
-
+
col_entry renders [
string {
my $proto = $_{row}->$_;
1;
+__END__;
+
=head1 NAME
Reaction::UI::Widget::ListView
use Reaction::UI::WidgetClass;
class ObjectView, which {
- widget renders [ fields => { viewport => func('self', 'viewport') } ];
- fields renders [ viewport over func('viewport','ordered_fields') } ];
+ widget renders [ fields => { viewport => func('self', 'viewport') } ];
+ fields renders [ field over func('viewport', 'ordered_fields') ];
+ field renders [ 'viewport' ];
};
1;
=for layout fields
+<p> [% content %] </p>
+
+=for layout field
+
[% content %] <br />
=for layout buttons
=for layout label
-<strong > [ % content %]: </strong>
+<strong > [% content | html %]: </strong>
=for layout value
-[% content %]
+[% content | html %]
=cut
\ No newline at end of file
=for layout label
-<strong > [ % content %]: </strong>
+<strong > [% content | html %]: </strong>
=for layout list
<ul>
-[% item %]
+[% content %]
</ul>
=for layout item
-<li>[% content %]</li>
+<li>[% content | html %]</li>
=cut
=for layout label
-<strong > [ % content %]: </strong>
+<strong> [% content | html %]: </strong>
=for layout value
-[% content %]
+[% content | html %]
=cut
=for layout label
-<strong > [ % content %]: </strong>
+<strong > [% content | html %]: </strong>
=for layout list
<ul>
-[% item %]
+[% content %]
</ul>
=for layout item
-<li>[% content %]</li>
+<li>[% content | html %]</li>
=cut
\ No newline at end of file
=for layout label
-<strong > [ % content %]: </strong>
+<strong> [% content | html %]: </strong>
=for layout value
-[% content %]
+[% content | html %]
=cut
=for layout label
-<strong > [ % content %]: </strong>
+<strong> [% content | html %]: </strong>
=for layout value
-[% content %]
+[% content | html %]
=cut
=for layout label
-<strong > [ % content %]: </strong>
+<strong> [% content | html %]: </strong>
=for layout value
-[% content %]
+[% content | html %]
=cut
\ No newline at end of file
=for layout label
-<strong > [ % content %]: </strong>
+<strong> [% content | html %]: </strong>
=for layout value
-[% content %]
+[% content | html %]
=cut
\ No newline at end of file
=for layout label
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <label for="[% id %]"> [% content | html %]: </label>
-[% END %]
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <label> [% content_str | html %]: </label>
+[% END; %]
=for layout message
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <span> [% content | html %] </span>
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <span> [% content_str | html %] </span> <br />
[% END %]
=cut
=for layout action_buttons
-<input type="submit" value=">>" name="[% viewport.event_id_for('add_all_values') | html %]" />
+<input type="submit" value=">>" name="[% viewport.event_id_for('add_all_values') | html %]" /> <br />
<input type="submit" value=">" name="[% viewport.event_id_for('do_add_values') | html %]" /> <br />
<input type="submit" value="<" name="[% viewport.event_id_for('do_remove_values') | html %]" /> <br />
<input type="submit" value="<<" name="[% viewport.event_id_for('remove_all_values') | html %]" /> <br />
=for layout label
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <label> [% content | html %]: </label>
-[% END %]
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <label> [% content_str | html %]: </label>
+[% END; %]
=for layout message
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <span> [% content | html %] </span> <br />
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <span> [% content_str | html %] </span> <br />
[% END %]
=cut
=for layout label
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <label for="[% id | html %]"> [% content | html %]: </label>
-[% END %]
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <label> [% content_str | html %]: </label>
+[% END; %]
=for layout message
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <span> [% content | html %] </span>
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <span> [% content_str | html %] </span> <br />
[% END %]
=cut
=for layout label
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <label for="[% id | html %]"> [% content | html %]: </label>
-[% END %]
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <label> [% content_str | html %]: </label>
+[% END; %]
=for layout message
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <span> [% content | html %] </span>
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <span> [% content_str | html %] </span> <br />
[% END %]
=cut
=for layout label
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <label for="[% id | html %]"> [% content | html %]: </label>
-[% END %]
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <label> [% content_str | html %]: </label>
+[% END; %]
=for layout message
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <span> [% content | html %] </span>
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <span> [% content_str | html %] </span> <br />
[% END %]
=cut
=for layout label
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <label for="[% id | html %]"> [% content | html %]: </label>
-[% END %]
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <label> [% content_str | html %]: </label>
+[% END; %]
=for layout message
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <span> [% content | html %] </span>
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <span> [% content_str | html %] </span> <br />
[% END %]
-=cut
\ No newline at end of file
+=cut
=for layout label
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <label for="[% id | html %]"> [% content | html %]: </label>
-[% END %]
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <label> [% content_str | html %]: </label>
+[% END; %]
=for layout message
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <span> [% content | html %] </span>
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <span> [% content_str | html %] </span> <br />
[% END %]
-=cut
\ No newline at end of file
+=cut
=for layout label
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <label for="[% id | html %]"> [% content | html %]: </label>
-[% END %]
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <label> [% content_str | html %]: </label>
+[% END; %]
=for layout message
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <span> [% content | html %] </span>
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <span> [% content_str | html %] </span> <br />
[% END %]
=cut
=for layout label
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <label for="[% id | html %]"> [% content | html %]: </label>
-[% END %]
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <label> [% content_str | html %]: </label>
+[% END; %]
=for layout message
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <span> [% content | html %] </span>
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <span> [% content_str | html %] </span> <br />
[% END %]
=cut
=for layout label
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <label for="[% id | html %]"> [% content | html %]: </label>
-[% END %]
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <label> [% content_str | html %]: </label>
+[% END; %]
=for layout message
<!-- This conditional goes away when mst comes up with something better -->
-[% IF content %]
- <span> [% content | html %] </span>
+[% content_str = GET content; %]
+[% IF content_str.length; %]
+ <span> [% content_str | html %] </span> <br />
[% END %]
=cut
--- /dev/null
+=for layout widget
+
+<p>I hate programming.</p>
+
+=cut
\ No newline at end of file
--- /dev/null
+=for layout widget
+<!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>Component UI Test Title</title>
+
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <link rel="stylesheet" type="text/css" href="/static/componentui-basic.css" />
+
+</head>
+
+<body>
+ <div id="container">
+ <div id="header">
+ [% header %]
+ </div>
+
+ <div id="nav">
+ [% menu %]
+ </div>
+
+ <div id="contents">
+ <div id="wrapper">
+ [% sidebar %]
+ [% main_content %]
+ </div>
+ <div class="spacer"></div>
+ </div>
+ </div>
+</body>
+
+</html>
+
+=for layout main_content
+
+ [% content %]
+
+=for layout header
+
+<h1>Component UI Header</h1>
+
+=for layout sidebar
+ <div class="sidebar">
+ [% content %]
+ </div>
+
+=for layout menu
+ <ul class="menu">
+ <li> <a href="/testmodel/foo">Foo</a> </li>
+ <li> <a href="/testmodel/bar">Bar</a> </li>
+ <li> <a href="/testmodel/baz">Baz</a> </li>
+ </ul>
+=cut
\ No newline at end of file
=for layout fields
- [% content %]<br>
+ <p> [% content %] </p>
+
+=cut
+
+=for layout field
+
+ [% content %] <br>
=cut
--- /dev/null
+html {
+ min-width: 915px;
+} /*IE7*/
+
+body {
+ color: #393733;
+ margin: 0;
+ padding: 0 20px;
+ text-align: center;
+ background: #DDDDDD;
+}
+
+img {
+ border: none;
+}
+
+p {
+ line-height: 1.4;
+}
+
+input{
+ line-height: 1;
+}
+
+#container {
+ text-align: left;
+ margin: 0 auto;
+ max-width: 1200px;
+ position: relative;
+}
+
+#wrapper {
+ padding: 15px 0 0 19px;
+ min-height: 500px;
+} /*IE6*/
+
+#contents {
+ clear: both;
+ padding: 0 15px 30px 0;
+ margin-top: 7px;
+ background: #FFFFFF;
+}
+
+.spacer{ clear: both; }
+.sidebar {
+ float: right;
+ width: 300px;
+ clear: both;
+ margin: 0 0 2em 0;
+ min-height: 500px;
+}
+.sidebar_section {
+ margin: 1em 0 1em 0;
+ min-height: 100px;
+}
+
+.sidebar_section h2{
+ border-bottom: 2px solid #036;
+ padding: 0 1em 0 0em;
+ font-size: 120%;
+ text-align: right;
+}
+
+#header {
+ background: #036;
+ color: #fff;
+ float: left;
+ width: 100%;
+ margin-bottom: 0px;
+ border-bottom: 1px solid white;
+ position: relative;
+ text-align: left;
+}
+
+#header h1 {
+ font-size: 150%;
+ padding: .2em;
+ margin: .2em;
+}
+
+#nav {
+ background: #036;
+ color: #fff;
+ float: left;
+ width: 100%;
+ margin-bottom: 5px;
+ position: relative;
+ text-align: right;
+}
+
+#nav .menu {
+ display: inline
+ width: 75%;
+ float: left;
+ margin: 0px;
+ padding: 0px;
+ list-style-type: none;
+ color: #FFFFFF;
+ background: #036
+}
+
+#nav .menu li {
+ display: inline;
+}
+
+#nav .menu li a {
+ float: left;
+ width: 7em;
+ color: #FFFFFF;
+ background:color #036;
+ padding: 0.2em .2em;
+ text-decoration: none;
+ border-right: 1px solid #fff;
+ text-align: center;
+ font-size: 105%;
+ font-weight: bold;
+}
+
+#nav .menu li a:hover {
+ background-color: #369;
+ color: #fff;
+}
+
+#login-status{
+ padding: .2em 1em 0 0;
+ font-size: 80%;
+}
+
+#search{
+ float: right;
+ width: 300;
+ padding: 1em;
+}
+#searchbox{
+ line-height: 1.4;
+ font-size: 90%;
+ border: 2px solid #FFF;
+ padding-left: 3px;
+}
+#searchsub{
+ background-color: #036;
+ font-weight: bold;
+ font-size: 90%;
+ color: white;
+ border: 2px solid #369;
+}
\ No newline at end of file