]> wagnertech.de Git - kivitendo-erp.git/commitdiff
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 3279ba8dcb19aa6bd25b5a320229d13d9eba893c..8447ec1b73f8063b1ed4dbdf1656efd8b8c20b29 100644 (file)
@@ -85,60 +85,211 @@ __END__
 
 SL::Layout::ActionBar - Unified action buttons for controllers
 
 
 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
 
 =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
 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
 
 
 =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
 
 
 =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
 
 
 =over 4
 
-=item C<add LIST>
+=item * C<only_if>
 
 
-to be documented
+=item * C<not_if>
 
 =back
 
 
 =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 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>
 =head1 AUTHOR
 
 Sven Schoeling E<lt>s.schoeling@linet-services.deE<gt>
index 4243b652ba7e79c8e5b789396258ca7b5cdb4b4c..c488f94a7fd2ad9e93a3f597b458fff6ad44e5de 100644 (file)
@@ -49,29 +49,174 @@ sub init_id {
   $_[0]->p->name_to_id('action[]')
 }
 
   $_[0]->p->name_to_id('action[]')
 }
 
-
 1;
 
 __END__
 
 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