# Expected front-end version

This documentation assumes you're using @qnc/qnc_data_tables==1.1.0

You _may_ use some of the back-end features with older front-ends, but not all features will work. 
You _may_ use newer versions of the front-end (within the same major version), but some newer front-end features may not be configurable or accessible.

## Documention

This README expains how to use the back-end project, and basic information about setting up the front-end. For basic purposes, all you need to know is the back-end. For more advanced front-end features (eg. accessing/modifying a table's selected rows, triggering a table to reload, etc.) see the documentation for the front-end.

## Installation/usage

1. Install the front-end (eg. `npm install --save-dev @qnc/qnc_data_tables`, follow setup instructions for front-end)
2. Install the back-end (eg. `pip install qnc_data_tables`, follow setup instructions for backend)

3. In a view for a page that renders a data table:
- create a qnc_data_tables.TableManager instance
- if request.method == POST, return table_manager.handle(...)
- otherwise, use `qnc_data_tables.render_*` functions to render the table and (optionally) selection buttons 


## Cell Transformations

The cell content (html) returned by `Column.formatter` will undergo one of several possible transformations by the front-end, depending on what that html specifies. I don't like this approach, but it seems to be the only way to support several important patterns while protecting from common pitfalls.

Here we describe the different transformations in "most specific" to "most common" order. The first condition which is satisfied describes the transform we use.

When we talk about "cell html matching an element", we mean that the string of html represents one complete element, with no surrounding text (not even whitespace). `<b>Something</b>` matches a `b` element, but ` <b>Something</b>` does not.

### <* data-qdt-full-cell>

This is recommended only for special situations requiring exact control over the cell.

If the cell html matches one element (of any type) with attribute `data-qdt-full-cell`, then that element will be used directly as the entire cell. It's parent element is a flex container, which will stretch it to the width of the column and height of the row. 

It will "inherit" the standard cell padding set on the table. Specifically, it will match a CSS selector with a specificity of 1 class applying the following rules:

```
.some-class-selector {
    padding: var(--qdt-cell-vertical-padding) var(--qdt-cell-horizontal-padding);
}
```

You may change the padding, as you see fit (via style attribute or class).

When you use `data-qdt-full-cell`, you're opting out of our techniques for aligning the content within the cell. You're on your own. 

If you set display to `flex` or `grid` on such an element, and that element has direct text node childen, then our `text-overflow: ellipsis` style won't work reliably.


### <a> or <div>

This is useful if you need to override the padding or alignment on a per-row basis. In the case of `a` tags, it also makes the entire cell (including the padding) clickable.

This is similar to the `data-qdt-full-cell` case, but we also wrap the element's children in an extra div (ie. we remove all the children of the element, append them to a div, and then append that to the element).

The element will "inherit" the standard cell padding as set on the table. Additionally, it will align its contents (the extra div wrapper) both vertically and horizontally, according to table/column configuration. Specifically, it will match:

```
.some-class-selector {
    padding: var(--qdt-cell-vertical-padding) var(--qdt-cell-horizontal-padding);
    display: flex;
    align-items: var(--qdt-cell-align-items); /* for vertical alignment */
    justify-content: var(--qdt-cell-justify-content); /* for horizontal alignment */
}
```

You may change the padding, as you see fit.
You may use `align-items` or `justify-content` on the element to override the alignment for this cell.

Aside: the extra wrapping div serves two purposes:
- restores standard flow layout (while allowing us to align the content as a group)
- enables `text-overflow: ellipsis;` to work on text nodes (if they were directly inside the flex parent, then text-overflow wouldn't work)

### <button> or <label>

These behave just like `a` / `div` elements, except that their content is wrapped in a span, instead of a div (since neither of these elements may have div children, according to the HTML spec). Useful when you want a full-cell button or label.

### Anything else

Any other content will be wrapped in two nested `div` elements. The outer one has the padding and display flex. The inner one is "plain". You have no ability to change the padding or alignment.




## Horizontal alignment

Headings and cell content are center-aligned by default. Use the `Column.horizontal_alignment` attribute for changing alignment of the entire column (including the header). Individual data cell alignment can be overridden (per row) by having the formatter function return an element with `justify-content` set to a different value. This element will have `display: flex; flex-direction: row`, so `justify-content` sets the horizontal position of its children.

## Vertical alignment

Headings and cell contents are both centered vertically, by default.

There is no means of overriding header vertical alignment.

Data cell vertical alignment can be set (for all data rows) with the `Column.data_vertical_alignment` attribute. Individual data cell alignment can be overridden (per row) by having the formatter function return an element with `align-items` set to a different value. This element will have `display: flex; flex-direction: row`, so `align-items` sets the vertical position of its children.




