search spec components factored out of T365
[catagits/Reaction.git] / lib / Reaction / Manual / Widgets.pod
CommitLineData
f9b32c83 1=head1 NAME
2
3Reaction::Manual::Widgets - Creating and extending Reaction Widgets
4
5=head1 WHAT IS A WIDGET
6
7A widget represents the Perl code used by the layout. Which widget to use
8can be set with the C<=widget> directive. For more on templates, look at
9L<Reaction::Manual::Templates>.
10
11The widget that is used defaults to a name built by the controller class
12and the name of the action. E.g. the action C<MyApp::Controller::Foo-E<gt>bar>
13would assume a widget named C<Foo::Bar> and look for it in the C<widget_search_path>
14defined in the C<share/skin/$skin_name/skin.conf> or the C<share/skin/defaults.conf>.
15
16=head1 A SIMPLE WIDGET
17
18The simplest widget would be this:
19
20 package MyApp::Widget::Foo;
21 use Reaction::UI::WidgetClass;
22
23 use namespace::clean -except => 'meta';
24
25 __PACKAGE__->meta->make_immutable;
26
27 1;
28
29The use of L<Reaction::UI::WidgetClass> will import L<strict>, L<warnings>, L<Moose> and
30L<Reaction::Class>. It will also set L<Reaction::UI::Widget> as the base class of the
31widget. If you want to extend an existing widget rather than create a new one, use
32L<Moose/extends>.
33
34=head1 FRAGMENTS
35
36Layouts can use the C<=for layout $fragmet> POD syntax to define fragments and use them
37like usual L<Template> variables.
38
39But sometimes it is desirable to have a fragment that invokes Perl code in the widget
40to render certain outputs. For this, the widget has its own mechanisms to handle
41fragments.
42
43=head2 Implementing a fragment
44
45A layout fragment can access the widgets attributes and other fragments like normal
46L<Template> variables. But if a widget implements a fragment, that implementation will
47be used to provide the data and some additional control over the rendering of the layout.
48
49This abstracts the data manipulation view logic from the layouting view logic.
50
51A widget can a new fragment like this:
52
53 package MyApp::Widget::Foo;
54 use Reaction::UI::WidgetClass;
55
56 use namespace::clean -except => 'meta';
57
58 implements fragment now {
59 arg timestamp => time();
60 };
61
62 __PACKAGE__->meta->make_immutable;
63
64 1;
65
66Now we can layout the provided data like this:
67
68 =widget Foo
69
70 =for layout widget
71
72 <h1>Info:</h1>
73
74 [% now %]
75
76 =for layout now
77
78 <p>Timestamp: [% timestamp %]</p>
79
80 =cut
81
82The C<widget> fragment is the root fragment of every widget. The widget directive sets
83the desired widget to C<Foo>. One of our C<widget_search_path>s should contain
84C<MyApp::Widget>, so the widget class defined above can be found.
85
86The C<widget> fragment defined here will render the C<now> fragment implemented by the
87widget and layed out by the layout template. Assuming the current timestamp is
88C<1234567890>, the rendered output will look like this:
89
90 <h1>Info:</h1>
91
92 <p>Timestamp: 1234567890</p>
93
94Let us take a closer look at the fragment implementation in the widget:
95
96 implements fragment now {
97 arg timestamp => time();
98 };
99
100This syntax might look a bit unusual, but it's not a source filter. The declarative style
101is provided by L<Devel::Declare>. This implements a fragment named C<now> in the current
102widget. The body uses the C<arg> keyword to provide a new argument C<timestamp> to the
103template with the value of the current return value of C<time()>.
104
105=head1 Extending a fragment
106
107Sometimes you don't want to redefine how a fragment is implemented, but merely extend on
108the current definition. An example would be adding the total number of entries in a
109collection below the listing of the entries.
110
111Fortunately, L<Reaction> is based on L<Moose> and trying to stay as flexible as possible.
112In this case, Reaction allows us to use Moose method modifiers with fragments:
113
114 package MyApp::Widget::Bar;
115 use Reaction::UI::WidgetClass;
116
117 use namespace::clean -except => 'meta';
118
119 extends 'MyApp::Widget::Foo';
120
121 around fragment now {
122 call_next;
123 arg timestamp => sprintf '"%s"', $_{timestamp};
124 };
125
126 __PACKAGE__->meta->make_immutable;
127
128 1;
129
130The C<call_next> keyword will call the next implementation in the inheritance tree, just
131like it would call the next fragment when used in the layout template.
132
133The global hash C<%_> is used to provide the fragment arguments to the code block
134implementing it. For example, the viewport would be available in C<$_{viewport}>.
135
136Besides C<around>, you can also use C<before> and C<after>.
137
138=head1 Iterating over a fragment
139
140Many fragments are intended to be iterated over a collection of items. An example
141implementation of this is listed below:
142
143 package MyApp::Widget::Baz
144 use Reaction::UI::WidgetClass;
145
146 use DateTime;
147
148 use namespace::clean -except => 'meta';
149
150 my @Fields = qw( year month day hour minute second );
151
152 implements fragment now {
153 arg dt_obj => DateTime->now;
154 render datetime_field => over [@Fields];
155 };
156
157 implements fragment datetime_field {
158 arg field_name => $_;
159 arg field_value => $_{dt_obj}->$_();
160 };
161
162 __PACKAGE__->meta->make_immutable;
163
164 1;
165
166Which could have a layout template like this:
167
168 =widget Baz
169
170 =for layout widget
171
172 <h1>Now:</h1>
173
174 [% now %]
175
176 =for layout now
177
178 <ul>
179 [% content %]
180 </ul>
181
182 =for layout datetime_field
183
184 <li>[% field_name | ucfirst %]: [% field_value %]</li>
185
186 =cut
187
188The C<widget> fragment defined in the layout template will render the C<now> fragment
189implemented in the widget class. It is setting the C<dt_obj> argument to a L<DateTime>
190object representing the current date and time. Then it will C<render> the fragment
191C<datetime_field> once for every item in the C<@Fields> array.
192
193The global topic variable C<$_> will be set to each corresponding value in the arguments
194to C<over>. The C<datetime_field> fragment will then for each field name set C<field_name>
195to the aforementioned value, and store the result of the method of that name on the C<dt_obj>
196in the C<field_value> argument.
197
198The layout simply formats and puts the components in place.
199
200=head1 WIDGETS PROVIDED BY REACTION
201
202=over
203
204=item L<Reaction::UI::Widget::SiteLayout>
205
206The common wrapper around the fully rendered site.
207
208=item L<Reaction::UI::Widget::ListView>
209
210Extends L<Reaction::UI::Widget::Grid> to provide actions and paging.
211
212=item L<Reaction::UI::Widget::Object>
213
214Rendering of a single object by a collection of viewports.
215
216=item L<Reaction::UI::Widget::Container>
217
218A base class that automatically provides callbacks to render attributes containing
219viewports on the current viewport.
220
221=item L<Reaction::UI::Widget::Collection>
222
223Renders a collection of member viewports in the current viewport.
224
225=item L<Reaction::UI::Widget::Grid>
226
227A subclass of L<Reaction::UI::Widget::Collection> providing header and footer
228as well as member actions. The C<default> skin contains layout sets to output
229this widget as a HTML table.
230
231=item L<Reaction::UI::Widget::Image>
232
233An image with optional width and height properties.
234
235=item L<Reaction::UI::Widget::Field>
236
237Base widget for fields. Contains a list of subclasses.
238
239=item L<Reaction::UI::Widget::Action>
240
241A widget representing a mutation of an object.
242
243=item L<Reaction::UI::Widget::Action::Link>
244
245Object mutation widget rendering a hyperlink.
246
247=item L<Reaction::UI::Widget::Data>
248
249Renders the data stored in the viewport's C<args> attribute.
250
251=item L<Reaction::UI::Widget::Value>
252
253Will take the C<value_string> or C<value> viewport method return value and provide it as
254argument C<value> to the C<widget> fragment. It also contains a list of subclasses.
255
256=item L<Reaction::UI::Widget::URI>
257
258A hyperlink reference via an URI stored in the viewport.
259
260=back
261
262=head1 SEE ALSO
263
264=over
265
266=item * L<Reaction::UI::WidgetClass>
267
268=item * L<Reaction::UI::Widget>
269
270=item * L<Reaction::Manual::Templates>
271
272=back
273
274=head1 AUTHORS
275
276See L<Reaction::Class> for authors.
277
278=head1 LICENSE
279
280See L<Reaction::Class> for the license.
281
282=cut
283