ActionBar Dokumentation
authorSven Schöling <s.schoeling@linet-services.de>
Mon, 10 Apr 2017 11:47:17 +0000 (13:47 +0200)
committerSven Schöling <s.schoeling@linet-services.de>
Mon, 10 Apr 2017 11:47:17 +0000 (13:47 +0200)
SL/Layout/ActionBar.pm
SL/Layout/ActionBar/Action.pm

index 3279ba8..8447ec1 100644 (file)
@@ -85,60 +85,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<new>
 
-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<add>
 
-Arrangement utility
+Add new elements to the bar. Can be instances of
+L<SL::Layout::ActionBar::Action> 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</add>, 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<action>
+
+=item * C<combobox>
+
+=item * C<link>
+
+=item * C<separator>
+
+=back
+
+C<separator> will use no parameters, the other three will expect one arrayref.
+
+Two additional pseuso parameters are supported for those:
 
 =over 4
 
-=item C<add LIST>
+=item * C<only_if>
 
-to be documented
+=item * C<not_if>
 
 =back
 
-=head1 ACCESS FROM CODE
+These are meant to reduce enterprise operators (C<()x!!>) when conditionally adding lots
+of elements.
 
-This is accessable through
+The combobox element is in itself a container and will simply expect the same
+syntax in an arrayref.
 
-  $::request->layout->get('actionbar')
+For the full list of parameters supported by the elements, see L<SL::Layout::ActionBar::Action/RECOGNIZED PARAMETERS>.
+
+
+=head1 GUIDELINES
+
+The current implementation follows these design guidelines:
 
-=head1 DOM MODEL
+=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.
 
-The entire block is rendered into a div with the class 'layout-actionbar'.
+=item *
+
+Hide elements with C<only_if> 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<delete> 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.
 
-=head1 ACTION WIDGETS
+=item *
 
-Each individual action must be an instance of C<SL::Layout::ActionBar::Action>.
+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<SL::Layout::ActioBar::Base>,
+L<SL::Layout::ActioBar::Action>,
+L<SL::Layout::ActioBar::Submit>,
+L<SL::Layout::ActioBar::ComboBox>,
+L<SL::Layout::ActioBar::Separator>,
+L<SL::Layout::ActioBar::Link>,
+
 =head1 AUTHOR
 
 Sven Schoeling E<lt>s.schoeling@linet-services.deE<gt>
index 4243b65..c488f94 100644 (file)
@@ -49,29 +49,174 @@ sub init_id {
   $_[0]->p->name_to_id('action[]')
 }
 
-
 1;
 
 __END__
 
-=head 1
+=encoding utf-8
+
+=head1 NAME
+
+SL::Layout::ActionBar::Action - base class for action bar actions
+
+=head1 DESCRIPTION
+
+This base class for actions can be used to implement elements that can be
+added to L<SL::Layout::ActionBar>.
+
+Elements can be interactive or simply used for layout. Most of the actual
+semantik is handled in the corresponding javascript C<js/kivi.ActionBar.js>, so
+this is only used to generate the DOM elements and to provide information for
+request time logic decisions.
+
+
+=head1 SYNOPSIS
+
+  # implement:
+  package SL::Layout::ActionBar::Custom;
+  use parent qw(SL::Layout::ActionBar::Action);
+
+  # unsugared use
+  SL::Layout::ActionBar::Custom->new(
+    text   => t8('Description'),
+    params => {
+      key => $attr,
+      key => $attr,
+      ...
+    },
+  );
+
+  # parse sugared version:
+  SL::Layout::ActionBar::Custom->from_params(
+    t8('Description'),
+    key => $attr,
+    key => $attr,
+    ...
+  );
+
+=head1 INTERFACE
+
+=over 4
+
+=item * C<render>
+
+Needs to be implemented. Should render only the bare minimum necessary to
+identify the element at run time.
+
+=item * C<script>
+
+Will be called during layout rendering. Defaults to dumping the params section
+into data field of the rendered DOM element.
+
+=item * C<from_params>
+
+Parse sugared version. Defaults for historic reasons to the implementation of
+L<SL::Layout::ActionBar::Submit>, all others must implement their own.
+
+=item * C<callable>
+
+Used to determine whether an instance is callable or only a layout element.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item * C<p>
+
+Returns the current request presenter.
+
+=item * C<id>
+
+Will get initialized to either the provided id from the params or to a
+generated unique id. Should be used to tie the rendered DOM and script
+together.
+
+=back
+
+=head1 RECOGNIZED PARAMETERS
+
+=over 4
+
+=item * C<< submit => [ $selector, \%params ] >>
+
+On click, submit the form found with the first parameter. If params is present
+and a hashref, the key value elements will be added to the form before
+submitting. Beware that this will destroy the form if the user uses the browser
+history to jump back to this page, so ony use parametrized submits for post
+submits that redirect on completion.
+
+=item * C<< link => $url >>
+
+On click, will load the given url.
+
+=item * C<< call => [ $function_name, @args ] >>
+
+On click, will call the function name with the argument array. The return will
+be discarded. It is assumed that the fucntion will trigger an asynchronous
+action.
+
+Contrast with C<checks>.
+
+=item * C<< checks => \@function_names >>
+
+Before any of C<submit>, C<link>, or C<call> are evaluated all
+functions in C<check> are called. Only if all of them return a true value the
+action will be triggered.
+
+Checks are expected not to trigger asynchronous actions (contrast with C<call>),
+but may change the DOM to indicate to the user why they fail.
+
+Each must return a boolean value.
+
+=item * C<< confirm => t8('Yes/No Question') >>
+
+Before any of C<submit>, C<link>, or C<call> are evaluated, the user
+will be asked to confirm. If checks are present and failed, confirm will not be
+triggered.
+
+=item * C<< only_if => $bool >>
+
+Pseudo parameter. If present and false, the element will not be rendered.
+
+=item * C<< not_if => $bool >>
+
+Pseudo parameter. If present and true, the element will not be rendered.
+
+=item * C<< only_once => 1 >>
+
+If present, a click will C<disable> the action to prevent multiple activations.
+
+=item * C<< accesskey => $text >>
+
+Registeres an accesskey for this element. While the most common accesskey is
+'enter', in theory every other should work as well. Modifier keys can be added
+to the accesskey string with 'ctrl+', 'alt+', or 'shift+'. 'shift+' is not
+necessary for upper case letters.
+
+=item * C<< disabled => t8('tooltip') >>
+
+Renders the element disabled, ignores all actions (C<submit>, C<call>, C<link>)
+and adds the given tooltip hopefully explaining why the element is disabled.
 
-planned options for clickables:
+=item * C<< id => $id >>
 
-- checks => [ ... ] (done)
+Sets the DOM id of the rendered element. If missing, the element will get a
+random id.
 
-a list of functions that need to return true before submitting
+=item * C<< tooltip => t8('tooltip') >>
 
-- submit => [ form-selector, { params } ] (done)
+Sets a tooltip for the element.
 
-on click submit the form specified by form-selector with the additional params
+=back
 
-- function => function-name (done)
+=head1 BUGS
 
-on click call the specified function (is this a special case of checks?)
+None yet :)
 
-- disabled => true/false/tooltip explaning why disabled (done)
+=head1 AUTHOR
 
-TODO:
+Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
 
-- runtime disable/enable
+=cut