@smui/data-table
Version:
Svelte Material UI - Data Table
310 lines • 13.5 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 { MDCComponent } from '@smui/base/component';
import { MDCCheckbox } from '@smui/checkbox/component';
import { closest } from '@smui/dom/ponyfill';
import { MDCLinearProgress } from '@smui/linear-progress/component';
import { cssClasses, dataAttributes, events, messages, selectors, SortValue, } from './constants';
import { MDCDataTableFoundation } from './foundation';
/** MDC Data Table */
export class MDCDataTable extends MDCComponent {
static attachTo(root) {
return new MDCDataTable(root);
}
initialize(checkboxFactory = (el) => new MDCCheckbox(el)) {
this.checkboxFactory = checkboxFactory;
}
initialSyncWithDOM() {
this.headerRow = this.root.querySelector(`.${cssClasses.HEADER_ROW}`);
this.handleHeaderRowCheckboxChange = () => {
this.foundation.handleHeaderRowCheckboxChange();
};
this.headerRow.addEventListener('change', this.handleHeaderRowCheckboxChange);
this.headerRowClickListener = (event) => {
this.handleHeaderRowClick(event);
};
this.headerRow.addEventListener('click', this.headerRowClickListener);
this.content = this.root.querySelector(`.${cssClasses.CONTENT}`);
this.handleContentClick = (event) => {
const dataRowEl = closest(event.target, selectors.ROW);
if (!dataRowEl)
return;
this.foundation.handleRowClick({
rowId: this.getRowIdByRowElement(dataRowEl),
row: dataRowEl,
altKey: event.altKey,
ctrlKey: event.ctrlKey,
metaKey: event.metaKey,
shiftKey: event.shiftKey,
});
};
this.content.addEventListener('click', this.handleContentClick);
this.handleRowCheckboxChange = (event) => {
this.foundation.handleRowCheckboxChange(event);
};
this.content.addEventListener('change', this.handleRowCheckboxChange);
this.layout();
}
/**
* Re-initializes header row checkbox and row checkboxes when selectable rows
* are added or removed from table.
*/
layout() {
this.foundation.layout();
}
/**
* @return Returns array of header row cell elements.
*/
getHeaderCells() {
return Array.from(this.root.querySelectorAll(selectors.HEADER_CELL));
}
/**
* @return Returns array of row elements.
*/
getRows() {
return this.foundation.getRows();
}
/**
* @return Returns array of selected row ids.
*/
getSelectedRowIds() {
return this.foundation.getSelectedRowIds();
}
/**
* Sets selected row ids. Overwrites previously selected rows.
* @param rowIds Array of row ids that needs to be selected.
*/
setSelectedRowIds(rowIds) {
this.foundation.setSelectedRowIds(rowIds);
}
/**
* Shows progress indicator when data table is in loading state.
*/
showProgress() {
this.getLinearProgress().open();
this.foundation.showProgress();
}
/**
* Hides progress indicator after data table is finished loading.
*/
hideProgress() {
this.foundation.hideProgress();
this.getLinearProgress().close();
}
destroy() {
if (this.handleHeaderRowCheckboxChange) {
this.headerRow.removeEventListener('change', this.handleHeaderRowCheckboxChange);
}
if (this.headerRowClickListener) {
this.headerRow.removeEventListener('click', this.headerRowClickListener);
}
if (this.handleRowCheckboxChange) {
this.content.removeEventListener('change', this.handleRowCheckboxChange);
}
if (this.headerRowCheckbox) {
this.headerRowCheckbox.destroy();
}
if (this.rowCheckboxList) {
for (const checkbox of this.rowCheckboxList) {
checkbox.destroy();
}
}
if (this.handleContentClick) {
this.content.removeEventListener('click', this.handleContentClick);
}
}
getDefaultFoundation() {
// DO NOT INLINE this variable. For backward compatibility, foundations take
// a Partial<MDCFooAdapter>. To ensure we don't accidentally omit any
// methods, we need a separate, strongly typed adapter variable.
// tslint:disable:object-literal-sort-keys Methods should be in the same order as the adapter interface.
const adapter = {
addClass: (className) => {
this.root.classList.add(className);
},
removeClass: (className) => {
this.root.classList.remove(className);
},
getHeaderCellElements: () => this.getHeaderCells(),
getHeaderCellCount: () => this.getHeaderCells().length,
getAttributeByHeaderCellIndex: (index, attribute) => {
return this.getHeaderCells()[index].getAttribute(attribute);
},
setAttributeByHeaderCellIndex: (index, attribute, value) => {
this.safeSetAttribute(this.getHeaderCells()[index], attribute, value);
},
setClassNameByHeaderCellIndex: (index, className) => {
this.getHeaderCells()[index].classList.add(className);
},
removeClassNameByHeaderCellIndex: (index, className) => {
this.getHeaderCells()[index].classList.remove(className);
},
notifySortAction: (data) => {
this.emit(events.SORTED, data, /** shouldBubble */ true);
},
getTableContainerHeight: () => {
const tableContainer = this.root.querySelector(`.${cssClasses.TABLE_CONTAINER}`);
if (!tableContainer) {
throw new Error('MDCDataTable: Table container element not found.');
}
return tableContainer.getBoundingClientRect().height;
},
getTableHeaderHeight: () => {
const tableHeader = this.root.querySelector(selectors.HEADER_ROW);
if (!tableHeader) {
throw new Error('MDCDataTable: Table header element not found.');
}
return tableHeader.getBoundingClientRect().height;
},
setProgressIndicatorStyles: (styles) => {
const progressIndicator = this.root.querySelector(selectors.PROGRESS_INDICATOR);
if (!progressIndicator) {
throw new Error('MDCDataTable: Progress indicator element not found.');
}
progressIndicator.style.setProperty('height', styles.height);
progressIndicator.style.setProperty('top', styles.top);
},
addClassAtRowIndex: (rowIndex, className) => {
this.getRows()[rowIndex].classList.add(className);
},
getRowCount: () => this.getRows().length,
getRowElements: () => Array.from(this.root.querySelectorAll(selectors.ROW)),
getRowIdAtIndex: (rowIndex) => this.getRows()[rowIndex].getAttribute(dataAttributes.ROW_ID),
getRowIndexByChildElement: (el) => {
return this.getRows().indexOf(closest(el, selectors.ROW));
},
getSelectedRowCount: () => this.root.querySelectorAll(selectors.ROW_SELECTED).length,
isCheckboxAtRowIndexChecked: (rowIndex) => this.rowCheckboxList[rowIndex].checked,
isHeaderRowCheckboxChecked: () => this.headerRowCheckbox.checked,
isRowsSelectable: () => !!this.root.querySelector(selectors.ROW_CHECKBOX) ||
!!this.root.querySelector(selectors.HEADER_ROW_CHECKBOX),
notifyRowSelectionChanged: (data) => {
this.emit(events.ROW_SELECTION_CHANGED, {
row: this.getRowByIndex(data.rowIndex),
rowId: this.getRowIdByIndex(data.rowIndex),
rowIndex: data.rowIndex,
selected: data.selected,
},
/** shouldBubble */ true);
},
notifySelectedAll: () => {
this.emit(events.SELECTED_ALL, {}, /** shouldBubble */ true);
},
notifyUnselectedAll: () => {
this.emit(events.UNSELECTED_ALL, {}, /** shouldBubble */ true);
},
notifyRowClick: (data) => {
this.emit(events.ROW_CLICK, data, /** shouldBubble */ true);
},
registerHeaderRowCheckbox: () => {
if (this.headerRowCheckbox) {
this.headerRowCheckbox.destroy();
}
const checkboxEl = this.root.querySelector(selectors.HEADER_ROW_CHECKBOX);
this.headerRowCheckbox = this.checkboxFactory(checkboxEl);
},
registerRowCheckboxes: () => {
if (this.rowCheckboxList) {
this.rowCheckboxList.forEach((checkbox) => {
checkbox.destroy();
});
}
this.rowCheckboxList = [];
this.getRows().forEach((rowEl) => {
const checkbox = this.checkboxFactory(rowEl.querySelector(selectors.ROW_CHECKBOX));
this.rowCheckboxList.push(checkbox);
});
},
removeClassAtRowIndex: (rowIndex, className) => {
this.getRows()[rowIndex].classList.remove(className);
},
setAttributeAtRowIndex: (rowIndex, attr, value) => {
this.safeSetAttribute(this.getRows()[rowIndex], attr, value);
},
setHeaderRowCheckboxChecked: (checked) => {
this.headerRowCheckbox.checked = checked;
},
setHeaderRowCheckboxIndeterminate: (indeterminate) => {
this.headerRowCheckbox.indeterminate = indeterminate;
},
setRowCheckboxCheckedAtIndex: (rowIndex, checked) => {
this.rowCheckboxList[rowIndex].checked = checked;
},
setSortStatusLabelByHeaderCellIndex: (columnIndex, sortValue) => {
const headerCell = this.getHeaderCells()[columnIndex];
const sortStatusLabel = headerCell.querySelector(selectors.SORT_STATUS_LABEL);
if (!sortStatusLabel)
return;
sortStatusLabel.textContent =
this.getSortStatusMessageBySortValue(sortValue);
},
};
return new MDCDataTableFoundation(adapter);
}
getRowByIndex(index) {
return this.getRows()[index];
}
getRowIdByIndex(index) {
return this.getRowByIndex(index).getAttribute(dataAttributes.ROW_ID);
}
handleHeaderRowClick(event) {
const headerCell = closest(event.target, selectors.HEADER_CELL_WITH_SORT);
if (!headerCell) {
return;
}
const columnId = headerCell.getAttribute(dataAttributes.COLUMN_ID);
const columnIndex = this.getHeaderCells().indexOf(headerCell);
if (columnIndex === -1) {
return;
}
this.foundation.handleSortAction({ columnId, columnIndex, headerCell });
}
getSortStatusMessageBySortValue(sortValue) {
switch (sortValue) {
case SortValue.ASCENDING:
return messages.SORTED_IN_ASCENDING;
case SortValue.DESCENDING:
return messages.SORTED_IN_DESCENDING;
default:
return '';
}
}
getLinearProgressElement() {
const el = this.root.querySelector(`.${cssClasses.LINEAR_PROGRESS}`);
if (!el) {
throw new Error('MDCDataTable: linear progress element is not found.');
}
return el;
}
getLinearProgress() {
if (!this.linearProgress) {
const el = this.getLinearProgressElement();
this.linearProgress = new MDCLinearProgress(el);
}
return this.linearProgress;
}
getRowIdByRowElement(rowElement) {
return rowElement.getAttribute(dataAttributes.ROW_ID);
}
}
//# sourceMappingURL=component.js.map