UNPKG

azure-devops-ui

Version:

React components for building web UI in Azure DevOps

116 lines (115 loc) 4.96 kB
import { cellFromEvent } from '../../List'; import { KeyCode } from '../../Util'; import { SortOrder } from "./Table.Props"; /** * The ColumnSorting class is a behavior that can be used with the Table * component to provide column sorting. To use the ColumnSorting, create an * instance passing the sorting delegate to the constructor. Then supply * the created behavior to the table. */ export class ColumnSorting { constructor(onSort) { this.initialize = (props, table, eventDispatch) => { this.props = props; this.eventDispatch = eventDispatch; eventDispatch.addEventListener("click", this.onClick); eventDispatch.addEventListener("keydown", this.onKeyDown); }; this.componentDidMount = (props) => { this.props = props; }; this.componentDidUpdate = (props) => { this.props = props; }; this.componentWillUnmount = () => { if (this.eventDispatch) { this.eventDispatch.removeEventListener("click", this.onClick); this.eventDispatch.removeEventListener("keydown", this.onKeyDown); } }; this.onClick = (event) => { if (!event.defaultPrevented) { this.processSortEvent(event, true); } }; this.onKeyDown = (event) => { if (!event.defaultPrevented) { if (event.which === KeyCode.enter || event.which === KeyCode.space) { this.processSortEvent(event); } } }; this.onSort = onSort; } processSortEvent(event, click) { if (document.body.getAttribute('data-resize-active') === 'true' || document.body.getAttribute('data-resize-active') === 'false') { return; } const clickedCell = cellFromEvent(event); // Check if we clicked on an actionable area; walk up to see if we clicked within one let testHtmlElement = event.target; let actionableClick = click ? false : testHtmlElement.classList.contains("bolt-table-header-cell-actionable"); if (testHtmlElement.classList.contains("bolt-table-header-sizer")) { return; } while (!actionableClick && testHtmlElement !== clickedCell.cellElement) { if (testHtmlElement.parentElement) { testHtmlElement = testHtmlElement.parentElement; } else { break; } actionableClick = testHtmlElement.classList.contains("bolt-table-header-cell-actionable"); } if (clickedCell.rowIndex === -1 && actionableClick) { const column = this.props.columns[clickedCell.cellIndex]; // If the column is currently sorted ascending then we need to invert the sort. if (column && column.sortProps) { const newSortOrder = column.sortProps.sortOrder === SortOrder.ascending ? SortOrder.descending : SortOrder.ascending; this.onSort(clickedCell.cellIndex, newSortOrder, event); event.preventDefault(); } } } } /** * sortItems is a helper method that works with the ColumnSorting and a Table * component to make it eaiser to maintain the props of the table. This function * will update the column definitions and return the sorted data. The caller * needs to update the props to the table appropriately after calling this * method. * * @param columnIndex The column that should be sorted. * @param sortOrder The order the data should be sorted. * @param sortFunctions An array of sort functions. Each sortable column should * have a function supplied. If there are non-sortable columns, null should be * supplied for their index. * @param columns The column definitions for the table. * @param items The array of items that should be sorted. Note: This is done in * place so the input array will be updated. * * @return The resulting sorted array of items. */ export function sortItems(columnIndex, sortOrder, sortFunctions, columns, items) { let sortFunction = sortFunctions[columnIndex]; // If we are sorting descending, invert the sorting function. if (sortFunction && sortOrder === SortOrder.descending) { sortFunction = (item1, item2) => { return -sortFunctions[columnIndex](item1, item2); }; } // Update the sortOrder for each of the columns. for (let index = 0; index < columns.length; index++) { const column = columns[index]; if (column.sortProps) { column.sortProps.sortOrder = index === columnIndex ? sortOrder : undefined; } } if (sortFunction) { return items.sort(sortFunction); } else { return items; } }