X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=SL%2FLayout%2FActionBar.pm;h=5345e9e14e72e75f7a9dacdd8f119df80426cfb7;hb=73f7989fcf23410ebd879d5150f6a13913ca2b90;hp=fa86d16ace8fb36f69591d3485cc8121a22334ef;hpb=02f6397dc6de7fde86420fd12d02c88b7c2f533e;p=kivitendo-erp.git diff --git a/SL/Layout/ActionBar.pm b/SL/Layout/ActionBar.pm index fa86d16ac..5345e9e14 100644 --- a/SL/Layout/ActionBar.pm +++ b/SL/Layout/ActionBar.pm @@ -10,6 +10,8 @@ use SL::Layout::ActionBar::ComboBox; use SL::Layout::ActionBar::Link; use SL::Layout::ActionBar::Separator; +use SL::Presenter::Tag qw(html_tag); + use constant HTML_CLASS => 'layout-actionbar'; use Rose::Object::MakeMethods::Generic ( @@ -30,14 +32,14 @@ sub pre_content { my $content = join '', map { $_->render } @{ $self->actions }; return if !$content; - $::request->presenter->html_tag('div', $content, class => HTML_CLASS); + html_tag('div', $content, class => HTML_CLASS); } sub javascripts_inline { join '', map { $_->script } @{ $_[0]->actions }; } -sub javascripts { +sub static_javascripts { 'kivi.ActionBar.js' } @@ -59,7 +61,7 @@ sub parse_actions { while (my $type = shift(@actions)) { if (blessed($type) && $type->isa('SL::Layout::ActionBar::Action')) { push @parsed, $type; - continue; + next; } my $descriptor = $class_descriptors{lc $type} || croak("Unknown action type '${type}'"); @@ -85,60 +87,211 @@ __END__ SL::Layout::ActionBar - Unified action buttons for controllers +=head1 SYNOPSIS + + # short sugared syntax: + for my $bar ($::request->layout->get('actionbar')) { + $bar->add( + action => [ + t8('Description'), + call => [ 'kivi.Javascript.function', @arguments ], + accesskey => 'enter', + disabled => $tooltip_with_reason_or_falsish, + only_if => $precomputed_condition, + not_if => $precomputed_condition, + id => 'html-element-id', + ], + combobox => [ + action => [...], + action => [...], + action => [...], + action => [...], + ], + link => [ + t8('Description'), + link => $url, + ], + 'separator', + ); + } + + # full syntax without sugar + for my $bar ($::request->layout->get('actionbar')) { + $bar->add( + (SL::Layout::ActionBar::Action->new( + text => t8('Description'), + params => { + call => [ 'kivi.Javascript.function', @arguments ], + accesskey => 'enter', + disabled => $tooltip_with_reason_or_falsish, + }, + )) x(!!$only_id && !$not_if), + SL::Layout::ActionBar::ComboBox->new( + actions => [ + SL::Layout::ActionBar::Action->new(...), + SL::Layout::ActionBar::Action->new(...), + SL::Layout::ActionBar::Action->new(...), + SL::Layout::ActionBar::Action->new(...), + ], + ), + SL::Layout::ActionBar::Link->new( + text => t8('Description'), + params => { + link => $url, + }, + ), + SL::Layout::ActionBar::Separator->new, + ); + } + =head1 CONCEPT -This is a layout block that does a unified action bar for any controller who +This is a layout block that creates an action bar for any controller who wants to use it. It's designed to be rendered above the content and to be -fixed when scrolling. +fixed when scrolling. It's structured as a container for elements that can be +extended when needed. -While it can be used as a generic widget container, it's designed to be able to -provide commonly used functionality as a short cut. These shortcuts include: +=head1 METHODS =over 4 -=item * +=item * C -Calling a controller with parameters +Will be used during initialization of the layout. You should never have to +instanciate an action bar yourself. Get the current request instances from -=item * + $::request->layout->get('actionbar') -Submitting a form with added parameters +instead. -=item * +=item * C -Arrangement utility +Add new elements to the bar. Can be instances of +L or scalar strings matching the sugar syntax +which is described further down. =back +=head1 SYNTACTIC SUGAR -=head1 METHODS +Instead of passing full objects to L, you can instead pass the arguments +to be used for instantiation to make the code easier to read. The short syntax +looks like this: + + type => [ + localized_description, + param => value, + param => value, + ... + ] + +A string type, followed by the parameters needed for that type. Type may be one of: =over 4 -=item C +=item * C + +=item * C -to be documented +=item * C + +=item * C =back -=head1 ACCESS FROM CODE +C will use no parameters, the other three will expect one arrayref. -This is accessable through +Two additional pseudo parameters are supported for those: - $::request->layout->get('actionbar') +=over 4 + +=item * C + +=item * C + +=back -=head1 DOM MODEL +These are meant to reduce enterprise operators (C<()x!!>) when conditionally adding lots +of elements. -The entire block is rendered into a div with the class 'layout-actionbar'. +The combobox element is in itself a container and will simply expect the same +syntax in an arrayref. -=head1 ACTION WIDGETS +For the full list of parameters supported by the elements, see L. -Each individual action must be an instance of C. + +=head1 GUIDELINES + +The current implementation follows these design guidelines: + +=over 4 + +=item * + +Don't put too many elements into the action bar. Group into comboboxes if +possible. Consider seven elements a reasonable limit. + +=item * + +If you've got an update button, put it first and bind the enter accesskey to +it. + +=item * + +Put mutating actions (save, post, delete, check out, ship) before the separator +and non mutating actions (export, search, history, workflow) after the +separator. Combined actions (save and close) still mutate and go before the +separator. + +=item * + +Avoid abusing the actionbar as a secondary menu. As a principle every action +should act upon the current element or topic. + +=item * + +Hide elements with C if they are known to be useless for the current +topic, but disable when they would be useful in principle but are not +applicable right now. For example C does not make sense in a creating +form, but makes still sense because the element can be deleted later. This +keeps the actionbar stable and reduces surprising elements that only appear in +rare situations. + +=item * + +Always add a tooltip when disabling an action. + +=item * + +Try to always add a default action with accesskey enter. Since the actionbar +lies outside of the main form, the usual submit on enter does not work out of +the box. + +=back + +=head1 DOM MODEL AND IMPLEMENTATION DETAILS + +The entire block is rendered into a div with the class 'layout-actionbar'. Each +action will render itself and will get added to the div. To keep the DOM small +and reduce startup overhead, the presentation is pure CSS and only the sticky +expansion of comboboxes is done with javascript. + +To keep startup times and HTML parsing fast the action data is simply written +into the data elements of the actions and handlers are added in a ready hook. =head1 BUGS none yet. :) +=head1 SEE ALSO + +L, +L, +L, +L, +L, +L, + =head1 AUTHOR Sven Schoeling Es.schoeling@linet-services.deE