From 51544498c588fd30facfa672f63c1e89f5c32447 Mon Sep 17 00:00:00 2001 From: Maicol Battistini Date: Tue, 23 Nov 2021 15:34:34 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20=E2=9C=A8=20Aggiunto=20ordinamento=20ne?= =?UTF-8?q?lla=20tabella?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/inspectionProfiles/Project_Default.xml | 4 +- package.json | 1 + pnpm-lock.yaml | 12 ++++ .../js/Components/DataTable/DataTable.jsx | 71 +++++++++++++++++++ .../js/Components/DataTable/TableColumn.jsx | 46 ++++++++++++ resources/js/Components/Pages/RecordsPage.jsx | 2 +- 6 files changed, 134 insertions(+), 2 deletions(-) diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 4f137b22c..3af56facc 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -99,7 +99,7 @@ diff --git a/package.json b/package.json index 87d920b90..c92b1a912 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@material/mwc-fab": "^0.25.3", "@material/mwc-formfield": "^0.25.3", "@material/mwc-icon-button": "^0.25.3", + "@material/mwc-icon-button-toggle": "^0.25.3", "@material/mwc-linear-progress": "^0.25.3", "@material/mwc-list": "^0.25.3", "@material/mwc-menu": "^0.25.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e4834b04e..90c1b8f85 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,7 @@ specifiers: '@material/mwc-fab': ^0.25.3 '@material/mwc-formfield': ^0.25.3 '@material/mwc-icon-button': ^0.25.3 + '@material/mwc-icon-button-toggle': ^0.25.3 '@material/mwc-linear-progress': ^0.25.3 '@material/mwc-list': ^0.25.3 '@material/mwc-menu': ^0.25.3 @@ -109,6 +110,7 @@ dependencies: '@material/mwc-fab': 0.25.3 '@material/mwc-formfield': 0.25.3 '@material/mwc-icon-button': 0.25.3 + '@material/mwc-icon-button-toggle': 0.25.3 '@material/mwc-linear-progress': 0.25.3 '@material/mwc-list': 0.25.3 '@material/mwc-menu': 0.25.3 @@ -2122,6 +2124,16 @@ packages: tslib: 2.3.1 dev: false + /@material/mwc-icon-button-toggle/0.25.3: + resolution: {integrity: sha512-H3eMHHZWyqO2Dd3FXiDOArmegUBpXB3vatZLPDHVFKABdZlt0M4qusgvV7IIo53urLqqcVo6u8FMjtv9VGnXpQ==} + dependencies: + '@material/mwc-base': 0.25.3 + '@material/mwc-icon-button': 0.25.3 + '@material/mwc-ripple': 0.25.3 + lit: 2.0.2 + tslib: 2.3.1 + dev: false + /@material/mwc-icon-button/0.25.3: resolution: {integrity: sha512-FexkMpK3ZSHh7NF+PIqvVhvAbBOgFDYPck/lqnxIDC3VGJ0rjD/1MqevDy2fY6IcHGlc8Ai7VuYbdQ6Cvw8WcQ==} dependencies: diff --git a/resources/js/Components/DataTable/DataTable.jsx b/resources/js/Components/DataTable/DataTable.jsx index 8acf0a72b..17ba3cf1c 100644 --- a/resources/js/Components/DataTable/DataTable.jsx +++ b/resources/js/Components/DataTable/DataTable.jsx @@ -2,6 +2,7 @@ import '@material/mwc-linear-progress'; import '@material/mwc-list/mwc-list-item'; import '@material/mwc-select'; +import {type Cash} from 'cash-dom/dist/cash'; import { type Children, type Vnode @@ -114,4 +115,74 @@ export default class DataTable extends Component { 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)); + } + + showProgress() { + $(this.element).find('.mdc-data-table__progress-indicator mwc-linear-progress').get(0).open(); + } + + hideProgress() { + $(this.element).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()); + } + } } diff --git a/resources/js/Components/DataTable/TableColumn.jsx b/resources/js/Components/DataTable/TableColumn.jsx index 1a6069604..b4e6467a9 100644 --- a/resources/js/Components/DataTable/TableColumn.jsx +++ b/resources/js/Components/DataTable/TableColumn.jsx @@ -1,4 +1,9 @@ +import '@material/mwc-icon-button-toggle'; + +import {type Cash} from 'cash-dom/dist/cash'; + import Component from '../Component.jsx'; +import Mdi from '../Mdi.jsx'; /** * Attributes: @@ -10,6 +15,24 @@ export default class TableColumn extends Component { [`mdc-data-table__header-cell--${this.attrs.get('type')}`]: this.attrs.has('type') }); + if (this.attrs.has('sortable')) { + this.attrs.addClassNames('mdc-data-table__header-cell--with-sort'); + this.attrs.put('aria-sort', 'none').put('data-column-id', this.attrs.get('id')); + + vnode.children = ( +
+ + + + +   +
+ {vnode.children} +
+
+ ); + } + if ((!vnode.children || vnode.children.length === 0) && this.attrs.get('type') === 'checkbox') { vnode.children = ; } @@ -32,5 +55,28 @@ export default class TableColumn extends Component { .prop('checked', checkbox.prop('checked')); }); } + + // Handle click on column (add arrows) + const observer = new MutationObserver((mutations) => { + for (const mutation of mutations) { + const {classList} = mutation.target; + const ascendingClass = 'mdc-data-table__header-cell--sorted'; + const descendingClass = 'mdc-data-table__header-cell--sorted-descending'; + + const onValue = classList.contains(descendingClass); + + const button: Cash = $(this.element).find('mwc-icon-button-toggle'); + button.prop('on', onValue); + + if (classList.contains(ascendingClass) || classList.contains(descendingClass)) { + $(this.element).css('cursor', 'auto').off('click'); + button.show(); + } + } + }); + observer.observe(this.element, { + attributes: true, + attributeFilter: ['class'] + }); } } diff --git a/resources/js/Components/Pages/RecordsPage.jsx b/resources/js/Components/Pages/RecordsPage.jsx index 4778d4de9..ca90ee7ee 100644 --- a/resources/js/Components/Pages/RecordsPage.jsx +++ b/resources/js/Components/Pages/RecordsPage.jsx @@ -124,7 +124,7 @@ export default class RecordsPage extends Page { return collect(this.columns) .map( (column: ColumnT | string, id: string) => ( - + {typeof column === 'string' ? column : column.title} )