NAME

Catalyst::ActionRole::Tabs - Add tabs to Catalyst controller actions

SYNOPSIS

package MyApp::Controller::Foo;

use Moose::Role;
use namespace::autoclean;

BEGIN { extends 'Catalyst::Controller::ActionRole' }

# view action has a tab
sub view : Local Does(Tabs) Tab {
  ...
}

# edit action has a tab
sub edit : Local Does(Tabs) Tab {
  ...
  $form->action($c->uri_for('update'));
  ...
}

# update action uses same tab as edit action
sub update : Local Does(Tabs) TabAlias(edit) {
  ...
  if ($form->result->has_errors) {
    $stash->{template} = 'edit.tt2';
  }
  else {
    $c->response->redirect($c->uri_for('view'));
}


[% # Tab template %]
[% # Assuming tab_navigation to be an array reference %]
[% # See below under CALLBACK METHODS %]
[% # For applicable CSS see below under SAMPLE CSS -%]
<ul>
[% FOR tab IN tab_navigation %]
    <li[% IF tab.selected %] class="selected"[% END %]>
        <a href="[% tab.uri %]">[% tab.label %]</a>
    </li>
[% END %]
</ul>

DESCRIPTION

This module allows to add 'Tab' attributes to action endpoints, and it will automatically build a data structure suitable for rendering 'tabs' to switch between the methods that share the same tab structure.

Although this was originally built to help with making tabbed interfaces, it isn't limited to creating tabs, as it simply collects the information about the related actions. Actions are considered to be related if they share a namespace and the same captures from chained actions.

For examples of usage, please have a look in the test directory ./t and its subdirectories.

ATTRIBUTES

Does

Does(Tabs)

Activate Catalyst::ActionRole::Tabs for the action.

Tab

Tab
Tab(Labeltext)

Assign a Tab to the action. The optional argument specifies the label text. Without an explicite label text the action name is used, with the first letter uppercased and the rest lowercased.

TabAlias(aliasaction)

In some cases it is usefull to assign one tab to many actions. E.g. an action with a form to update some data, might be called initially as action edit where data is read from the database and filled into the form fields and then point the form's action to update, where the actual input processing happens. In case of an error, the same form (decorated with some error messages) would be shown again, but this time under .../update. With TabAlias update shows the same tab as edit:

# action 'edit' has a Tab with label "Edit"
sub edit : Local Does(Tabs) Tab { ... }

# action 'update' has a Tab with label "Edit" too
sub update : Local Does(Tabs) TabAlias(edit) { ... }

METHODS

BUILD

BUILD is a standard Moose method, that is called at the end of the object construction process.

  • Asserts that not both Tab and TabAlias exist for the same action.

  • The TabAlias attribute is checked to have an argument.

execute

Called before the actual action code to build the tabs for the current controller.

Makes use of Catalyst::ActionRole::ACL->can_visit() if available for the particular action and removes those tabs, whose actions are not allowed for the current user.

The final result is a hash, where the keys are the action names and the values are references to hashes that describe the actual tabs:

name

The action name. Same as the key of the main hash.

label

The tab label text.

selected

A boolean that is true for the tab of the currently executed action.

uri

An URI object of this tab's action.

alias

This exists only in the tab for the current action (where selected is true) and if the action has a TabAlias attribute. Contains the actual action name.

A dump of the controller's tab hash might look like this:

{
  view => {
    name => "view",
    label => "View",
    selected => 1,
    uri => bless(
        do{\(my $o = "http://example.com/admin/user/id/1337")},
        "URI::http"
      ),
  },
  edit => {
    name => "edit",
    label => "Edit",
    selected => "",
    uri => bless(
        do{\(my $o = "http://example.com/admin/user/id/1337/edit")},
        "URI::http"
      ),
  },
}

CALLBACK METHODS

BUILD_TABS

If method BUILD_TABS() exists in the controller class, it is called as

$controller->BUILD_TABS($c, $tabs)

else the tabs hash as described in "execute" is stored at $c->stash->{tabs}.

BUILD_TABS() has to store the tabs data wherever appropriate. It can also be used to convert the incomig hash into an array with the desired order of tabs. Finally is is a place to apply further modifications to the tabs, like adding or removing tabs.

Here is an example for a BUILD_TABS(), that turns tab data into an array with the desired order and then stores it onto the stash under the name tab_navigation:

sub BUILD_TABS {
  my ($self, $c, $tabs) = @_;
  my (@tabs, $tab);

  for (qw(browse add view edit remove)) {
    $tab = $tabs->{$_}
      and push @tabs, $tab;
  }

  $c->stash->{tab_navigation} = \@tabs;
}

SAMPLE CSS

Here is some CSS that works with the template included in the synopsis. It's probably not exactly what you need, but it should give a decent starting point...

ul.tabs {
  text-align: left;
  margin: 1em 0 1em 0;
  border-bottom: 1px solid #6c6;
  list-style-type: none;
  padding: 3px 10px 3px 10px;
}
    
ul.tabs li {
  display: inline;
}

ul.tabs li.selected {
  border-bottom: 1px solid #fff;
  background-color: #fff;
}

ul.tabs li.selected a {
  background-color: #fff;
  color: #000;
  position: relative;
  top: 1px;
  padding-top: 4px;
}

ul.tabs li a {
  padding: 3px 4px;
  border: 1px solid #6c6;
  background-color: #cfc;
  color: #666;
  margin-right: 0px;
  text-decoration: none;
  border-bottom: none;
}

ul.tabs a:hover {
  background: #fff;
}

AUTHOR

Bernhard Graf <graf(a)cpan.org>,

SUPPORT

You can find documentation for this module with the perldoc command.

perldoc Catalyst::ActionRole::Tabs

You can also look for information at:

ACKNOWLEDGEMENTS

Inspired by and parts of code and documentation used from CatalystX::Controller::Tabs.

Catalyst::ActionRole::ACL to be the first released module to use ...

... the wonderful Catalyst::Controller::ActionRole.

And of course Catalyst.

COPYRIGHT & LICENSE

Copyright 2009 Bernhard Graf.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.