Krang::HTMLPager - Web-paginate lists of records
#### In your Krang::CGI::* module... # use Krang::ClassLoader 'HTMLPager';
## In a run-mode, instantiate new pager object...
my $pager = pkg('HTMLPager')->new(
cgi_query => $query,
use_module => pkg('Contrib'),
columns => [ 'last', 'first', 'command_column', 'checkbox_column' ],
columns_sortable => [ 'last', 'first' ],
command_column_commands => [ 'edit_contrib' ],
id_handler => sub { return $_[0]->contrib_id },
row_handler => sub { $_[0]->{last} = $_[1]->last(); $_[0]->{first} = $_[1]->first(); },
);
# Run the pager my $pager_html = $pager->output(); $template->param(pager_html => $pager_html);
#### In your HTML::Template file...
#
<!-- pkg('HTMLPager') Output START -->
<tmpl_var pager_html>
<!-- pkg('HTMLPager') Output END -->
The primary purpose of Krang::HTMLPager is to allow Krang-style page able lists of results to be easily created. The secondary purpose is to enforce a standard function and appearance to these lists.
The pager interface is designed to work specifically with the Krang system, and to be as simple to use as possible. It is modeled after HTML::Pager, but is more specialized for use with Krang. In particular Krang::HTMLPager provides the following functions which are unique to Krang:
* Use of class find() methods * Generation of "checkbox columns" * Generation of "command columns" * Krang-style sort controls * Krang-style user interface
Krang::HTMLPager implements the following primary methods:
my $pager = pkg('HTMLPager')->new(%pager_props);
The new() method instantiates a new pager. It takes a litany of
parameters, which are documented in full later in this POD in the
section ``Krang::HTMLPager Properties''.
output()my $pager_html = $pager->output();
The output() method is one of two ways to execute a paged view
and utilize the output. This method is intended for use when
the standard built-in pager templates are being employed, as
opposed to a custom pager template.
The output() method runs the Krang::HTMLPager and returns a block of
HTML containing the data output. This is expected to be used in the
context of a larger template:
$template_object->param( pager_html => $pager->output() );
The output returned is contained in a form with the name ``krang_pager_form''. This is important to know if you have a checkbox column on which you want to operate. In this case you are expected to implement a button which calls a javascript function. The javascript function would have to submit the pager form to get access to the checked rows. For example:
function delete_selected () {
var myform = document.forms["krang_pager_form"];
myform.rm.value = "delete_selected";
myform.submit();
}
This assumes that your run-mode parameter is ``rm'' and that you have set ``rm'' to be included in the pager form via the ``persist_vars'' pager property.
fill_template()$pager->fill_template($template_object);
The fill_template() method is one of two ways to execute a paged view
and utilize the output. This method is used in the context of a
custom pager template. The section later in this POD, ``Creating Custom
Pager Templates'', more fully describes how and why you would want to
use a custom template.
The fill_template() method runs the Krang::HTMLPager and sets template
variables in the $template_object you provide. It is then your
responsibility to output that $template_object.
row_count()
my $row_count = $pager->row_count();
The row_count() method returns the number of rows output
by the pager. It is expected to be called after output()
or fill_template(). Until one of those methods are called
row_count() will return undef.
This method is useful for changing the UI based on whether or not any results were found.
make_internal_template()my $template = $pager->make_internal_template();
The make_internal_template() method returns a dynamically created template
for use with Krang::HTMLPager. This method is used internally by output()
to generate a template based on your specification.
This method is made public to assist in the creation of custom pager templates. Using this method you can specify and create a template which can be saved to a file and customized as needed.
$pager->column_display(status => 1, ...)
This method allows to control whether certain columns should be displayed or not. It is meant to be used in row handlers. This way, columns that would be displayed per default can be hidden depending on some row object property. Likewise, columns that would be hidden (see the property 'columns_hidden' below) can be shown.
For each column name passed to this method, the pager creates a special tmpl_if that can be used to actually control the column display in the templates:
<tmpl_if __show_status__><td><tmpl_var status></tmpl_if>
This method can be called multiple times for the same column name allowing for more involved control schemes.
Displaying the list buttons can be controlled via the checkbox_column display.
Krang::HTMLPager expects a number of parameters to be set via the
new() method. These parameters set properties which are used to
create a specification for your pager, such as the list of columns and
which of those columns are sortable.
Following is a list of the parameters for Krang::HTMLPager. These parameters are also accessible via object methods.
cgi_query => $query
Contains the CGI.pm query object for this request. The query object is needed to read in the pager state parameters, such as krang_pager_curr_page_num, krang_pager_sort_field, and krang_pager_sort_order.
persist_vars => {
rm => 'search',
search_filter => $search_filter,
}
A hashref containing the names and values of CGI parameters which should be remembered as hidden data within the pager form. This is necessary for maintaining web application state. The pager expects to have its own form for paging through data and re-sorting results.
Values set in persist_vars will be implemented via CGI.pm's hidden() method
with ``-override=>1'' set. This will ensure that the value you specify will be
set regardless of the current state of that form parameter.
use_module => pkg('Contrib')
The name of the Krang object module which contains the find() method
pager should use for retrieving data. This module's find() method
will be used for handling all queries, sorting, and paging (limit,
offset).
Although it is expected that use_module will specify a Krang object
module, any module which implements a sufficiently compatible find()
method can be used. In this case, ``sufficiently compatible'' means
the following parameters are supported:
* count * order_by * order_desc * offset * limit
find_params => { simple_search => $q->param('search_filter') }
A hashref containing the search parameters exactly as they should be passed to find(). This hashref will be augmented to include parameters related to sorting (order_by, order_desc) and paging (limit, offset).
columns => [qw( last first_middle type command_column checkbox_column )]
An arrayref containing columns names. This property defines two things: The order of the columns in the table (left to right), and the key names which will be expected in custom templates.
There are two special values which can be included in the list of columns. If included in the column list, these columns will be automagically handled by pager as follows:
"command_column" - A list of actions, implemented as button controls. "checkbox_column" - A series of checkboxes, one per record/row.
``command_column'' is used for button links such as ``Edit'' or ``View Detail''. How these buttons are configured is described in more detail below (pager parameters ``command_column_commands'' and ``command_column_labels'').
``command_column'' also sets up the column header as a blank field. This column header functionality can be overridden via ``column_labels'' below.
``checkbox_column'' is used for interfaces where the user is allowed to check a set of records for the purpose of processing them in a particular way. For example, ``delete checked'', ``check out'', and ``associate'' are examples of functionality which use these checkboxes.
Pager will automatically create these checkboxes for you. The checkboxes will be implemented as CGI form inputs which all are named ``krang_pager_rows_checked''. The value of each checkbox is set by pager to be the ``ID'' as returned per row by the ``id_handler'' pager parameter (described below). In HTML, a typical set of checkboxes might look like this:
<input type="checkbox" name="krang_pager_rows_checked" value="1"> <input type="checkbox" name="krang_pager_rows_checked" value="2"> <input type="checkbox" name="krang_pager_rows_checked" value="3"> <input type="checkbox" name="krang_pager_rows_checked" value="4">
This will allow you to easily retrieve an array of checked rows via CGI.pm:
my @rows_checked = $query->param('krang_pager_rows_checked');
``checkbox_column'' also sets up the column header as a widget through which ``select all'' and ``un-select all'' functions can be triggered. This column header functionality can be overridden via ``column_labels'' below.
columns_hidden => [qw( status )]
An arrayref containing the names of columns that should not be displayed per default. Members of this list must also be members of the arrayref 'columns'. Together with column_display(), this list allows to display the named columns depending on some row object property.
For each member of this list, the pager creates a special tmpl_if that can be used to control the column display in the templates. The default value of those tmpl_if is '0', but can be changed via column_display().
B<Example:>
On Retired Asset screens, the status column should normally not show up. There is however one edge case making it desirable to display this column. When searching an asset by ID, all assets are found, no matter whether they are actually retired or live or trashed. A live or trashed asset should indicate its living place and the status column seems the right place for this piece of information. For this edge the status column hidden per default should be displayed nonetheless. The default -- hide the column -- is specified using the 'columns_hidden' list, inverting the default from within a row handler is done via column_display().
<tmpl_if __show_status__><td><tmpl_var status></tmpl_if>
column_labels => { last=>'Last Name', first_middle=>'First, Middle Name' }
A hashref mapping column names (as defined by the ``columns'' pager parameter) to the text label which should appear in the column header line at the top of the table.
It is not necessary to define a column label for every column. If not supplied, the column name will be used instead, except in the case of magic internal column types, ``command_column'' and ``checkbox_column''.
A ``command_column'' header is automatically set to be blank. You could use ``column_labels'' to change it to ``Commands'' or something else intuitive. In the case of a ``checkbox_column'', overriding the label via ``column_labels'' is probably undesirable. A ``checkbox_column'' puts a highly functional gadget in the header, which is probably required.
command_column_commands => [qw( edit_contrib )]
An arrayref containing the names of the JavaScript functions to be called when the user clicks on a particular command. The function will be called with the ``ID'' (as returned per row by the ``id_handler'' pager parameter described below) as the only argument. For example, following would be the HTML generated if ID was set to ``4'':
<input onclick="edit_contrib('4')" type="button" class="button">
It is expected that a corresponding JavaScript function would be written to implement the functionality desired when the user clicks on the command link for a particular row.
command_column_labels => { edit_contrib => 'Edit' }
A hashref containing a map of command names (as defined by ``command_column_commands'') to the text which should be in the link which appears to the user. For example, the above might generate:
<input value="Edit" onclick="edit_contrib('4')" type="button" class="button">
If a label is not defined for a particular command, the name will be used instead.
columns_sortable => [qw( last first_middle )]
An arrayref containing the names of the columns (as defined by ``columns'') by which the user is allowed to sort. These column headers will be clickable JavaScript links which will modify the sorting order of the data listed.
An arrow will appear next to the current sort column. This graphical arrow will identify if the current sort order is ascending (up arrow) or descending (down arrow).
The first item in the list will be regarded as the default sort column. This column will be used for sort the first time the pager is invoked. This behavior, combined with the ``default_sort_order_desc'' property, allows you to control the default pager sort behavior.
columns_sort_map => { first_middle => 'first,middle' }
A hashref mapping the name of a sortable column to
the string which should be passed to find() via the
``order_by'' parameter. If a particular sortable column
is not specified, its name will be used instead. This
is probably adequate in most cases.
default_sort_order_desc => 1
A scalar containing a Boolean (1 or 0) value. If true, when the pager is first called the sort order will be set to ``descending'' If not set, this property will default to ``0'' and sort order will consequently default to ``ascending''.
row_handler => sub { $self->my_row_handler(@_) }
A subroutine reference pointing to a custom function to process each row of data. This function will receive, as arguments, a hashref into which row data should be placed, a reference to the object to be displayed on this row and a reference to the pager object. The job of your custom function is to convert the object attributes into template data and set that data in the hashref. For example:
sub my_row_handler {
my ($self, $row_hashref, $row_obj, $pager) = @_;
$row_hashref->{first_middle} = $row_obj->first() . " " . $row_obj->middle();
$row_hashref->{last} = $row_obj->last();
$row_hashref->{type} = join(", ", ($row_obj->contrib_type_names()) );
$pager->column_display('checkbox_column' => 1) if $row_obj->may_edit;
}
The purpose of passing in the pager object is to make the display of list controls (list checkbox and buttons) dependant on some row object attribute. The Trash for example may contain stories, media and templates. If a user has only template edit permission, but the trash contains no templates, the list controls should not be displayed.
id_handler => sub { return $_[0]->contrib_id }
A subroutine reference pointing to a custom function to return a unique identifier for each row of data. This ID is needed for creating the checkbox columns and command columns.
The referenced subroutine receives a reference to the object to be displayed on this row. The job of your custom function is to return a unique identifier for this row.
max_page_links => 10
Set this to the maximum number of page links that the pager should display. Any more pages outside this number will be represented by a ``...'' in the output HTML. If set to 0 all page links are shown. The default is 10.
It is expected that most of the time you will use the output() method
to run the pager and return a rendered block of HTML with your
interface. The HTML which is returned is generated internally within
Krang::HTMLPager.
In some cases, this internally-created HTML will not suffice. You may have to implement a screen which has a slightly different style to it. You may have additional functionality which is not compatible with that provided by the stock Krang::HTMLPager output. In these cases you may want to create your own custom Krang::HTMLPager template to replace the internal one.
This is not a task for the faint of heart. Your template must be
structured to be fully compatible with the internal template in
terms of HTML::Template structures. The easiest way to get started
with a custom template is to have Krang::HTMLPager dynamically
generate a template for you, which you can then customize. This
can be done via the make_internal_template() method:
my $pager = pkg('HTMLPager')->new(%pager_props);
my $template = $pager->make_internal_template();
Refer to the make_internal_template() POD in this document for more
details.
The template which is created contains all the variables necessary in a custom template, for the pager specification (%pager_props) you have provided. Following is a summary of the variables you will find.
In order to implement this functionality, one <TMPL_VAR> is expected for each column in the pager. These variables are named using the column name (as defined by the ``columns'' pager property), with the prefix, ``colhead_''.
The internal template uses ``prev_page_number'' in the context of a <TMPL_IF> to hide the previous page button on the first page.
(N.b.: A JavaScript function, ``Krang.Pager.goto_page()'', is provided for navigation between pages by pager-internals.tmpl. You are encouraged to use it.)
The internal template uses ``next_page_number'' in the context of a <TMPL_IF> to hide the next page button on the last page.
(N.b.: A JavaScript function, ``Krang.Pager.goto_page()'', is provided for navigation between pages by pager-internals.tmpl. You are encouraged to use it.)
(N.b.: A JavaScript function, ``Krang.Pager.goto_page()'', is provided for navigation between pages by pager-internals.tmpl. You are encouraged to use it.)
(N.b.: A JavaScript function, ``Krang.Pager.goto_page()'', is provided for navigation between pages by pager-internals.tmpl. You are encouraged to use it.)
(N.b.: A JavaScript function, ``Krang.Pager.show_big_view()'', is provided for toggling between modes by pager-internals.tmpl. You are encouraged to use it.)
show_big_view is true. Normally this
is 100, but if the user's preference is for 100, then this becomes 20.