Source code for uw.web.html.sorttable

"""Sort table routines.

This module makes it easy to use tables that can be sorted by clicking the
headers.

The main routine provided by this module is :func:`render_sort_table`.  In
order for this to work, the header_insert provided to
:func:`uw.local.webtools.web_main` should include the header_insert values
from this module.
"""

from collections import namedtuple

from ll.xist import xsc
from ll.xist.ns import html

from uw.web.html.format import make_table_format

header_insert = [
    html.script (src="//odyssey.uwaterloo.ca/static/table-sort.js", type="text/javascript"),
    html.link (href="//odyssey.uwaterloo.ca/static/table-sort.css", rel="stylesheet", type="text/css"),
]

[docs]class table_column (namedtuple ('table_column', ['col', 'head', 'content', 'attr', 'sort_style'])): """A namedtuple class representing the definition of a table column. The namedtuple elements are col, head, content, attr, and sort_style. The constructor of this class, however, allows omitting elements, in which case the natural default will be used in each case. An additional sort_order element may be provided, which should be a function from a data row to a sort order value. This is a convenient way of adding the data-sort-value attribute which could otherwise be provided by the attr function. """ def __new__ (cls, col=None, head=None, content=None, attr=None, sort_order=None, sort_style=None): if col is None: col = html.col () if content is None: content = lambda r: None if attr is None: attr = lambda r: {} if sort_order is None: complete_attr = attr else: def complete_attr (value): result = attr (value) result["data-sort-value"] = sort_order (value) return result if sort_style is None: sort_style = 'string-ins' elif sort_style == 'none': sort_style = None return super (table_column, cls).__new__ (cls, col, head, content, complete_attr, sort_style)
[docs]def make_table_format_sortable (*columns, **keys): """Compute a function for producing an HTML <table> which is sortable. :param columns: a list of column definitions. :param keys['header_row']: a function to be invoked before the first item row which may also return an extra row. :param keys['before_row']: a function to be invoked before each item row which may also return an extra row. :param keys['after_row']: a function to be invoked after each item row which may also return an extra row. :param keys['footer_row']: a function to be invoked after the last item row which may also return an extra row. :param keys['row_attributor']: a function to be invoked on each item which returns a dictionary of attributes for the <tr> element. Returns a function which, when passed a list of items, returns an HTML <table> with one column for each entry in columns, and one row for each item in the list of items, as well as a header row and possibly some additional rows depending on the optional keyword parameters supplied. Each element of columns is a column definition, which is an instance of :class:`table_column`. The \*_row keyword parameters specify additional computations to take place at the noted point in computation of the result table. They may also return additional rows if that is useful in a particular use. One use of this is for header_row to initialize counters or totals, and footer_row to produce a row which displays the final results. """ format_raw_table = make_table_format (*(tc[:4] for tc in columns), use_colgroup=True, **keys) def format_table (rows): result = format_raw_table (rows) result['class'] = "sorttable sorttable-countcolumn" # Insert extra <col> element for numeric count column result[0][0:0] = html.col (width='3%') # Set data-sort attributes of table headers for th, column in zip (result[1], columns): th['data-sort'] = column.sort_style result[1] = html.thead (result[1]) return result return format_table