Commit | Line | Data |
ddccc6a2 |
1 | package Reaction::UI::ViewPort::Role::Actions; |
b8faba69 |
2 | |
3 | use Reaction::Role; |
37728bba |
4 | use Reaction::UI::ViewPort::URI; |
b8faba69 |
5 | |
81393881 |
6 | use namespace::clean -except => [ qw(meta) ]; |
7 | |
37728bba |
8 | has actions => ( |
9 | is => 'ro', |
10 | isa => 'ArrayRef', |
11 | lazy_build => 1 |
12 | ); |
13 | |
14 | has action_order => ( |
15 | is => 'ro', |
16 | isa => 'ArrayRef' |
17 | ); |
18 | |
565a1fc7 |
19 | has action_filter => ( |
20 | isa => 'CodeRef', is => 'ro', |
565a1fc7 |
21 | ); |
22 | |
37728bba |
23 | has action_prototypes => ( |
24 | is => 'ro', |
25 | isa => 'HashRef', |
26 | required => 1, |
27 | default => sub{ {} } |
28 | ); |
29 | |
30 | has computed_action_order => ( |
31 | is => 'ro', |
32 | isa => 'ArrayRef', |
33 | lazy_build => 1 |
34 | ); |
35 | |
0caf173e |
36 | sub _filter_action_list { |
37 | my $self = shift; |
38 | my $actions = [keys %{$self->action_prototypes}]; |
39 | return $self->has_action_filter ? |
40 | $self->action_filter->($actions, $self->model) |
41 | : $actions; |
42 | } |
43 | |
37728bba |
44 | sub _build_computed_action_order { |
45 | my $self = shift; |
46 | my $ordered = $self->sort_by_spec( |
47 | ($self->has_action_order ? $self->action_order : []), |
0caf173e |
48 | $self->_filter_action_list |
37728bba |
49 | ); |
0caf173e |
50 | return $ordered; |
37728bba |
51 | } |
81393881 |
52 | |
81393881 |
53 | sub _build_actions { |
54 | my ($self) = @_; |
55 | my (@act, $i); |
56 | my $ctx = $self->ctx; |
57 | my $loc = $self->location; |
37728bba |
58 | my $target = $self->model; |
59 | |
60 | foreach my $proto_name ( @{ $self->computed_action_order } ) { |
61 | my $proto = $self->action_prototypes->{$proto_name}; |
62 | my $uri = $proto->{uri} or confess('uri is required in prototype action'); |
63 | my $label = exists $proto->{label} ? $proto->{label} : $proto_name; |
a33275e9 |
64 | my $layout = exists $proto->{layout} ? $proto->{layout} : 'uri'; |
a841aae8 |
65 | my $layout_args = exists $proto->{layout_args} ? $proto->{layout_args} : {}; |
37728bba |
66 | |
67 | my $action = Reaction::UI::ViewPort::URI->new( |
68 | location => join ('-', $loc, 'action', $i++), |
69 | uri => ( ref($uri) eq 'CODE' ? $uri->($target, $ctx) : $uri ), |
70 | display => ( ref($label) eq 'CODE' ? $label->($target, $ctx) : $label ), |
a33275e9 |
71 | layout => ( ref($layout) eq 'CODE' ? $layout->($target, $ctx) : $layout ), |
a841aae8 |
72 | layout_args => ( ref($layout_args) eq 'CODE' ? $layout_args->($target, $ctx) : $layout_args ), |
37728bba |
73 | ); |
81393881 |
74 | push(@act, $action); |
75 | } |
76 | return \@act; |
37728bba |
77 | } |
81393881 |
78 | |
b8faba69 |
79 | 1; |
2dba7201 |
80 | |
81 | __END__; |
82 | |
83 | =head1 NAME |
84 | |
85 | Reaction::UI::ViewPort::Role::Actions |
86 | |
87 | =head1 DESCRIPTION |
88 | |
89 | A role to ease attaching actions to L<Reaction::InterfaceModel::Object>s |
90 | |
91 | =head1 ATTRIBUTES |
92 | |
93 | =head2 actions |
94 | |
91140599 |
95 | Read-only, lazy-building ArrayRef of URI objects pointing to actions. |
3be50b19 |
96 | |
2dba7201 |
97 | =head2 action_prototypes |
98 | |
3be50b19 |
99 | A HashRef of prototypes for building the Action links. The prototypes should be |
100 | composed like these: |
101 | |
102 | my %action_prototypes = ( |
103 | example_action => { label => 'Example Action', uri => $uri_obj }, |
104 | ); |
105 | |
106 | #or you can get fancy and do something like what is below: |
107 | sub make_label{ |
108 | my($im, $ctx) = @_; #InterfaceModel::Object/Collection, Catalyst Context |
109 | return 'label_text'; |
110 | } |
111 | sub make_uri{ |
112 | my($im, $ctx) = @_; #InterfaceModel::Object/Collection, Catalyst Context |
113 | return return $ctx->uri_for('some_action'); |
114 | } |
115 | my %action_prototypes = ( |
116 | example_action => { label => \&make_label, uri => \&make_uri }, |
117 | ); |
118 | |
119 | =head2 action_order |
120 | |
121 | User-provided ArrayRef with how the actions should be ordered eg |
122 | |
123 | action_order => [qw/view edit delete/] |
124 | |
125 | =head2 computed_action_order |
126 | |
91140599 |
127 | Read-only lazy-building ARRAY ref. The final computed action order. This may |
128 | differ from the C<action_order> provided if you any actions were not included |
129 | in that list. |
130 | |
131 | =head1 METHODS |
132 | |
133 | =head2 _build_actions |
134 | |
135 | Cycle through the C<computed_action_order> and create a new |
136 | L<ViewPort::URI|Reaction::UI::ViewPort::URI> object for each action using the |
137 | provided prototypes. |
138 | |
139 | =head2 _build_computed_action_order |
140 | |
141 | Compute the final action ordering by using the provided C<action_order> as a |
142 | spec to order all the present actions (the keys of C<action_prototypes>) |
143 | |
144 | =head1 ACTION PROTOTYPES |
145 | |
146 | Action prototypes are simply hashrefs that must contain a C<uri> key and may |
147 | contain a C<label> key. The label can be anything that the display attribute of |
148 | L<ViewPort::URI|Reaction::UI::ViewPort::URI> will accept, usually a scalar or a |
149 | ViewPort. The value for C<uri> may be either a scalar, a L<URI> object (or |
150 | anything that C<ISA URI>). |
151 | |
152 | Additionally, both C<label> and C<uri> can be CODE refs. In this case, the code |
153 | will be executed at C<_build_actions> time and will recieve two arguments, the |
154 | value returned by C<model> and the value returned by C<ctx> in that order. Both |
155 | of these methods should be implemented in the consuming class. By convention, |
156 | model refers to the target of the action, an C<InterfaceModel::Object> in the |
157 | case of a member action and an C<InterfaceModel::Collection> in the case of a |
158 | Collection action. C<ctx> should be the current Catalyst context. |
3be50b19 |
159 | |
2dba7201 |
160 | =head1 AUTHORS |
161 | |
162 | See L<Reaction::Class> for authors. |
163 | |
164 | =head1 LICENSE |
165 | |
166 | See L<Reaction::Class> for the license. |
167 | |
168 | =cut |