Revision cea0e38d
Von Sven Schöling vor mehr als 7 Jahren hinzugefügt
SL/Layout/ActionBar.pm | ||
---|---|---|
85 | 85 |
|
86 | 86 |
SL::Layout::ActionBar - Unified action buttons for controllers |
87 | 87 |
|
88 |
=head1 SYNOPSIS |
|
89 |
|
|
90 |
# short sugared syntax: |
|
91 |
for my $bar ($::request->layout->get('actionbar')) { |
|
92 |
$bar->add( |
|
93 |
action => [ |
|
94 |
t8('Description'), |
|
95 |
call => [ 'kivi.Javascript.function', @arguments ], |
|
96 |
accesskey => 'enter', |
|
97 |
disabled => $tooltip_with_reason_or_falsish, |
|
98 |
only_if => $precomputed_condition, |
|
99 |
not_if => $precomputed_condition, |
|
100 |
id => 'html-element-id', |
|
101 |
], |
|
102 |
combobox => [ |
|
103 |
action => [...], |
|
104 |
action => [...], |
|
105 |
action => [...], |
|
106 |
action => [...], |
|
107 |
], |
|
108 |
link => [ |
|
109 |
t8('Description'), |
|
110 |
link => $url, |
|
111 |
], |
|
112 |
'separator', |
|
113 |
); |
|
114 |
} |
|
115 |
|
|
116 |
# full syntax without sugar |
|
117 |
for my $bar ($::request->layout->get('actionbar')) { |
|
118 |
$bar->add( |
|
119 |
(SL::Layout::ActionBar::Action->new( |
|
120 |
text => t8('Description'), |
|
121 |
params => { |
|
122 |
call => [ 'kivi.Javascript.function', @arguments ], |
|
123 |
accesskey => 'enter', |
|
124 |
disabled => $tooltip_with_reason_or_falsish, |
|
125 |
}, |
|
126 |
)) x(!!$only_id && !$not_if), |
|
127 |
SL::Layout::ActionBar::ComboBox->new( |
|
128 |
actions => [ |
|
129 |
SL::Layout::ActionBar::Action->new(...), |
|
130 |
SL::Layout::ActionBar::Action->new(...), |
|
131 |
SL::Layout::ActionBar::Action->new(...), |
|
132 |
SL::Layout::ActionBar::Action->new(...), |
|
133 |
], |
|
134 |
), |
|
135 |
SL::Layout::ActionBar::Link->new( |
|
136 |
text => t8('Description'), |
|
137 |
params => { |
|
138 |
link => $url, |
|
139 |
}, |
|
140 |
), |
|
141 |
SL::Layout::ActionBar::Separator->new, |
|
142 |
); |
|
143 |
} |
|
144 |
|
|
88 | 145 |
=head1 CONCEPT |
89 | 146 |
|
90 |
This is a layout block that does a unified action bar for any controller who
|
|
147 |
This is a layout block that creates an action bar for any controller who
|
|
91 | 148 |
wants to use it. It's designed to be rendered above the content and to be |
92 |
fixed when scrolling. |
|
149 |
fixed when scrolling. It's structured as a container for elements that can be |
|
150 |
extended when needed. |
|
93 | 151 |
|
94 |
While it can be used as a generic widget container, it's designed to be able to |
|
95 |
provide commonly used functionality as a short cut. These shortcuts include: |
|
152 |
=head1 METHODS |
|
96 | 153 |
|
97 | 154 |
=over 4 |
98 | 155 |
|
99 |
=item * |
|
156 |
=item * C<new>
|
|
100 | 157 |
|
101 |
Calling a controller with parameters |
|
158 |
Will be used during initialization of the layout. You should never have to |
|
159 |
instanciate an action bar yourself. Get the current request instances from |
|
102 | 160 |
|
103 |
=item *
|
|
161 |
$::request->layout->get('actionbar')
|
|
104 | 162 |
|
105 |
Submitting a form with added parameters
|
|
163 |
instead.
|
|
106 | 164 |
|
107 |
=item * |
|
165 |
=item * C<add>
|
|
108 | 166 |
|
109 |
Arrangement utility |
|
167 |
Add new elements to the bar. Can be instances of |
|
168 |
L<SL::Layout::ActionBar::Action> or scalar strings matching the sugar syntax |
|
169 |
which is described further down. |
|
110 | 170 |
|
111 | 171 |
=back |
112 | 172 |
|
173 |
=head1 SYNTACTIC SUGAR |
|
113 | 174 |
|
114 |
=head1 METHODS |
|
175 |
Instead of passing full objects to L</add>, you can instead pass the arguments |
|
176 |
to be used for instantiation to make the code easier to read. The short syntax |
|
177 |
looks like this: |
|
178 |
|
|
179 |
type => [ |
|
180 |
localized_description, |
|
181 |
param => value, |
|
182 |
param => value, |
|
183 |
... |
|
184 |
] |
|
185 |
|
|
186 |
A string type, followed by the parameters needed for that type. Type may be one of: |
|
187 |
|
|
188 |
=over 4 |
|
189 |
|
|
190 |
=item * C<action> |
|
191 |
|
|
192 |
=item * C<combobox> |
|
193 |
|
|
194 |
=item * C<link> |
|
195 |
|
|
196 |
=item * C<separator> |
|
197 |
|
|
198 |
=back |
|
199 |
|
|
200 |
C<separator> will use no parameters, the other three will expect one arrayref. |
|
201 |
|
|
202 |
Two additional pseuso parameters are supported for those: |
|
115 | 203 |
|
116 | 204 |
=over 4 |
117 | 205 |
|
118 |
=item C<add LIST>
|
|
206 |
=item * C<only_if>
|
|
119 | 207 |
|
120 |
to be documented
|
|
208 |
=item * C<not_if>
|
|
121 | 209 |
|
122 | 210 |
=back |
123 | 211 |
|
124 |
=head1 ACCESS FROM CODE |
|
212 |
These are meant to reduce enterprise operators (C<()x!!>) when conditionally adding lots |
|
213 |
of elements. |
|
125 | 214 |
|
126 |
This is accessable through |
|
215 |
The combobox element is in itself a container and will simply expect the same |
|
216 |
syntax in an arrayref. |
|
127 | 217 |
|
128 |
$::request->layout->get('actionbar') |
|
218 |
For the full list of parameters supported by the elements, see L<SL::Layout::ActionBar::Action/RECOGNIZED PARAMETERS>. |
|
219 |
|
|
220 |
|
|
221 |
=head1 GUIDELINES |
|
222 |
|
|
223 |
The current implementation follows these design guidelines: |
|
129 | 224 |
|
130 |
=head1 DOM MODEL |
|
225 |
=over 4 |
|
226 |
|
|
227 |
=item * |
|
228 |
|
|
229 |
Don't put too many elements into the action bar. Group into comboboxes if |
|
230 |
possible. Consider seven elements a reasonable limit. |
|
231 |
|
|
232 |
=item * |
|
233 |
|
|
234 |
If you've got an update button, put it first and bind the enter accesskey to |
|
235 |
it. |
|
236 |
|
|
237 |
=item * |
|
238 |
|
|
239 |
Put mutating actions (save, post, delete, check out, ship) before the separator |
|
240 |
and non mutating actions (export, search, history, workflow) after the |
|
241 |
separator. Combined actions (save and close) still mutate and go before the |
|
242 |
separator. |
|
243 |
|
|
244 |
=item * |
|
245 |
|
|
246 |
Avoid abusing the actionbar as a secondary menu. As a principle every action |
|
247 |
should act upon the current element or topic. |
|
131 | 248 |
|
132 |
The entire block is rendered into a div with the class 'layout-actionbar'. |
|
249 |
=item * |
|
250 |
|
|
251 |
Hide elements with C<only_if> if they are known to be useless for the current |
|
252 |
topic, but disable when they would be useful in principle but are not |
|
253 |
applicable right now. For example C<delete> does not make sense in a creating |
|
254 |
form, but makes still sense because the element can be deleted later. This |
|
255 |
keeps the actionbar stable and reduces surprising elements that only appear in |
|
256 |
rare situations. |
|
133 | 257 |
|
134 |
=head1 ACTION WIDGETS
|
|
258 |
=item *
|
|
135 | 259 |
|
136 |
Each individual action must be an instance of C<SL::Layout::ActionBar::Action>. |
|
260 |
Always add a tooltip when disabling an action. |
|
261 |
|
|
262 |
=item * |
|
263 |
|
|
264 |
Try to always add a default action with accesskey enter. Since the actionbar |
|
265 |
lies outside of the main form, the usual submit on enter does not work out of |
|
266 |
the box. |
|
267 |
|
|
268 |
=back |
|
269 |
|
|
270 |
=head1 DOM MODEL AND IMPLEMENTATION DETAILS |
|
271 |
|
|
272 |
The entire block is rendered into a div with the class 'layout-actionbar'. Each |
|
273 |
action will render itself and will get added to the div. To keep the DOM small |
|
274 |
and reduce startup overhead, the presentation is pure CSS and only the sticky |
|
275 |
expansion of comboboxes is done with javascript. |
|
276 |
|
|
277 |
To keep startup times and HTML parsing fast the action data is simply written |
|
278 |
into the data elements of the actions and handlers are added in a ready hook. |
|
137 | 279 |
|
138 | 280 |
=head1 BUGS |
139 | 281 |
|
140 | 282 |
none yet. :) |
141 | 283 |
|
284 |
=head1 SEE ALSO |
|
285 |
|
|
286 |
L<SL::Layout::ActioBar::Base>, |
|
287 |
L<SL::Layout::ActioBar::Action>, |
|
288 |
L<SL::Layout::ActioBar::Submit>, |
|
289 |
L<SL::Layout::ActioBar::ComboBox>, |
|
290 |
L<SL::Layout::ActioBar::Separator>, |
|
291 |
L<SL::Layout::ActioBar::Link>, |
|
292 |
|
|
142 | 293 |
=head1 AUTHOR |
143 | 294 |
|
144 | 295 |
Sven Schoeling E<lt>s.schoeling@linet-services.deE<gt> |
SL/Layout/ActionBar/Action.pm | ||
---|---|---|
49 | 49 |
$_[0]->p->name_to_id('action[]') |
50 | 50 |
} |
51 | 51 |
|
52 |
|
|
53 | 52 |
1; |
54 | 53 |
|
55 | 54 |
__END__ |
56 | 55 |
|
57 |
=head 1 |
|
56 |
=encoding utf-8 |
|
57 |
|
|
58 |
=head1 NAME |
|
59 |
|
|
60 |
SL::Layout::ActionBar::Action - base class for action bar actions |
|
61 |
|
|
62 |
=head1 DESCRIPTION |
|
63 |
|
|
64 |
This base class for actions can be used to implement elements that can be |
|
65 |
added to L<SL::Layout::ActionBar>. |
|
66 |
|
|
67 |
Elements can be interactive or simply used for layout. Most of the actual |
|
68 |
semantik is handled in the corresponding javascript C<js/kivi.ActionBar.js>, so |
|
69 |
this is only used to generate the DOM elements and to provide information for |
|
70 |
request time logic decisions. |
|
71 |
|
|
72 |
|
|
73 |
=head1 SYNOPSIS |
|
74 |
|
|
75 |
# implement: |
|
76 |
package SL::Layout::ActionBar::Custom; |
|
77 |
use parent qw(SL::Layout::ActionBar::Action); |
|
78 |
|
|
79 |
# unsugared use |
|
80 |
SL::Layout::ActionBar::Custom->new( |
|
81 |
text => t8('Description'), |
|
82 |
params => { |
|
83 |
key => $attr, |
|
84 |
key => $attr, |
|
85 |
... |
|
86 |
}, |
|
87 |
); |
|
88 |
|
|
89 |
# parse sugared version: |
|
90 |
SL::Layout::ActionBar::Custom->from_params( |
|
91 |
t8('Description'), |
|
92 |
key => $attr, |
|
93 |
key => $attr, |
|
94 |
... |
|
95 |
); |
|
96 |
|
|
97 |
=head1 INTERFACE |
|
98 |
|
|
99 |
=over 4 |
|
100 |
|
|
101 |
=item * C<render> |
|
102 |
|
|
103 |
Needs to be implemented. Should render only the bare minimum necessary to |
|
104 |
identify the element at run time. |
|
105 |
|
|
106 |
=item * C<script> |
|
107 |
|
|
108 |
Will be called during layout rendering. Defaults to dumping the params section |
|
109 |
into data field of the rendered DOM element. |
|
110 |
|
|
111 |
=item * C<from_params> |
|
112 |
|
|
113 |
Parse sugared version. Defaults for historic reasons to the implementation of |
|
114 |
L<SL::Layout::ActionBar::Submit>, all others must implement their own. |
|
115 |
|
|
116 |
=item * C<callable> |
|
117 |
|
|
118 |
Used to determine whether an instance is callable or only a layout element. |
|
119 |
|
|
120 |
=back |
|
121 |
|
|
122 |
=head1 METHODS |
|
123 |
|
|
124 |
=over 4 |
|
125 |
|
|
126 |
=item * C<p> |
|
127 |
|
|
128 |
Returns the current request presenter. |
|
129 |
|
|
130 |
=item * C<id> |
|
131 |
|
|
132 |
Will get initialized to either the provided id from the params or to a |
|
133 |
generated unique id. Should be used to tie the rendered DOM and script |
|
134 |
together. |
|
135 |
|
|
136 |
=back |
|
137 |
|
|
138 |
=head1 RECOGNIZED PARAMETERS |
|
139 |
|
|
140 |
=over 4 |
|
141 |
|
|
142 |
=item * C<< submit => [ $selector, \%params ] >> |
|
143 |
|
|
144 |
On click, submit the form found with the first parameter. If params is present |
|
145 |
and a hashref, the key value elements will be added to the form before |
|
146 |
submitting. Beware that this will destroy the form if the user uses the browser |
|
147 |
history to jump back to this page, so ony use parametrized submits for post |
|
148 |
submits that redirect on completion. |
|
149 |
|
|
150 |
=item * C<< link => $url >> |
|
151 |
|
|
152 |
On click, will load the given url. |
|
153 |
|
|
154 |
=item * C<< call => [ $function_name, @args ] >> |
|
155 |
|
|
156 |
On click, will call the function name with the argument array. The return will |
|
157 |
be discarded. It is assumed that the fucntion will trigger an asynchronous |
|
158 |
action. |
|
159 |
|
|
160 |
Contrast with C<checks>. |
|
161 |
|
|
162 |
=item * C<< checks => \@function_names >> |
|
163 |
|
|
164 |
Before any of C<submit>, C<link>, or C<call> are evaluated all |
|
165 |
functions in C<check> are called. Only if all of them return a true value the |
|
166 |
action will be triggered. |
|
167 |
|
|
168 |
Checks are expected not to trigger asynchronous actions (contrast with C<call>), |
|
169 |
but may change the DOM to indicate to the user why they fail. |
|
170 |
|
|
171 |
Each must return a boolean value. |
|
172 |
|
|
173 |
=item * C<< confirm => t8('Yes/No Question') >> |
|
174 |
|
|
175 |
Before any of C<submit>, C<link>, or C<call> are evaluated, the user |
|
176 |
will be asked to confirm. If checks are present and failed, confirm will not be |
|
177 |
triggered. |
|
178 |
|
|
179 |
=item * C<< only_if => $bool >> |
|
180 |
|
|
181 |
Pseudo parameter. If present and false, the element will not be rendered. |
|
182 |
|
|
183 |
=item * C<< not_if => $bool >> |
|
184 |
|
|
185 |
Pseudo parameter. If present and true, the element will not be rendered. |
|
186 |
|
|
187 |
=item * C<< only_once => 1 >> |
|
188 |
|
|
189 |
If present, a click will C<disable> the action to prevent multiple activations. |
|
190 |
|
|
191 |
=item * C<< accesskey => $text >> |
|
192 |
|
|
193 |
Registeres an accesskey for this element. While the most common accesskey is |
|
194 |
'enter', in theory every other should work as well. Modifier keys can be added |
|
195 |
to the accesskey string with 'ctrl+', 'alt+', or 'shift+'. 'shift+' is not |
|
196 |
necessary for upper case letters. |
|
197 |
|
|
198 |
=item * C<< disabled => t8('tooltip') >> |
|
199 |
|
|
200 |
Renders the element disabled, ignores all actions (C<submit>, C<call>, C<link>) |
|
201 |
and adds the given tooltip hopefully explaining why the element is disabled. |
|
58 | 202 |
|
59 |
planned options for clickables:
|
|
203 |
=item * C<< id => $id >>
|
|
60 | 204 |
|
61 |
- checks => [ ... ] (done) |
|
205 |
Sets the DOM id of the rendered element. If missing, the element will get a |
|
206 |
random id. |
|
62 | 207 |
|
63 |
a list of functions that need to return true before submitting
|
|
208 |
=item * C<< tooltip => t8('tooltip') >>
|
|
64 | 209 |
|
65 |
- submit => [ form-selector, { params } ] (done)
|
|
210 |
Sets a tooltip for the element.
|
|
66 | 211 |
|
67 |
on click submit the form specified by form-selector with the additional params
|
|
212 |
=back
|
|
68 | 213 |
|
69 |
- function => function-name (done)
|
|
214 |
=head1 BUGS
|
|
70 | 215 |
|
71 |
on click call the specified function (is this a special case of checks?)
|
|
216 |
None yet :)
|
|
72 | 217 |
|
73 |
- disabled => true/false/tooltip explaning why disabled (done)
|
|
218 |
=head1 AUTHOR
|
|
74 | 219 |
|
75 |
TODO:
|
|
220 |
Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
|
|
76 | 221 |
|
77 |
- runtime disable/enable |
|
222 |
=cut |
Auch abrufbar als: Unified diff
ActionBar Dokumentation