@smui/data-table
Version:
Svelte Material UI - Data Table
284 lines • 11.8 kB
JavaScript
/**
* @license
* Copyright 2019 Google Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import { MDCFoundation } from '@smui/base/foundation';
import { cssClasses, SortValue, attributes } from './constants';
/**
* The Foundation of data table component containing pure business logic, any
* logic requiring DOM manipulation are delegated to adapter methods.
*/
export class MDCDataTableFoundation extends MDCFoundation {
static get defaultAdapter() {
return {
addClass: () => undefined,
addClassAtRowIndex: () => undefined,
getAttributeByHeaderCellIndex: () => '',
getHeaderCellCount: () => 0,
getHeaderCellElements: () => [],
getRowCount: () => 0,
getRowElements: () => [],
getRowIdAtIndex: () => '',
getRowIndexByChildElement: () => 0,
getSelectedRowCount: () => 0,
getTableContainerHeight: () => 0,
getTableHeaderHeight: () => 0,
isCheckboxAtRowIndexChecked: () => false,
isHeaderRowCheckboxChecked: () => false,
isRowsSelectable: () => false,
notifyRowSelectionChanged: () => undefined,
notifySelectedAll: () => undefined,
notifySortAction: () => undefined,
notifyUnselectedAll: () => undefined,
notifyRowClick: () => undefined,
registerHeaderRowCheckbox: () => undefined,
registerRowCheckboxes: () => undefined,
removeClass: () => undefined,
removeClassAtRowIndex: () => undefined,
removeClassNameByHeaderCellIndex: () => undefined,
setAttributeAtRowIndex: () => undefined,
setAttributeByHeaderCellIndex: () => undefined,
setClassNameByHeaderCellIndex: () => undefined,
setHeaderRowCheckboxChecked: () => undefined,
setHeaderRowCheckboxIndeterminate: () => undefined,
setProgressIndicatorStyles: () => undefined,
setRowCheckboxCheckedAtIndex: () => undefined,
setSortStatusLabelByHeaderCellIndex: () => undefined,
};
}
constructor(adapter) {
super(Object.assign(Object.assign({}, MDCDataTableFoundation.defaultAdapter), adapter));
}
/**
* Re-initializes header row checkbox and row checkboxes when selectable rows
* are added or removed from table. Use this if registering checkbox is
* synchronous.
*/
layout() {
if (this.adapter.isRowsSelectable()) {
this.adapter.registerHeaderRowCheckbox();
this.adapter.registerRowCheckboxes();
this.setHeaderRowCheckboxState();
}
}
/**
* Re-initializes header row checkbox and row checkboxes when selectable rows
* are added or removed from table. Use this if registering checkbox is
* asynchronous.
*/
async layoutAsync() {
if (this.adapter.isRowsSelectable()) {
await this.adapter.registerHeaderRowCheckbox();
await this.adapter.registerRowCheckboxes();
this.setHeaderRowCheckboxState();
}
}
/**
* @return Returns array of row elements.
*/
getRows() {
return this.adapter.getRowElements();
}
/**
* @return Array of header cell elements.
*/
getHeaderCells() {
return this.adapter.getHeaderCellElements();
}
/**
* Sets selected row ids. Overwrites previously selected rows.
* @param rowIds Array of row ids that needs to be selected.
*/
setSelectedRowIds(rowIds) {
for (let rowIndex = 0; rowIndex < this.adapter.getRowCount(); rowIndex++) {
const rowId = this.adapter.getRowIdAtIndex(rowIndex);
let isSelected = false;
if (rowId && rowIds.indexOf(rowId) >= 0) {
isSelected = true;
}
this.adapter.setRowCheckboxCheckedAtIndex(rowIndex, isSelected);
this.selectRowAtIndex(rowIndex, isSelected);
}
this.setHeaderRowCheckboxState();
}
/**
* @return Returns array of all row ids.
*/
getRowIds() {
const rowIds = [];
for (let rowIndex = 0; rowIndex < this.adapter.getRowCount(); rowIndex++) {
rowIds.push(this.adapter.getRowIdAtIndex(rowIndex));
}
return rowIds;
}
/**
* @return Returns array of selected row ids.
*/
getSelectedRowIds() {
const selectedRowIds = [];
for (let rowIndex = 0; rowIndex < this.adapter.getRowCount(); rowIndex++) {
if (this.adapter.isCheckboxAtRowIndexChecked(rowIndex)) {
selectedRowIds.push(this.adapter.getRowIdAtIndex(rowIndex));
}
}
return selectedRowIds;
}
/**
* Handles header row checkbox change event.
*/
handleHeaderRowCheckboxChange() {
const isHeaderChecked = this.adapter.isHeaderRowCheckboxChecked();
for (let rowIndex = 0; rowIndex < this.adapter.getRowCount(); rowIndex++) {
this.adapter.setRowCheckboxCheckedAtIndex(rowIndex, isHeaderChecked);
this.selectRowAtIndex(rowIndex, isHeaderChecked);
}
if (isHeaderChecked) {
this.adapter.notifySelectedAll();
}
else {
this.adapter.notifyUnselectedAll();
}
}
/**
* Handles change event originated from row checkboxes.
*/
handleRowCheckboxChange(event) {
const rowIndex = this.adapter.getRowIndexByChildElement(event.target);
if (rowIndex === -1) {
return;
}
const selected = this.adapter.isCheckboxAtRowIndexChecked(rowIndex);
this.selectRowAtIndex(rowIndex, selected);
this.setHeaderRowCheckboxState();
const rowId = this.adapter.getRowIdAtIndex(rowIndex);
this.adapter.notifyRowSelectionChanged({ rowId, rowIndex, selected });
}
/**
* Handles sort action on sortable header cell.
*/
handleSortAction(eventData) {
const { columnId, columnIndex, headerCell } = eventData;
// Reset sort attributes / classes on other header cells.
for (let index = 0; index < this.adapter.getHeaderCellCount(); index++) {
if (index === columnIndex) {
continue;
}
this.adapter.removeClassNameByHeaderCellIndex(index, cssClasses.HEADER_CELL_SORTED);
this.adapter.removeClassNameByHeaderCellIndex(index, cssClasses.HEADER_CELL_SORTED_DESCENDING);
this.adapter.setAttributeByHeaderCellIndex(index, attributes.ARIA_SORT, SortValue.NONE);
this.adapter.setSortStatusLabelByHeaderCellIndex(index, SortValue.NONE);
}
// Set appropriate sort attributes / classes on target header cell.
this.adapter.setClassNameByHeaderCellIndex(columnIndex, cssClasses.HEADER_CELL_SORTED);
const currentSortValue = this.adapter.getAttributeByHeaderCellIndex(columnIndex, attributes.ARIA_SORT);
let sortValue = SortValue.NONE;
// Set to descending if sorted on ascending order.
if (currentSortValue === SortValue.ASCENDING) {
this.adapter.setClassNameByHeaderCellIndex(columnIndex, cssClasses.HEADER_CELL_SORTED_DESCENDING);
this.adapter.setAttributeByHeaderCellIndex(columnIndex, attributes.ARIA_SORT, SortValue.DESCENDING);
sortValue = SortValue.DESCENDING;
// Set to ascending if sorted on descending order.
}
else if (currentSortValue === SortValue.DESCENDING) {
this.adapter.removeClassNameByHeaderCellIndex(columnIndex, cssClasses.HEADER_CELL_SORTED_DESCENDING);
this.adapter.setAttributeByHeaderCellIndex(columnIndex, attributes.ARIA_SORT, SortValue.ASCENDING);
sortValue = SortValue.ASCENDING;
}
else {
// Set to ascending by default when not sorted.
this.adapter.setAttributeByHeaderCellIndex(columnIndex, attributes.ARIA_SORT, SortValue.ASCENDING);
sortValue = SortValue.ASCENDING;
}
this.adapter.setSortStatusLabelByHeaderCellIndex(columnIndex, sortValue);
this.adapter.notifySortAction({
columnId,
columnIndex,
headerCell,
sortValue,
});
}
/**
* Handles data table row click event.
*/
handleRowClick({ rowId, row, altKey, ctrlKey, metaKey, shiftKey, }) {
this.adapter.notifyRowClick({
rowId,
row,
altKey,
ctrlKey,
metaKey,
shiftKey,
});
}
/**
* Shows progress indicator blocking only the table body content when in
* loading state.
*/
showProgress() {
const tableHeaderHeight = this.adapter.getTableHeaderHeight();
// Calculate the height of table content (Not scroll content) excluding
// header row height.
const height = this.adapter.getTableContainerHeight() - tableHeaderHeight;
const top = tableHeaderHeight;
this.adapter.setProgressIndicatorStyles({
height: `${height}px`,
top: `${top}px`,
});
this.adapter.addClass(cssClasses.IN_PROGRESS);
}
/**
* Hides progress indicator when data table is finished loading.
*/
hideProgress() {
this.adapter.removeClass(cssClasses.IN_PROGRESS);
}
/**
* Updates header row checkbox state based on number of rows selected.
*/
setHeaderRowCheckboxState() {
if (this.adapter.getSelectedRowCount() === 0) {
this.adapter.setHeaderRowCheckboxChecked(false);
this.adapter.setHeaderRowCheckboxIndeterminate(false);
}
else if (this.adapter.getSelectedRowCount() === this.adapter.getRowCount()) {
this.adapter.setHeaderRowCheckboxChecked(true);
this.adapter.setHeaderRowCheckboxIndeterminate(false);
}
else {
this.adapter.setHeaderRowCheckboxIndeterminate(true);
this.adapter.setHeaderRowCheckboxChecked(false);
}
}
/**
* Sets the attributes of row element based on selection state.
*/
selectRowAtIndex(rowIndex, selected) {
if (selected) {
this.adapter.addClassAtRowIndex(rowIndex, cssClasses.ROW_SELECTED);
this.adapter.setAttributeAtRowIndex(rowIndex, attributes.ARIA_SELECTED, 'true');
}
else {
this.adapter.removeClassAtRowIndex(rowIndex, cssClasses.ROW_SELECTED);
this.adapter.setAttributeAtRowIndex(rowIndex, attributes.ARIA_SELECTED, 'false');
}
}
}
//# sourceMappingURL=foundation.js.map