1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219 |
- /* eslint-disable prefer-destructuring */
- /* eslint-disable max-depth */
- /* eslint-disable max-nested-callbacks */
- /* eslint-disable max-len */
- /* eslint-disable no-param-reassign */
- /* eslint-disable eqeqeq */
- /* eslint-disable @typescript-eslint/no-empty-function */
- import {
- get,
- merge,
- isFunction,
- each,
- find,
- some,
- pull,
- isSet,
- filter,
- isMap,
- slice,
- isEqual
- } from 'lodash';
- import memoizeOne from 'memoize-one';
- import { ArrayElement } from '../utils/type';
- import { BaseCheckboxProps } from '../checkbox/checkboxFoundation';
- import BaseFoundation, { DefaultAdapter } from '../base/foundation';
- import { strings, numbers } from './constants';
- import { mergeQueries, flattenColumns, filterColumns } from './utils';
- import { pullAll, withOrderSort } from '../utils/array';
- export interface BaseColumnProps<RecordType> {
- align?: BaseAlign;
- children?: Array<BaseColumnProps<RecordType>>;
- className?: string;
- colSpan?: number;
- dataIndex?: string;
- defaultFilteredValue?: any[];
- defaultSortOrder?: BaseSortOrder;
- filterChildrenRecord?: boolean;
- filterDropdown?: any;
- filterDropdownProps?: Record<string, any>;
- filterDropdownVisible?: boolean;
- filterIcon?: any;
- filterMultiple?: boolean;
- filteredValue?: any[];
- filters?: BaseFilter[];
- fixed?: BaseFixed;
- key?: string | number;
- onCell?: BaseOnCell<RecordType>;
- onFilter?: BaseOnFilter<RecordType>;
- onFilterDropdownVisibleChange?: BaseOnFilterDropdownVisibleChange;
- onHeaderCell?: BaseOnHeaderCell<RecordType>;
- render?: (...args: any[]) => any;
- renderFilterDropdownItem?: (...args: any[]) => any;
- sortChildrenRecord?: boolean;
- sortOrder?: BaseSortOrder;
- sorter?: BaseSorter<RecordType>;
- title?: any;
- useFullRender?: boolean;
- width?: string | number;
- }
- export interface TableAdapter<RecordType> extends DefaultAdapter {
- resetScrollY: () => void;
- setSelectedRowKeys: (selectedRowKeys: BaseRowKeyType[]) => void;
- setDisabledRowKeys: (disabledRowKeys: BaseRowKeyType[]) => void;
- setCurrentPage: (currentPage: number) => void;
- setPagination: (pagination: BasePagination) => void;
- setGroups: (groups: Map<string, RecordType[]>) => void;
- setDataSource: (dataSource: RecordType[]) => void;
- setExpandedRowKeys: (expandedRowKeys: BaseRowKeyType[]) => void;
- setQuery: (query?: BaseColumnProps<RecordType>) => void;
- setQueries: (queries: BaseColumnProps<RecordType>[]) => void;
- setFlattenData: (flattenData: RecordType[]) => void;
- setAllRowKeys: (allRowKeys: BaseRowKeyType[]) => void;
- setHoveredRowKey: (hoveredRowKey: BaseRowKeyType) => void;
- setCachedFilteredSortedDataSource: (filteredSortedDataSource: RecordType[]) => void;
- setCachedFilteredSortedRowKeys: (filteredSortedRowKeys: BaseRowKeyType[]) => void;
- getCurrentPage: () => number;
- getCurrentPageSize: () => number;
- getCachedFilteredSortedDataSource: () => RecordType[];
- getCachedFilteredSortedRowKeys: () => BaseRowKeyType[];
- getCachedFilteredSortedRowKeysSet: () => Set<BaseRowKeyType>;
- notifyFilterDropdownVisibleChange: (visible: boolean, dataIndex: string) => void;
- notifyChange: (changeInfo: { pagination: BasePagination; filters: BaseChangeInfoFilter<RecordType>[]; sorter: BaseChangeInfoSorter<RecordType>; extra: any }) => void;
- notifyExpand: (expanded?: boolean, record?: BaseIncludeGroupRecord<RecordType>, mouseEvent?: any) => void;
- notifyExpandedRowsChange: (expandedRows: BaseIncludeGroupRecord<RecordType>[]) => void;
- notifySelect: (record?: BaseIncludeGroupRecord<RecordType>, selected?: boolean, selectedRows?: BaseIncludeGroupRecord<RecordType>[], nativeEvent?: any) => void;
- notifySelectAll: (selected?: boolean, selectedRows?: BaseIncludeGroupRecord<RecordType>[], changedRows?: BaseIncludeGroupRecord<RecordType>[], e?: any) => void;
- notifySelectInvert: (record?: RecordType[], selected?: boolean, selectedRows?: BaseIncludeGroupRecord<RecordType>[], nativeEvent?: any) => void;
- notifySelectionChange: (selectedRowKeys: BaseRowKeyType[], selectedRows: BaseIncludeGroupRecord<RecordType>[]) => void;
- isAnyColumnFixed: (columns?: BaseColumnProps<RecordType>[]) => boolean;
- useFixedHeader: () => boolean;
- setHeadWidths: (headWidths: Array<BaseHeadWidth>, index?: number) => void;
- getHeadWidths: (index?: number) => number[];
- getCellWidths: (flattenedColumns: BaseColumnProps<RecordType>[], flattenedWidths?: BaseHeadWidth[], ignoreScrollBarKey?: boolean) => number[];
- mergedRowExpandable: (record: RecordType) => boolean;
- isAnyColumnUseFullRender: (columns: BaseColumnProps<RecordType>[]) => boolean;
- getNormalizeColumns: () => (columns: BaseColumnProps<RecordType>[], children: any) => BaseColumnProps<RecordType>[];
- getHandleColumns: () => (queries: BaseColumnProps<RecordType>[], cachedColumns: BaseColumnProps<RecordType>[]) => BaseColumnProps<RecordType>[];
- getMergePagination: () => (pagination: BasePagination) => BasePagination;
- setBodyHasScrollbar: (bodyHasScrollBar: boolean) => void;
- }
- class TableFoundation<RecordType> extends BaseFoundation<TableAdapter<RecordType>> {
- memoizedWithFnsColumns: (
- queries: BaseColumnProps<RecordType>[],
- cachedColumns: BaseColumnProps<RecordType>[],
- rowSelectionUpdate: boolean,
- hideExpandedColumn: boolean,
- bodyHasScrollBar: boolean,
- ) => BaseColumnProps<RecordType>[];
- memoizedFilterColumns: (columns: BaseColumnProps<RecordType>[], ignoreKeys?: string[]) => BaseColumnProps<RecordType>[];
- memoizedFlattenFnsColumns: (columns: BaseColumnProps<RecordType>[], childrenColumnName?: string) => BaseColumnProps<RecordType>[];
- memoizedPagination: (pagination: BasePagination) => BasePagination;
- constructor(adapter: TableAdapter<RecordType>) {
- super({ ...adapter });
- /**
- * memoized function list
- */
- const handleColumns: (queries: BaseColumnProps<RecordType>[], cachedColumns: BaseColumnProps<RecordType>[]) => BaseColumnProps<RecordType>[] = this._adapter.getHandleColumns();
- const mergePagination: (pagination: BasePagination) => BasePagination = this._adapter.getMergePagination();
- this.memoizedWithFnsColumns = memoizeOne(handleColumns, isEqual);
- this.memoizedFilterColumns = memoizeOne(filterColumns);
- this.memoizedFlattenFnsColumns = memoizeOne(flattenColumns);
- this.memoizedPagination = memoizeOne(mergePagination, isEqual);
- }
- init() {
- const dataSource = [...this.getProp('dataSource')];
- const { queries } = this._adapter.getStates();
- const filteredSortedDataSource = this.getFilteredSortedDataSource(dataSource, queries);
- const pageData = this.getCurrentPageData(filteredSortedDataSource);
- this.setAdapterPageData(pageData);
- this.initExpandedRowKeys(pageData);
- this.initSelectedRowKeys(pageData);
- // cache dataSource after mount, and then calculate it on demand
- this.setCachedFilteredSortedDataSource(filteredSortedDataSource);
- }
- initExpandedRowKeys({ groups }: { groups?: Map<string, RecordType[]> } = {}) {
- const {
- defaultExpandAllRows,
- defaultExpandedRowKeys = [],
- expandedRowKeys: propExpandedRowKeys = [],
- dataSource = [],
- expandAllRows,
- defaultExpandAllGroupRows,
- expandAllGroupRows,
- } = this.getProps();
- const expandedRowKeys: BaseRowKeyType[] = [];
- if (defaultExpandAllRows || expandAllRows) {
- this._addNoDuplicatedItemsToArr(
- expandedRowKeys,
- this.getAllRowKeys(dataSource),
- groups && isMap(groups) && groups.size ? Array.from(groups.keys()) : []
- );
- } else if (defaultExpandAllGroupRows || expandAllGroupRows) {
- this._addNoDuplicatedItemsToArr(
- expandedRowKeys,
- groups && isMap(groups) && groups.size ? Array.from(groups.keys()) : []
- );
- } else if (Array.isArray(defaultExpandedRowKeys) && defaultExpandedRowKeys.length) {
- this._addNoDuplicatedItemsToArr(expandedRowKeys, defaultExpandedRowKeys);
- } else if (Array.isArray(propExpandedRowKeys) && propExpandedRowKeys.length) {
- this._addNoDuplicatedItemsToArr(expandedRowKeys, propExpandedRowKeys);
- }
- this._adapter.setExpandedRowKeys(expandedRowKeys);
- }
- initSelectedRowKeys({ disabledRowKeys }: { disabledRowKeys?: BaseRowKeyType[] }) {
- const rowSelection = this.getProp('rowSelection');
- const rowKeys: BaseRowKeyType[] = [];
- if (rowSelection) {
- const selectedRowKeys = get(rowSelection, 'selectedRowKeys');
- const defaultSelectedRowKeys = get(rowSelection, 'defaultSelectedRowKeys');
- if (Array.isArray(selectedRowKeys)) {
- this._addNoDuplicatedItemsToArr(rowKeys, selectedRowKeys);
- } else if (Array.isArray(defaultSelectedRowKeys)) {
- this._addNoDuplicatedItemsToArr(rowKeys, defaultSelectedRowKeys);
- }
- if (Array.isArray(disabledRowKeys) && disabledRowKeys.length) {
- pull(rowKeys, ...disabledRowKeys);
- }
- this._adapter.setSelectedRowKeys(rowKeys);
- }
- }
- /**
- * Get filtered and sorted data
- * @param {Object[]} dataSource
- * @param {Object[]} queries
- * @returns {Object[]} sortedDataSource
- */
- getFilteredSortedDataSource(dataSource: RecordType[], queries: BaseColumnProps<RecordType>[]) {
- const filteredDataSource = this.filterDataSource(dataSource, queries.filter(
- query => {
- /**
- * 这里无需判断 filteredValue 是否为数组,初始化时它是 `undefined`,点击选择空时为 `[]`
- * 初始化时我们应该用 `defaultFilteredValue`,点击后我们应该用 `filteredValue`
- *
- * There is no need to judge whether `filteredValue` is an array here, because it is `undefined` when initialized, and `[]` when you click to select empty
- * When initializing we should use `defaultFilteredValue`, after clicking we should use `filteredValue`
- */
- const currentFilteredValue = query.filteredValue ? query.filteredValue : query.defaultFilteredValue;
- return (
- isFunction(query.onFilter) &&
- Array.isArray(query.filters) &&
- query.filters.length &&
- Array.isArray(currentFilteredValue) &&
- currentFilteredValue.length
- );
- }
- ));
- const sortedDataSource = this.sortDataSource(filteredDataSource, queries.filter(query => query && isFunction(query.sorter)));
- return sortedDataSource;
- }
- /**
- * get current page data
- *
- * @param {Array} dataSource
- * @param {object} pagination
- * @param {object} queries
- * @returns {{dataSource: RecordType[], groups: Map<string, Set<string>>, pagination: object, disabledRowKeys: string[], queries: BaseColumnProps[], allRowKeys: string[]}}
- */
- getCurrentPageData(dataSource?: RecordType[], pagination?: BasePagination, queries?: BaseColumnProps<RecordType>[]) {
- const filteredSortedDataSource = this._adapter.getCachedFilteredSortedDataSource();
- dataSource = dataSource == null ? [...filteredSortedDataSource] : dataSource;
- pagination =
- pagination == null ? this.getState('pagination') && { ...this.getState('pagination') } : pagination;
- queries = queries == null ? [...this.getState('queries')] : queries;
- let groups;
- if (this.getProp('groupBy') != null) {
- const { groups: groupedGroups, dataSource: groupedData } = this.groupDataSource(dataSource);
- dataSource = groupedData;
- groups = groupedGroups;
- }
- pagination = this.normalizePagination(pagination, dataSource);
- dataSource = this.limitPageDataSource(dataSource, pagination);
- const disabledRowKeys = this.getAllDisabledRowKeys(dataSource);
- const allRowKeys = this.getAllRowKeys(dataSource);
- const pageData: BasePageData<RecordType> = {
- dataSource,
- groups,
- pagination,
- disabledRowKeys,
- allRowKeys,
- queries,
- };
- return pageData;
- }
- /**
- * group dataSource, return grouped row keys
- *
- * @param {*[]} dataSource
- * @param {Function|string} groupBy
- */
- groupDataSource(dataSource: RecordType[], groupBy?: BaseGroupBy<RecordType>) {
- groupBy = groupBy == null ? this.getProp('groupBy') : groupBy;
- const groups = new Map();
- const newDataSource = [];
- if (groupBy != null) {
- each(dataSource, (record, index) => {
- const groupKey = typeof groupBy === 'function' ? groupBy(record) : get(record, groupBy);
- if (groupKey != null && groupKey !== '') {
- const recordKey = this.getRecordKey(record);
- let group = groups.get(groupKey);
- if (!isSet(group)) {
- group = new Set([recordKey]);
- groups.set(groupKey, group);
- } else {
- group.add(recordKey);
- }
- }
- });
- }
- if (groups && groups.size) {
- groups.forEach((set, key) => {
- if (isSet(set)) {
- set.forEach(realKey => {
- newDataSource.push(this._getRecord(realKey));
- });
- }
- });
- } else {
- newDataSource.push(...dataSource);
- }
- return { groups, dataSource: newDataSource };
- }
- /**
- * sort data
- *
- * @param {Array} dataSource
- * @param {Array} sorters
- * @returns {Array}
- */
- sortDataSource(dataSource: RecordType[], sorters: BaseSorterInfo<RecordType>[]) {
- each(sorters, sorterObj => {
- // const sorterObj = last(sorters) || {};
- const { sorter, sortOrder, defaultSortOrder, sortChildrenRecord } = sorterObj;
- const currentSortOrder = this.isSortOrderValid(sortOrder) ? sortOrder : defaultSortOrder;
- if (isFunction(sorter) && (currentSortOrder && strings.SORT_DIRECTIONS.includes(currentSortOrder))) {
- if (sortChildrenRecord) {
- const childrenRecordName = this.getProp('childrenRecordName');
- dataSource =
- dataSource &&
- dataSource.map(record => {
- const children = this._getRecordChildren(record);
- if (Array.isArray(children) && children.length) {
- return {
- ...record,
- [childrenRecordName]: this.sortDataSource(children, [sorterObj]),
- };
- }
- return record;
- });
- }
- dataSource.sort(withOrderSort(sorter, currentSortOrder));
- return false;
- }
- return undefined;
- });
- return dataSource;
- }
- /**
- * set page number
- */
- setPage = (currentPage: number, currentPageSize: number) => {
- currentPage = currentPage || this._adapter.getCurrentPage();
- const currentPagination = this.getState('pagination');
- const { dataSource, pagination, disabledRowKeys, allRowKeys } = this.getCurrentPageData(null, {
- ...currentPagination,
- currentPage,
- pageSize: currentPageSize,
- });
- if (!this._pagerIsControlled() && currentPage > 0) {
- this._adapter.setDisabledRowKeys(disabledRowKeys);
- this._adapter.setAllRowKeys(allRowKeys);
- this._adapter.setPagination(pagination);
- this._adapter.setDataSource(dataSource);
- }
- this._notifyChange(pagination);
- };
- /**
- * filter data source
- *
- * @param {*[]} dataSource
- * @param {*[]} filters
- * @returns {*[]}
- */
- filterDataSource(dataSource: RecordType[], filters: BaseChangeInfoFilter<RecordType>[]) {
- let filteredData: Map<string, RecordType> | null = null;
- let hasValidFilters = false;
- const childrenRecordName = this.getProp('childrenRecordName');
- each(filters, filterObj => {
- const { onFilter, filteredValue, filterChildrenRecord, defaultFilteredValue } = filterObj;
- const currentFilteredValue = Array.isArray(filteredValue) ? filteredValue : defaultFilteredValue;
- if (typeof onFilter === 'function' && Array.isArray(currentFilteredValue) && currentFilteredValue.length) {
- hasValidFilters = true;
- if (filteredData === null) {
- filteredData = new Map();
- } else {
- dataSource = Array.from(filteredData && filteredData.values());
- filteredData = new Map();
- }
- each(currentFilteredValue, value => {
- each(dataSource, record => {
- const childrenRecords = get(record, childrenRecordName);
- const recordKey = this.getRecordKey(record);
- let filteredChildren;
- if (Array.isArray(childrenRecords) && childrenRecords.length && filterChildrenRecord) {
- filteredChildren = this.filterDataSource(childrenRecords, [filterObj]);
- }
- if (Array.isArray(filteredChildren) && filteredChildren.length) {
- if (recordKey != null) {
- const children = get(filteredData.get(recordKey), childrenRecordName, []);
- filteredData.set(recordKey, {
- ...record,
- [childrenRecordName]: filteredChildren.reduce(
- (arr, cur) => {
- if (
- arr.find((item: any) => this.getRecordKey(item) === this.getRecordKey(cur)) ==
- null
- ) {
- arr.push(cur);
- }
- return arr;
- },
- [...children]
- ),
- });
- }
- } else if (onFilter(value, record)) {
- filteredData.set(recordKey, record);
- }
- });
- });
- }
- });
- if (hasValidFilters) {
- dataSource = Array.from(filteredData && filteredData.values());
- }
- return dataSource;
- }
- limitPageDataSource(dataSource: RecordType[], pagination: BasePagination) {
- dataSource = dataSource == null ? this.getProp('dataSource') : dataSource;
- pagination = pagination == null ? this.getState('pagination') : pagination;
- let pageData = dataSource;
- const pageNo = get(pagination, 'currentPage');
- if (this.getProp('pagination') !== false && pageNo && dataSource && pagination && !this._pagerIsControlled()) {
- const { pageSize = numbers.DEFAULT_PAGE_SIZE } = pagination;
- const start = (pageNo - 1) * pageSize;
- const end = pageNo * pageSize;
- pageData = slice(dataSource, start, end);
- }
- return pageData;
- }
- normalizePagination(pagination: BasePagination, dataSource: RecordType[]) {
- pagination = pagination == null ? this._getPagination() : pagination;
- dataSource = dataSource == null ? this._getDataSource() : dataSource;
- const propPagination = this.getProp('pagination');
- if (pagination) {
- pagination = typeof pagination === 'object' ? { ...pagination } : {};
- pagination = merge(
- {
- total: (dataSource && dataSource.length) || 0,
- pageSize: numbers.DEFAULT_PAGE_SIZE,
- currentPage: get(propPagination, 'defaultCurrentPage', 1),
- position: strings.PAGINATION_POSITIONS[0],
- },
- pagination
- );
- if (!this._pagerIsControlled()) {
- const total = get(propPagination, 'total', dataSource.length);
- const pageSize = get(propPagination, 'pageSize', pagination.pageSize);
- const { currentPage } = pagination;
- const realTotalPage = Math.ceil(total / pageSize);
- pagination.total = total;
- if (currentPage > realTotalPage) {
- pagination.currentPage = 1;
- }
- }
- }
- return pagination;
- }
- setAdapterPageData(pageData: BasePageData<RecordType> = {}) {
- const { pagination, dataSource, disabledRowKeys, allRowKeys, groups } = pageData;
- this._adapter.setDisabledRowKeys(disabledRowKeys);
- this._adapter.setAllRowKeys(allRowKeys);
- this._adapter.setPagination(pagination);
- this._adapter.setGroups(groups);
- this._adapter.setDataSource(dataSource);
- }
- /**
- * Cache related data when initializing or updating the calculated dataSource
- * @param {*} filteredSortedDataSource
- */
- setCachedFilteredSortedDataSource = (filteredSortedDataSource: RecordType[]) => {
- this._adapter.setCachedFilteredSortedDataSource(filteredSortedDataSource);
- const filteredSortedRowKeys = this.getAllRowKeys(filteredSortedDataSource);
- this._adapter.setCachedFilteredSortedRowKeys(filteredSortedRowKeys);
- };
- destroy() { }
- handleClick(e: any) { }
- handleMouseEnter(e: any) { }
- handleMouseLeave(e: any) { }
- stopPropagation(e: any) {
- if (e && typeof e === 'object') {
- if (typeof e.stopPropagation === 'function') {
- e.stopPropagation();
- }
- if (e.nativeEvent && typeof e.nativeEvent.stopPropagation === 'function') {
- e.nativeEvent.stopPropagation();
- } else if (typeof e.stopImmediatePropagation === 'function') {
- e.stopImmediatePropagation();
- }
- }
- }
- /**
- * Add non-repeating elements to the array itself
- * @param {Array} srcArr
- * @param {Object} objArrs
- */
- _addNoDuplicatedItemsToArr(srcArr: any[] = [], ...objArrs: any[]) {
- for (const objArr of objArrs) {
- if (Array.isArray(objArr)) {
- for (const item of objArr) {
- if (!srcArr.includes(item)) {
- srcArr.push(item);
- }
- }
- }
- }
- return srcArr;
- }
- _notifyChange(pagination: BasePagination, filters?: BaseChangeInfoFilter<RecordType>[], sorter?: BaseChangeInfoSorter<RecordType>, extra?: RecordType) {
- pagination = pagination == null ? this._getPagination() : pagination;
- filters = filters == null ? this._getAllFilters() : filters;
- sorter = sorter == null ? this._getAllSorters()[0] as BaseChangeInfoSorter<RecordType> : sorter;
- if (get(this.getProp('scroll'), 'scrollToFirstRowOnChange')) {
- this._adapter.resetScrollY();
- }
- this._adapter.notifyChange({
- pagination: { ...pagination },
- filters: [...filters],
- sorter,
- extra: { ...extra },
- });
- }
- _rowExpansionIsControlled() {
- return Array.isArray(this.getProp('expandedRowKeys'));
- }
- _pagerIsControlled() {
- return get(this.getProp('pagination'), 'currentPage') != null;
- }
- _selectionIsControlled() {
- return Array.isArray(get(this.getProp('rowSelection'), 'selectedRowKeys'));
- }
- /**
- * Determine whether the column sorting is controlled
- * Controlled: the column passed the sortOrder prop
- * @param {String} dataIndex
- * @returns {Boolean}
- */
- _sorterIsControlled(dataIndex: string) {
- // The basis for judgment should be props columns instead of cachedColumns fix#1141
- const query = dataIndex && this.getQuery(dataIndex, this.getState('flattenColumns'));
- return Boolean(query && query.sortOrder != null);
- }
- /**
- * Determine whether the column is filtered and controlled
- * Controlled: the column passed the filteredValue prop
- * @param {String} dataIndex
- * @returns {Boolean}
- */
- _filterIsControlled(dataIndex: string) {
- const query = dataIndex && this.getQuery(dataIndex, this.getState('flattenColumns'));
- return Boolean(query && Array.isArray(query.filteredValue));
- }
- _filterShowIsControlled(dataIndex?: string) {
- const query = dataIndex && this.getQuery(dataIndex, this.getState('flattenColumns'));
- return Boolean(query && (query.filterDropdownVisible === true || query.filterDropdownVisible === false));
- }
- _getSelectedRowKeys() {
- const rowSelection = this.getState('rowSelection');
- const selectedRowKeys = get(rowSelection, 'selectedRowKeys', []);
- return [...selectedRowKeys];
- }
- _getSelectedRowKeysSet() {
- const rowSelection = this.getState('rowSelection');
- const selectedRowKeysSet = get(rowSelection, 'selectedRowKeysSet', new Set());
- return selectedRowKeysSet;
- }
- _getDataSource() {
- return this.getProp('dataSource') || [];
- }
- _getRecord(realKey: string | number) {
- return find(
- this.getProp('dataSource'),
- record => realKey != null && realKey !== '' && this.getRecordKey(record) === realKey
- );
- }
- _getRecordChildren(record: RecordType) {
- return get(record, this.getProp('childrenRecordName'));
- }
- _getPagination() {
- return this.getState('pagination') || {};
- }
- _getAllFilters(queries?: BaseColumnProps<RecordType>[]) {
- queries = queries || this.getState('queries');
- const filters: BaseChangeInfoFilter<RecordType>[] = [];
- each(queries, query => {
- if (
- Array.isArray(query.filteredValue) &&
- (query.filteredValue.length || this._filterIsControlled(query.dataIndex))
- ) {
- filters.push(query);
- }
- });
- return filters;
- }
- _getAllSorters(queries?: BaseColumnProps<RecordType>[]): BaseColumnProps<RecordType>[] {
- queries = queries || this.getState('queries');
- return filter(queries, query => query.sorter && query.sortOrder) as BaseColumnProps<RecordType>[];
- }
- _filterQueries(targetQuery: BaseColumnProps<RecordType>, queries: BaseColumnProps<RecordType>[], keys = ['dataIndex']) {
- queries = queries == null ? this.getState('queries') : queries;
- const filteredQueries: BaseColumnProps<RecordType>[] = [];
- const filteredIndexes: number[] = [];
- each(queries, (itQuery, index) => {
- const flag = some(keys, k => k && targetQuery[k] != null && targetQuery[k] === itQuery[k]);
- if (flag) {
- filteredQueries.push(itQuery);
- filteredIndexes.push(index);
- }
- });
- return { filteredQueries, filteredIndexes };
- }
- _mergeToQueries(query: BaseColumnProps<RecordType>, queries: BaseColumnProps<RecordType>[], keys = ['dataIndex']) {
- queries = queries == null ? this.getState('queries') : queries;
- queries = [...queries];
- query = { ...query };
- const { filteredQueries, filteredIndexes } = this._filterQueries(query, queries, keys);
- each(filteredQueries, (curQuery, idx) => {
- // assign(curQuery, query);
- queries[filteredIndexes[idx]] = { ...query };
- });
- return queries;
- }
- /**
- * get record real key
- * @param {RecordType} record
- * @returns {string}
- */
- getRecordKey(record: RecordType): string {
- if (!record) {
- return undefined;
- }
- const rowKey = this.getProp('rowKey');
- return typeof rowKey === 'function' ? rowKey(record) : get(record, rowKey);
- }
- isEmpty(dataSource: RecordType[]) {
- dataSource = dataSource == null ? this.getProp('dataSource') : dataSource;
- return !(Array.isArray(dataSource) && dataSource.length > 0);
- }
- handleSelectRow(realKey: BaseRowKeyType, selected: boolean, e: any) {
- this.stopPropagation(e);
- if (typeof selected === 'boolean' && realKey != null) {
- const selectedRowKeys = this._getSelectedRowKeys();
- let foundIdx = -1;
- const selectedRow = this.getSelectedRows(null, [realKey])[0];
- let selectedRows: BaseIncludeGroupRecord<RecordType>[];
- if ((foundIdx = selectedRowKeys.indexOf(realKey)) > -1 && selected === false) {
- selectedRowKeys.splice(foundIdx, 1);
- selectedRows = this.getSelectedRows(null, selectedRowKeys);
- if (!this._selectionIsControlled()) {
- this._adapter.setSelectedRowKeys(selectedRowKeys);
- }
- this._adapter.notifySelect(selectedRow, selected, selectedRows, e);
- this._adapter.notifySelectionChange(selectedRowKeys, selectedRows);
- } else if (selectedRowKeys.indexOf(realKey) === -1 && selected === true) {
- selectedRowKeys.push(realKey);
- selectedRows = this.getSelectedRows(null, selectedRowKeys);
- if (!this._selectionIsControlled()) {
- this._adapter.setSelectedRowKeys(selectedRowKeys);
- }
- this._adapter.notifySelect(selectedRow, selected, selectedRows, e);
- this._adapter.notifySelectionChange(selectedRowKeys, selectedRows);
- }
- }
- }
- /**
- * select all rows
- * @param {*} selected The future state of the select all button
- * @param {*} e
- */
- handleSelectAllRow(selected: boolean, e: any) {
- this.stopPropagation(e);
- if (typeof selected === 'boolean') {
- const curSelectedRowKeys = this._getSelectedRowKeys();
- let selectedRowKeys = [...curSelectedRowKeys];
- const selectedRowKeysSet = this._getSelectedRowKeysSet();
- let allRowKeys = [...this._adapter.getCachedFilteredSortedRowKeys()];
- const disabledRowKeys = this.getAllDisabledRowKeys();
- const disabledRowKeysSet = new Set(disabledRowKeys);
- let changedRowKeys;
- // Select all, if not disabled && not in selectedRowKeys
- if (selected) {
- for (const key of allRowKeys) {
- if (!disabledRowKeysSet.has(key) && !selectedRowKeysSet.has(key)) {
- selectedRowKeys.push(key);
- }
- }
- allRowKeys = pullAll(allRowKeys, [...disabledRowKeys, ...curSelectedRowKeys]);
- changedRowKeys = [...allRowKeys];
- } else {
- selectedRowKeys = pullAll(selectedRowKeys, allRowKeys);
- changedRowKeys = [...curSelectedRowKeys];
- }
- const changedRows = this.getSelectedRows(null, changedRowKeys || []);
- const selectedRows = this.getSelectedRows(null, selectedRowKeys || []);
- if (!this._selectionIsControlled()) {
- this._adapter.setSelectedRowKeys(selectedRowKeys);
- }
- this._adapter.notifySelectAll(selected, selectedRows, changedRows, e);
- this._adapter.notifySelectionChange(selectedRowKeys, selectedRows);
- }
- }
- /**
- * row keys => rows
- * @param {*} dataSource
- * @param {*} selectedRowKeys
- * @param {*} selectedRowKeysSet Recursive optimization
- */
- getSelectedRows(dataSource: RecordType[], selectedRowKeys: BaseRowKeyType[], selectedRowKeysSet?: Set<BaseRowKeyType>): BaseIncludeGroupRecord<RecordType>[] {
- dataSource = dataSource == null ? this._getDataSource() : dataSource;
- selectedRowKeys = selectedRowKeys == null ? this._getSelectedRowKeys() : selectedRowKeys;
- if (!isSet(selectedRowKeysSet)) {
- selectedRowKeysSet = new Set(selectedRowKeys);
- }
- const childrenRecordName = this.getProp('childrenRecordName');
- const selectedRows: BaseIncludeGroupRecord<RecordType>[] = [];
- if (
- isSet(selectedRowKeysSet) &&
- selectedRowKeysSet.size &&
- Array.isArray(dataSource) &&
- dataSource.length
- ) {
- // Time complexity optimization, replace the includes operation of array with has of set
- selectedRows.push(...dataSource.filter(data => selectedRowKeysSet.has(this.getRecordKey(data))));
- if (selectedRows.length < selectedRowKeys.length) {
- for (const item of dataSource) {
- const children = get(item, childrenRecordName);
- if (Array.isArray(children) && children.length) {
- const rows = this.getSelectedRows(children, selectedRowKeys, selectedRowKeysSet);
- selectedRows.push(...rows);
- }
- }
- }
- }
- return selectedRows;
- }
- getAllDisabledRowKeys(dataSource?: RecordType[], getCheckboxProps?: GetCheckboxProps<RecordType>): BaseRowKeyType[] {
- dataSource = dataSource == null ? this._getDataSource() : dataSource;
- getCheckboxProps =
- getCheckboxProps == null ? get(this.getProp('rowSelection'), 'getCheckboxProps') : getCheckboxProps;
- const childrenRecordName = this.getProp('childrenRecordName');
- const disabledRowKeys: BaseRowKeyType[] = [];
- if (Array.isArray(dataSource) && dataSource.length && typeof getCheckboxProps === 'function') {
- for (const record of dataSource) {
- const props = getCheckboxProps(record);
- if (props && props.disabled) {
- disabledRowKeys.push(this.getRecordKey(record));
- }
- const children = get(record, childrenRecordName);
- if (Array.isArray(children) && children.length) {
- const keys: BaseRowKeyType[] = this.getAllDisabledRowKeys(children, getCheckboxProps);
- disabledRowKeys.push(...keys);
- }
- }
- }
- return disabledRowKeys;
- }
- getAllRowKeys(dataSource: RecordType[]): BaseRowKeyType[] {
- dataSource = dataSource == null ? this._getDataSource() : dataSource;
- const childrenRecordName = this.getProp('childrenRecordName');
- const allRowKeys = [];
- if (Array.isArray(dataSource) && dataSource.length) {
- for (const record of dataSource) {
- const childrenRowKeys = [];
- const children = get(record, childrenRecordName);
- if (Array.isArray(children) && children.length) {
- childrenRowKeys.push(...this.getAllRowKeys(children));
- }
- allRowKeys.push(this.getRecordKey(record), ...childrenRowKeys);
- }
- }
- return allRowKeys;
- }
- /**
- * Check if the selected item is in allRowKeysSet
- * @param {Array} selectedRowKeys
- * @param {Set} allRowKeysSet
- */
- hasRowSelected(selectedRowKeys: BaseRowKeyType[], allRowKeysSet: Set<BaseRowKeyType>) {
- return Boolean(Array.isArray(selectedRowKeys) &&
- selectedRowKeys.length &&
- isSet(allRowKeysSet) &&
- allRowKeysSet.size &&
- selectedRowKeys.filter(key => allRowKeysSet.has(key)).length);
- }
- /**
- * expand processing function
- * @param {Boolean} expanded
- * @param {String} realKey
- * @param {Event} domEvent
- */
- handleRowExpanded(expanded: boolean, realKey: string, domEvent: any) {
- this.stopPropagation(domEvent);
- const expandedRowKeys = [...this.getState('expandedRowKeys')];
- const index = expandedRowKeys.indexOf(realKey);
- const keyIsValid = typeof realKey === 'string' || typeof realKey === 'number';
- if (keyIsValid && expanded && index === -1) {
- expandedRowKeys.push(realKey);
- } else if (keyIsValid && !expanded && index > -1) {
- expandedRowKeys.splice(index, 1);
- }
- if (!this._rowExpansionIsControlled()) {
- this._adapter.setExpandedRowKeys(expandedRowKeys);
- }
- const expandedRows = this.getSelectedRows(null, expandedRowKeys);
- let expandedRow = this.getSelectedRows(null, [realKey])[0];
- // groups record processing
- const groups = this._getGroups();
- if (groups) {
- // Construct group expandRow
- if (groups.has(realKey)) {
- expandedRow = { groupKey: realKey };
- }
- // If expandedRowKeys includes groupKey, add to expandedRows
- for (let i = 0, len = expandedRowKeys.length; i < len; i++) {
- if (groups.has(realKey)) {
- expandedRows.push({ groupKey: expandedRowKeys[i] });
- }
- }
- }
- this._adapter.notifyExpand(expanded, expandedRow, domEvent);
- this._adapter.notifyExpandedRowsChange(expandedRows);
- }
- /**
- * get state.groups
- * @returns {Map|Null}
- */
- _getGroups() {
- const groupBy = this._adapter.getProp('groupBy');
- if (groupBy !== null) {
- const groups = this._adapter.getState('groups');
- return groups;
- }
- return null;
- }
- /**
- * Determine whether you have selected all except for disabled
- * @param {Set} selectedRowKeysSet
- * @param {Set} disabledRowKeysSet
- * @param {Array} allKeys keys after sorted and filtered
- */
- allIsSelected(selectedRowKeysSet: Set<BaseRowKeyType>, disabledRowKeysSet: Set<BaseRowKeyType>, allKeys: BaseRowKeyType[]) {
- const filteredAllKeys = filter(allKeys, key => key != null && !disabledRowKeysSet.has(key));
- if (filteredAllKeys && filteredAllKeys.length) {
- for (const key of filteredAllKeys) {
- if (key != null && !selectedRowKeysSet.has(key)) {
- return false;
- }
- }
- return true;
- } else {
- return false;
- }
- }
- /**
- * This function is not used yet
- * @param {*} selectedRowKeys
- * @param {*} allKeys
- */
- allIsNotSelected(selectedRowKeys: BaseRowKeyType[], allKeys: BaseRowKeyType[]) {
- for (const key of allKeys) {
- if (key != null && Array.isArray(selectedRowKeys) && selectedRowKeys.includes(key)) {
- return true;
- }
- }
- return false;
- }
- formatPaginationInfo(pagination: BasePagination = {}, defaultPageText = '') {
- let info = '';
- const formatPageText = get(this.getProp('pagination'), 'formatPageText');
- const { total, pageSize, currentPage } = pagination;
- const currentStart = Math.min((currentPage - 1) * pageSize + 1, total);
- const currentEnd = Math.min(currentPage * pageSize, total);
- if (formatPageText || (formatPageText !== false && defaultPageText && total > 0)) {
- info =
- typeof formatPageText === 'function' ?
- formatPageText({ currentStart, currentEnd, total }) :
- defaultPageText
- .replace('${currentStart}', currentStart as any)
- .replace('${currentEnd}', currentEnd as any)
- .replace('${total}', total as any);
- }
- return info;
- }
- toggleShowFilter(dataIndex: string, visible: boolean) {
- let filterObj: BaseColumnProps<RecordType> = this.getQuery(dataIndex);
- const filterDropdownVisible = visible;
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- filterObj = { ...filterObj, filterDropdownVisible };
- if (!this._filterShowIsControlled()) {
- // this._adapter.setQuery({
- // ...filterObj,
- // filterDropdownVisible,
- // });
- }
- this._adapter.notifyFilterDropdownVisibleChange(filterDropdownVisible, dataIndex);
- }
- /**
- * Called when the filter changes
- * @param {*} dataIndex
- * @param {*} data
- */
- handleFilterSelect(dataIndex: string, data: { filteredValue?: string[] } = {}) {
- let query: BaseColumnProps<RecordType> = this.getQuery(dataIndex);
- let queries = [...this._adapter.getState('queries')];
- const { filteredValue } = data;
- query = {
- ...query,
- filteredValue,
- };
- queries = mergeQueries(query, queries);
- const mergedQueries = this._mergeToQueries(query, null);
- const filters = this._getAllFilters(mergedQueries);
- if (!this._filterIsControlled(dataIndex)) {
- this._adapter.setQueries(queries);
- this.handleClickFilterOrSorter(queries);
- }
- this._notifyChange(null, filters);
- }
- /**
- * Click the sort button to call
- * @param {*} column
- * @param {*} e
- */
- handleSort(column: { dataIndex?: string; sortOrder?: BaseSortOrder } = {}, e: any) {
- this.stopPropagation(e);
- const { dataIndex } = column;
- let queries = this.getState('queries');
- let curQuery = null;
- queries = [...queries];
- each(queries, (query, idx, arr) => {
- if (query.sorter) {
- const sorterObj = { ...query };
- const stateSortOrder = get(sorterObj, 'sortOrder');
- const defaultSortOrder = get(sorterObj, 'defaultSortOrder', false);
- let querySortOrder = this.isSortOrderValid(stateSortOrder) ? stateSortOrder : defaultSortOrder;
- if (dataIndex && dataIndex === sorterObj.dataIndex) {
- if (querySortOrder === strings.SORT_DIRECTIONS[0]) {
- querySortOrder = strings.SORT_DIRECTIONS[1];
- } else if (querySortOrder === strings.SORT_DIRECTIONS[1]) {
- querySortOrder = false;
- } else {
- querySortOrder = strings.SORT_DIRECTIONS[0];
- }
- } else {
- // This results in the current click only supports single column sorting
- querySortOrder = false;
- }
- arr[idx] = { ...sorterObj, sortOrder: querySortOrder };
- if (dataIndex === sorterObj.dataIndex) {
- curQuery = arr[idx];
- }
- }
- });
- if (!this._sorterIsControlled(dataIndex)) {
- this._adapter.setQueries(queries);
- this.handleClickFilterOrSorter(queries);
- }
- // notify sort event
- this._notifyChange(null, null, curQuery, null);
- }
- /**
- * Recalculate the cached data after clicking filter or sorter
- * @param {*} queries
- */
- handleClickFilterOrSorter(queries: BaseColumnProps<RecordType>[]) {
- const dataSource = [...this.getProp('dataSource')];
- const sortedDataSource = this.getFilteredSortedDataSource(dataSource, queries);
- this.setCachedFilteredSortedDataSource(sortedDataSource);
- const pageData = this.getCurrentPageData(sortedDataSource);
- this.setAdapterPageData(pageData);
- }
- getQuery(dataIndex: string, queries?: BaseColumnProps<RecordType>[]) {
- queries = queries || this.getState('queries');
- if (dataIndex != null) {
- return find(queries, query => query.dataIndex === dataIndex);
- }
- return undefined;
- }
- getCellWidths(flattenedColumns: BaseColumnProps<RecordType>[], flattenedWidths?: BaseHeadWidth[], ignoreScrollBarKey?: boolean) {
- return this._adapter.getCellWidths(flattenedColumns, flattenedWidths, ignoreScrollBarKey);
- }
- setHeadWidths(headWidths: Array<BaseHeadWidth>, index?: number) {
- return this._adapter.setHeadWidths(headWidths, index);
- }
- getHeadWidths(index: number) {
- return this._adapter.getHeadWidths(index);
- }
- mergedRowExpandable(record: RecordType) {
- return this._adapter.mergedRowExpandable(record);
- }
- setBodyHasScrollbar(bodyHasScrollbar: boolean) {
- this._adapter.setBodyHasScrollbar(bodyHasScrollbar);
- }
- isSortOrderValid = (sortOrder: BaseSortOrder) => strings.SORT_DIRECTIONS.includes(sortOrder as any) || sortOrder === false;
- }
- export type BaseRowKeyType = string | number;
- export interface BasePagination {
- total?: number;
- currentPage?: number;
- pageSize?: number;
- position?: ArrayElement<typeof strings.PAGINATION_POSITIONS>;
- defaultCurrentPage?: number;
- formatPageText?: any;
- }
- export interface BaseHeadWidth {
- width: number;
- key: string;
- }
- export interface BasePageData<RecordType> {
- dataSource?: RecordType[];
- groups?: Map<string, RecordType[]>;
- pagination?: BasePagination;
- disabledRowKeys?: BaseRowKeyType[];
- allRowKeys?: BaseRowKeyType[];
- queries?: BaseColumnProps<RecordType>[];
- }
- export type GetCheckboxProps<RecordType> = (record?: RecordType) => BaseCheckboxProps;
- export type BaseGroupBy<RecordType> = string | number | BaseGroupByFn<RecordType>;
- export type BaseGroupByFn<RecordType> = (record?: RecordType) => string | number;
- export interface BaseSorterInfo<RecordType> {
- [x: string]: any;
- dataIndex?: string;
- sortOrder?: BaseSortOrder;
- sorter?: BaseSorter<RecordType>;
- }
- export type BaseSortOrder = boolean | ArrayElement<typeof strings.SORT_DIRECTIONS>;
- export type BaseSorter<RecordType> = boolean | ((a?: RecordType, b?: RecordType) => number);
- export interface BaseChangeInfoFilter<RecordType> {
- dataIndex?: string;
- value?: any;
- text?: any;
- filters?: BaseFilter[];
- onFilter?: (filteredValue?: any, record?: RecordType) => boolean;
- filteredValue?: any[];
- defaultFilteredValue?: any[];
- children?: BaseFilter[];
- filterChildrenRecord?: boolean;
- }
- export interface BaseFilter {
- value?: any;
- text?: any;
- children?: BaseFilter[];
- }
- export type BaseFixed = ArrayElement<typeof strings.FIXED_SET>;
- export type BaseAlign = ArrayElement<typeof strings.ALIGNS>;
- export type BaseOnCell<RecordType> = (record?: RecordType, rowIndex?: number) => BaseOnCellReturnObject;
- export interface BaseOnCellReturnObject {
- [x: string]: any;
- style?: Record<string, any>;
- className?: string;
- onClick?: (e: any) => void;
- }
- export type BaseOnFilter<RecordType> = (filteredValue?: any, record?: RecordType) => boolean;
- export type BaseOnFilterDropdownVisibleChange = (visible?: boolean) => void;
- export type BaseOnHeaderCell<RecordType> = (record?: RecordType, columnIndex?: number) => BaseOnHeaderCellReturnObject;
- export interface BaseOnHeaderCellReturnObject {
- [x: string]: any;
- style?: Record<string, any>;
- className?: string;
- onClick?: (e: any) => void;
- }
- export interface BaseChangeInfoSorter<RecordType> {
- [x: string]: any;
- dataIndex: string;
- sortOrder: BaseSortOrder;
- sorter: BaseSorter<RecordType>;
- }
- export type BaseIncludeGroupRecord<RecordType> = RecordType | { groupKey: string };
- export default TableFoundation;
|