Commit | Line | Data |
f9b32c83 |
1 | =head1 NAME |
2 | |
3 | Reaction::Manual::Widgets - Creating and extending Reaction Widgets |
4 | |
5 | =head1 WHAT IS A WIDGET |
6 | |
7 | A widget represents the Perl code used by the layout. Which widget to use |
8 | can be set with the C<=widget> directive. For more on templates, look at |
9 | L<Reaction::Manual::Templates>. |
10 | |
11 | The widget that is used defaults to a name built by the controller class |
12 | and the name of the action. E.g. the action C<MyApp::Controller::Foo-E<gt>bar> |
13 | would assume a widget named C<Foo::Bar> and look for it in the C<widget_search_path> |
14 | defined in the C<share/skin/$skin_name/skin.conf> or the C<share/skin/defaults.conf>. |
15 | |
16 | =head1 A SIMPLE WIDGET |
17 | |
18 | The simplest widget would be this: |
19 | |
20 | package MyApp::Widget::Foo; |
21 | use Reaction::UI::WidgetClass; |
22 | |
91c2674b |
23 | use namespace::autoclean; |
f9b32c83 |
24 | |
25 | __PACKAGE__->meta->make_immutable; |
26 | |
27 | 1; |
28 | |
29 | The use of L<Reaction::UI::WidgetClass> will import L<strict>, L<warnings>, L<Moose> and |
30 | L<Reaction::Class>. It will also set L<Reaction::UI::Widget> as the base class of the |
31 | widget. If you want to extend an existing widget rather than create a new one, use |
32 | L<Moose/extends>. |
33 | |
34 | =head1 FRAGMENTS |
35 | |
b807f8bf |
36 | Layouts can use the C<=for layout $fragment> POD syntax to define fragments and use them |
f9b32c83 |
37 | like usual L<Template> variables. |
38 | |
39 | But sometimes it is desirable to have a fragment that invokes Perl code in the widget |
40 | to render certain outputs. For this, the widget has its own mechanisms to handle |
41 | fragments. |
42 | |
43 | =head2 Implementing a fragment |
44 | |
45 | A layout fragment can access the widgets attributes and other fragments like normal |
46 | L<Template> variables. But if a widget implements a fragment, that implementation will |
47 | be used to provide the data and some additional control over the rendering of the layout. |
48 | |
49 | This abstracts the data manipulation view logic from the layouting view logic. |
50 | |
1b45efc1 |
51 | A widget can implement a new fragment like this: |
f9b32c83 |
52 | |
53 | package MyApp::Widget::Foo; |
54 | use Reaction::UI::WidgetClass; |
55 | |
91c2674b |
56 | use namespace::autoclean; |
f9b32c83 |
57 | |
58 | implements fragment now { |
59 | arg timestamp => time(); |
60 | }; |
61 | |
62 | __PACKAGE__->meta->make_immutable; |
63 | |
64 | 1; |
65 | |
66 | Now 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 | |
82 | The C<widget> fragment is the root fragment of every widget. The widget directive sets |
83 | the desired widget to C<Foo>. One of our C<widget_search_path>s should contain |
84 | C<MyApp::Widget>, so the widget class defined above can be found. |
85 | |
86 | The C<widget> fragment defined here will render the C<now> fragment implemented by the |
87 | widget and layed out by the layout template. Assuming the current timestamp is |
88 | C<1234567890>, the rendered output will look like this: |
89 | |
90 | <h1>Info:</h1> |
91 | |
92 | <p>Timestamp: 1234567890</p> |
93 | |
94 | Let us take a closer look at the fragment implementation in the widget: |
95 | |
96 | implements fragment now { |
97 | arg timestamp => time(); |
98 | }; |
99 | |
100 | This syntax might look a bit unusual, but it's not a source filter. The declarative style |
101 | is provided by L<Devel::Declare>. This implements a fragment named C<now> in the current |
102 | widget. The body uses the C<arg> keyword to provide a new argument C<timestamp> to the |
103 | template with the value of the current return value of C<time()>. |
104 | |
105 | =head1 Extending a fragment |
106 | |
107 | Sometimes you don't want to redefine how a fragment is implemented, but merely extend on |
108 | the current definition. An example would be adding the total number of entries in a |
109 | collection below the listing of the entries. |
110 | |
111 | Fortunately, L<Reaction> is based on L<Moose> and trying to stay as flexible as possible. |
112 | In this case, Reaction allows us to use Moose method modifiers with fragments: |
113 | |
114 | package MyApp::Widget::Bar; |
115 | use Reaction::UI::WidgetClass; |
116 | |
91c2674b |
117 | use namespace::autoclean; |
f9b32c83 |
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 | |
130 | The C<call_next> keyword will call the next implementation in the inheritance tree, just |
131 | like it would call the next fragment when used in the layout template. |
132 | |
133 | The global hash C<%_> is used to provide the fragment arguments to the code block |
134 | implementing it. For example, the viewport would be available in C<$_{viewport}>. |
135 | |
136 | Besides C<around>, you can also use C<before> and C<after>. |
137 | |
138 | =head1 Iterating over a fragment |
139 | |
140 | Many fragments are intended to be iterated over a collection of items. An example |
141 | implementation of this is listed below: |
142 | |
143 | package MyApp::Widget::Baz |
144 | use Reaction::UI::WidgetClass; |
145 | |
146 | use DateTime; |
147 | |
91c2674b |
148 | use namespace::autoclean; |
f9b32c83 |
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 | |
166 | Which 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 | |
188 | The C<widget> fragment defined in the layout template will render the C<now> fragment |
189 | implemented in the widget class. It is setting the C<dt_obj> argument to a L<DateTime> |
190 | object representing the current date and time. Then it will C<render> the fragment |
191 | C<datetime_field> once for every item in the C<@Fields> array. |
192 | |
193 | The global topic variable C<$_> will be set to each corresponding value in the arguments |
194 | to C<over>. The C<datetime_field> fragment will then for each field name set C<field_name> |
195 | to the aforementioned value, and store the result of the method of that name on the C<dt_obj> |
196 | in the C<field_value> argument. |
197 | |
198 | The 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 | |
206 | The common wrapper around the fully rendered site. |
207 | |
208 | =item L<Reaction::UI::Widget::ListView> |
209 | |
210 | Extends L<Reaction::UI::Widget::Grid> to provide actions and paging. |
211 | |
212 | =item L<Reaction::UI::Widget::Object> |
213 | |
214 | Rendering of a single object by a collection of viewports. |
215 | |
216 | =item L<Reaction::UI::Widget::Container> |
217 | |
218 | A base class that automatically provides callbacks to render attributes containing |
219 | viewports on the current viewport. |
220 | |
221 | =item L<Reaction::UI::Widget::Collection> |
222 | |
223 | Renders a collection of member viewports in the current viewport. |
224 | |
225 | =item L<Reaction::UI::Widget::Grid> |
226 | |
227 | A subclass of L<Reaction::UI::Widget::Collection> providing header and footer |
228 | as well as member actions. The C<default> skin contains layout sets to output |
229 | this widget as a HTML table. |
230 | |
231 | =item L<Reaction::UI::Widget::Image> |
232 | |
233 | An image with optional width and height properties. |
234 | |
235 | =item L<Reaction::UI::Widget::Field> |
236 | |
237 | Base widget for fields. Contains a list of subclasses. |
238 | |
239 | =item L<Reaction::UI::Widget::Action> |
240 | |
241 | A widget representing a mutation of an object. |
242 | |
243 | =item L<Reaction::UI::Widget::Action::Link> |
244 | |
245 | Object mutation widget rendering a hyperlink. |
246 | |
247 | =item L<Reaction::UI::Widget::Data> |
248 | |
249 | Renders the data stored in the viewport's C<args> attribute. |
250 | |
251 | =item L<Reaction::UI::Widget::Value> |
252 | |
253 | Will take the C<value_string> or C<value> viewport method return value and provide it as |
254 | argument C<value> to the C<widget> fragment. It also contains a list of subclasses. |
255 | |
256 | =item L<Reaction::UI::Widget::URI> |
257 | |
258 | A 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 | |
276 | See L<Reaction::Class> for authors. |
277 | |
278 | =head1 LICENSE |
279 | |
280 | See L<Reaction::Class> for the license. |
281 | |
282 | =cut |
283 | |