allow redirect_to a url parameter
[catagits/Reaction.git] / lib / Reaction / UI / LayoutSet.pm
CommitLineData
7adfd53f 1package Reaction::UI::LayoutSet;
2
3use Reaction::Class;
4use File::Spec;
5
81393881 6use namespace::clean -except => [ qw(meta) ];
7adfd53f 7
7adfd53f 8
81393881 9has 'layouts' => (is => 'ro', default => sub { {} });
7adfd53f 10
81393881 11has 'name' => (is => 'ro', required => 1);
e22de101 12
81393881 13has 'source_file' => (is => 'ro', required => 1);
1c41e332 14
81393881 15has 'widget_class' => (
16 is => 'rw', lazy_fail => 1, predicate => 'has_widget_class'
17);
f2fef590 18
81393881 19has 'widget_type' => (is => 'rw', lazy_build => 1);
f2fef590 20
81393881 21has 'super' => (is => 'rw', predicate => 'has_super');
22sub BUILD {
23 my ($self, $args) = @_;
24 my @path = @{$args->{search_path}||[]};
25 confess "No skin object provided" unless $args->{skin};
26 confess "No top skin object provided" unless $args->{top_skin};
27 $self->_load_file($self->source_file, $args);
28 unless ($self->has_widget_class) {
29 $self->widget_class($args->{skin}->widget_class_for($self));
30 }
31};
32sub widget_order_for {
33 my ($self, $name) = @_;
34 return (
35 ($self->has_layout($name)
36 ? ([ $self->widget_class, $self ]) #;
37 : ()),
38 ($self->has_super
39 ? ($self->super->widget_order_for($name))
40 : ()),
41 );
42};
43sub layout_names {
44 my ($self) = @_;
45 my %seen;
46 return [
47 grep { !$seen{$_}++ }
48 keys %{shift->layouts},
aa8c0c90 49 ($self->has_super
81393881 50 ? (@{$self->super->layout_names})
51 : ())
52 ];
53};
54sub has_layout { exists $_[0]->layouts->{$_[1]} };
55sub _load_file {
56 my ($self, $file, $build_args) = @_;
57 my $data = $file->slurp;
4edebf11 58 utf8::decode($data)
59 unless utf8::is_utf8($data);
81393881 60 my $layouts = $self->layouts;
61 # cheesy match for "=for layout name ... =something"
62 # final split group also handles last in file, (?==) is lookahead
63 # assertion for '=' so "=for layout name1 ... =for layout name2"
64 # doesn't have the match pos go past the latter = and lose name2
65 while ($data =~ m/=(.*?)\n(.*?)(?:\n(?==)|$)/sg) {
66 my ($data, $text) = ($1, $2);
67 if ($data =~ /^for layout (\S+)/) {
68 my $fname = $1;
69 $text =~ s/^(?:\s*\r?\n)+//; #remove leading empty lines
70 $text =~ s/[\s\r\n]+$//; #remove trailing whitespace
71 $layouts->{$fname} = $text;
72 } elsif ($data =~ /^extends (\S+)/) {
73 my $super_name = $1;
74 my $skin;
75 if ($super_name eq 'NEXT') {
76 confess "No next skin and layout extends NEXT"
77 unless $build_args->{next_skin};
78 $skin = $build_args->{next_skin};
79 $super_name = $self->name;
aa8c0c90 80 } else {
81393881 81 $skin = $build_args->{top_skin};
aa8c0c90 82 }
81393881 83 $self->super($skin->create_layout_set($super_name));
84 } elsif ($data =~ /^widget (\S+)/) {
85 my $widget_type = $1;
86 $self->widget_type($1);
87 } elsif ($data =~ /^cut/) {
88 # no-op
89 } else {
90 confess "Unparseable directive ${data} in ${file}";
7adfd53f 91 }
81393881 92 }
93};
94sub _build_widget_type {
95 my ($self) = @_;
96 my $widget = join('', map { ucfirst($_) } split('_', $self->name));
97 $widget = join('::', map { ucfirst($_) } split('/', $widget));
7adfd53f 98
81393881 99 #print STDERR "--- ", $self->name, " maps to widget $widget \n";
6ab43711 100
81393881 101 return $widget;
102};
6ab43711 103
81393881 104__PACKAGE__->meta->make_immutable;
7b78a39d 105
7adfd53f 106
1071;