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
{this.attrs.has('checkable') && } {this.columns} {this.rows} {this.footer}
{this.attrs.has('paginated') &&
{__('Righe per pagina')}
{this.rowsPerPage.options.map( rowsPerPage => ( {rowsPerPage} ) )}
{__(':start-:chunk di :total', { start: this.rowsPerPage.currentStart + 1, chunk: this.rowsPerPage.currentEnd, total: this.rows.length })}
}
; } tableRows(children: Children[]): Children[] { let rows = this.filterElements(children, TableRow); if (this.attrs.has('checkable')) { rows = rows.map((row: Vnode) => ( {row.children} )); } 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]); } } }