1
0
mirror of https://github.com/devcode-it/openstamanager.git synced 2025-02-25 15:58:56 +01:00
2021-11-30 19:51:33 +01:00

317 lines
9.6 KiB
JavaScript

import '@material/mwc-linear-progress';
import '@material/mwc-list/mwc-list-item';
import '../../WebComponents/Select';
import {type Cash} from 'cash-dom/dist/cash';
import {
type Children,
type Vnode
} from 'mithril';
import Component from '../Component.jsx';
import Mdi from '../Mdi.jsx';
import TableColumn from './TableColumn.jsx';
import TableFooter from './TableFooter.jsx';
import TableRow from './TableRow.jsx';
export default class DataTable extends Component {
rows: Cash[] = [];
columns: Children[];
footer: Children[];
rowsPerPage = {
options: [10, 25, 50, 75, 100],
currentStart: 0,
value: 10,
currentEnd: 10
}
onbeforeupdate(vnode) {
super.onbeforeupdate(vnode);
const children = (vnode.children: Children[]).flat();
this.rows = this.tableRows(children);
this.columns = this.filterElements(children, TableColumn);
this.footer = this.filterElements(children, TableFooter);
const rowsPerPage = this.attrs.get('rows-per-page');
if (rowsPerPage) {
this.rowsPerPage.options = rowsPerPage.split(',')
.map((value: string) => Number.parseInt(value, 10));
}
let defaultRowsPerPage = this.attrs.get('default-rows-per-page');
if (Number.isInteger(defaultRowsPerPage)) {
defaultRowsPerPage = Number.parseInt(defaultRowsPerPage, 10);
if (!this.rowsPerPage.options.includes(defaultRowsPerPage)) {
[defaultRowsPerPage] = this.rowsPerPage.options;
}
this.rowsPerPage.value = defaultRowsPerPage;
}
if (this.rowsPerPage.currentStart === 0) {
this.rowsPerPage.currentEnd = this.rowsPerPage.value >= this.rows.length ? this.rows.length
: defaultRowsPerPage;
}
}
onupdate(vnode) {
super.onupdate(vnode);
const rows: Cash = $(this.element).find('tbody tr');
rows.hide();
// eslint-disable-next-line no-plusplus
for (let index = this.rowsPerPage.currentStart; index < this.rowsPerPage.currentEnd; index++) {
rows.eq(index).show();
}
if (this.rowsPerPage.currentStart === 0) {
this.paginate('first');
}
}
view(vnode) {
return <div className="mdc-data-table" {...this.attrs.all()}>
<div className="mdc-data-table__table-container">
<table className="mdc-data-table__table" aria-label={this.attrs.get('aria-label')}>
<thead>
<tr className="mdc-data-table__header-row">
{this.attrs.has('checkable') && <TableColumn type="checkbox"/>}
{this.columns}
</tr>
</thead>
<tbody className="mdc-data-table__content">
{this.rows}
</tbody>
{this.footer}
</table>
{this.attrs.has('paginated') && <div className="mdc-data-table__pagination">
<div className="mdc-data-table__pagination-trailing">
<div className="mdc-data-table__pagination-rows-per-page">
<div className="mdc-data-table__pagination-rows-per-page-label">
{__('Righe per pagina')}
</div>
<material-select
outlined
className="mdc-data-table__pagination-rows-per-page-select"
fixedMenuPosition
style="--mdc-select-width: 112px; --mdc-select-height: 36px; --mdc-menu-item-height: 36px;"
>
{this.rowsPerPage.options.map(
rowsPerPage => (
<mwc-list-item
key={rowsPerPage}
value={rowsPerPage}
selected={this.rowsPerPage.value === rowsPerPage}
>
{rowsPerPage}
</mwc-list-item>
)
)}
</material-select>
</div>
<div className="mdc-data-table__pagination-navigation">
<div className="mdc-data-table__pagination-total">
{__(':start-:chunk di :total', {
start: this.rowsPerPage.currentStart + 1,
chunk: this.rowsPerPage.currentEnd,
total: this.rows.length
})}
</div>
<mwc-icon-button className="mdc-data-table__pagination-button" data-page="first"
disabled>
<Mdi icon="page-first"/>
</mwc-icon-button>
<mwc-icon-button className="mdc-data-table__pagination-button" data-page="previous"
disabled>
<Mdi icon="chevron-left"/>
</mwc-icon-button>
<mwc-icon-button className="mdc-data-table__pagination-button" data-page="next">
<Mdi icon="chevron-right"/>
</mwc-icon-button>
<mwc-icon-button className="mdc-data-table__pagination-button" data-page="last">
<Mdi icon="page-last"/>
</mwc-icon-button>
</div>
</div>
</div>}
<div className="mdc-data-table__progress-indicator">
<div className="mdc-data-table__scrim"/>
<mwc-linear-progress className="mdc-data-table__linear-progress" indeterminate/>
</div>
</div>
</div>;
}
tableRows(children: Children[]): Children[] {
let rows = this.filterElements(children, TableRow);
if (this.attrs.has('checkable')) {
rows = rows.map((row: Vnode) => (
<TableRow key={row.attrs.key} checkable {...row.attrs}>
{row.children}
</TableRow>
));
}
return rows;
}
filterElements(elements: Children[], tag: Component | string): Children[] {
const filtered = [];
for (const element: Vnode of elements) {
if (element.tag === tag) {
filtered.push(element);
}
}
return filtered;
}
oncreate(vnode) {
super.oncreate(vnode);
$(this.element)
.find('thead th[sortable], thead th[sortable] mwc-icon-button-toggle')
.on('click', this.onColumnClicked.bind(this));
$(this.element).find('.mdc-data-table__pagination-rows-per-page-select')
.on('selected', this.onPaginationSelected.bind(this));
$(this.element).find('.mdc-data-table__pagination-button')
.on('click', this.onPaginationButtonClicked.bind(this));
}
showProgress() {
$(this.element)
.addClass('mdc-data-table--in-progress')
.find('.mdc-data-table__progress-indicator mwc-linear-progress')
.get(0)
.open();
}
hideProgress() {
$(this.element)
.removeClass('mdc-data-table--in-progress')
.find('.mdc-data-table__progress-indicator mwc-linear-progress')
.get(0)
.open();
}
onColumnClicked(event: Event) {
this.showProgress();
const column: Cash = $(event.target)
.closest('th');
const ascendingClass = 'mdc-data-table__header-cell--sorted';
const descendingClass = 'mdc-data-table__header-cell--sorted-descending';
// If it's already sorted change direction
if (column.hasClass(ascendingClass)) {
column.toggleClass(descendingClass);
}
// Clean previously sorted info and arrows
const columns = $(this.element)
.find('thead th');
columns.removeClass(ascendingClass);
columns.find('mwc-icon-button-toggle')
.hide();
// Add ony one header to sort
column.addClass(ascendingClass);
// Check if need descending sorting
const isDescending = column.hasClass(descendingClass);
// Do sorting
this.sortTable(column.index() + 1, isDescending, column.attr('type') === 'numeric');
}
sortTable(columnIndex: number, isDescending: boolean, isNumeric: boolean) {
const sorted = [...$(this.element)
.find(`tr td:nth-child(${columnIndex})`)].sort((a: HTMLElement, b: HTMLElement) => {
let aValue = a.textContent;
let bValue = b.textContent;
if (isNumeric) {
aValue = Number.parseFloat(aValue);
bValue = Number.parseFloat(bValue);
}
if (!isDescending) {
const temporary = aValue;
aValue = bValue;
bValue = temporary;
}
if (typeof aValue === 'string') {
return aValue.localeCompare(bValue);
}
return aValue < bValue ? -1 : (aValue > bValue ? 1 : 0);
});
for (const cell of sorted) {
const row = $(cell)
.parent();
row.appendTo(row.parent());
}
}
onPaginationSelected(event: Event) {
this.rowsPerPage.value = $(event.target).find('mwc-list-item').eq(event.detail.index).val();
this.rowsPerPage.currentStart = 0;
this.rowsPerPage.currentEnd = this.rowsPerPage.value;
m.redraw();
}
onPaginationButtonClicked(event: Event) {
const button: Cash = $(event.target);
this.paginate(button.data('page'));
m.redraw();
}
paginate(action: 'first' | 'next' | 'previous' | 'last') {
const increments = {
first: -this.rowsPerPage.currentStart,
next: this.rowsPerPage.value,
previous: -this.rowsPerPage.value,
last: this.rows.length - this.rowsPerPage.currentStart
};
const increment = increments[action];
if (action !== 'first') {
this.rowsPerPage.currentStart += increment;
}
if (action !== 'last') {
this.rowsPerPage.currentEnd += increment;
}
const paginationButtons: Cash = $(this.element).find('.mdc-data-table__pagination-button');
const disabled = {
first: this.rowsPerPage.currentStart === 0,
previous: this.rowsPerPage.currentStart === 0,
next: this.rowsPerPage.currentEnd >= this.rows.length,
last: this.rowsPerPage.currentEnd >= this.rows.length
};
for (const button of paginationButtons) {
const buttonElement = $(button);
const buttonAction = buttonElement.data('page');
buttonElement.prop('disabled', disabled[buttonAction]);
}
}
}