/* eslint-disable max-len */ /* eslint-disable no-param-reassign */ /* eslint-disable eqeqeq */ import { cloneDeepWith, isEqualWith, get, filter, find, map, clone as lodashClone, each, findIndex, some, includes, toString } from 'lodash-es'; import { strings, numbers } from './constants'; import isNullOrUndefined from '../utils/isNullOrUndefined'; export function cloneDeep(value: any, customizer?: (v: any) => any) { return cloneDeepWith(value, v => { if (typeof v === 'function') { return v; } else if (typeof customizer === 'function') { return customizer(v); } return undefined; }); } export function equalWith(value: any, other: any, customizer?: (...args: any[]) => boolean) { return isEqualWith(value, other, (objVal, othVal, ...rest) => { if (typeof objVal === 'function' && typeof othVal === 'function') { return toString(objVal) === toString(othVal); } if (typeof customizer === 'function') { return customizer(objVal, othVal, ...rest); } // If customizer returns undefined, comparisons are handled by isEqual instead return undefined; }); } export function getColumnKey(column: any, keyPropNames: any[]): any { keyPropNames = Array.isArray(keyPropNames) ? keyPropNames : ['key', 'dataIndex']; let key = null; each(keyPropNames, propName => { key = get(column, propName); if (key != null) { return false; } return undefined; }); return key; } export function mergeColumns(oldColumns: any[] = [], newColumns: any[] = [], keyPropNames: any[] = null, deep = true) { const finalColumns: any[] = []; const clone = deep ? cloneDeep : lodashClone; map(newColumns, newColumn => { newColumn = { ...newColumn }; const key = getColumnKey(newColumn, keyPropNames); const oldColumn = key != null && find(oldColumns, item => getColumnKey(item, keyPropNames) === key); if (oldColumn) { finalColumns.push( clone({ ...oldColumn, ...newColumn, }) ); } else { finalColumns.push(clone(newColumn)); } }); return finalColumns; } /** * * @param {Array} arr * @param {number} [beginIndex] begin index, included * @param {number} [endIndex] end index, not included * @returns {number} */ export function arrayAdd(arr: any[] = [], beginIndex = 0, endIndex?: number) { beginIndex = beginIndex < 0 || typeof beginIndex !== 'number' ? 0 : beginIndex; endIndex = endIndex > arr.length || typeof endIndex !== 'number' ? arr.length : endIndex; let result = 0; each(arr, (value, index) => { if (index >= beginIndex && index < endIndex) { result += typeof value === 'number' && !isNaN(value) ? value : 0; } }); return result; } export function isLastLeftFixed(columns: Record[], column: Record, checkKeys = ['key']) { const leftFixedColumns = filter(columns, col => col.fixed === true || col.fixed === 'left'); const index = findIndex(leftFixedColumns, col => checkKeys.every(key => col[key] != null && col[key] === column[key]) ); return leftFixedColumns.length > 0 && index === leftFixedColumns.length - 1; } export function isFirstFixedRight(columns: Record[], column: Record, checkKeys = ['key']) { const rightFixedColumns = filter(columns, col => col.fixed === 'right'); const index = findIndex(rightFixedColumns, col => checkKeys.every(key => col[key] != null && col[key] === column[key]) ); return rightFixedColumns.length > 0 && index === 0; } export function isAnyFixed(columns: Record[], fixedSet = ['left', true, 'right']) { if (typeof fixedSet === 'string' || typeof fixedSet === 'boolean') { fixedSet = [fixedSet]; } return fixedSet.length > 0 && some(columns, col => fixedSet.includes(col.fixed)); } export function isAnyFixedRight(columns: Record[]) { return some(columns, col => col.fixed === 'right'); } export function isFixedLeft(column: Record) { return ['left', true].includes(get(column, 'fixed')); } export function isFixedRight(column: Record) { return ['right'].includes(get(column, 'fixed')); } export function isFixed(column: Record) { return isFixedLeft(column) || isFixedRight(column); } export function isInnerColumnKey(key: string | number) { return [ strings.DEFAULT_KEY_COLUMN_EXPAND, strings.DEFAULT_KEY_COLUMN_SCROLLBAR, strings.DEFAULT_KEY_COLUMN_SELECTION, ].includes(key as any); } export function isExpandedColumn(column: Record) { return get(column, 'key') === strings.DEFAULT_KEY_COLUMN_EXPAND; } export function isScrollbarColumn(column: Record) { return get(column, 'key') === strings.DEFAULT_KEY_COLUMN_SCROLLBAR; } export function isSelectionColumn(column: Record) { return get(column, 'key') === strings.DEFAULT_KEY_COLUMN_SELECTION; } export function filterColumns(columns: Record[], ignoreKeys = [strings.DEFAULT_KEY_COLUMN_SCROLLBAR]) { return filter(columns, col => !ignoreKeys.includes(col.key)); } /** * get width of scroll bar * @param {Array} columns * @returns {Number|undefined} */ export function getScrollbarColumnWidth(columns: Record[] = []) { const len = columns.length; if (len) { const lastColumn = columns[len - 1]; if (get(lastColumn, 'key') === strings.DEFAULT_KEY_COLUMN_SCROLLBAR) { return get(lastColumn, 'width', 0); } } } export function getRecordKey(record: Record, rowKey: string | number | ((record: any) => string | number)) { if (rowKey === undefined) { rowKey = 'key'; } return typeof rowKey === 'function' ? rowKey(record) : get(record, rowKey); } /** * Determine whether the expandedRowKeys includes a key (rowKey will be added to expandedRowKeys when the expand button is clicked) * @param {*} expandedRowKeys * @param {*} key */ export function isExpanded(expandedRowKeys: (string | number)[], key: string | number) { return key != null && includes(expandedRowKeys, key); } /** * Determine whether the selectedKeysSet includes the key * @param {Set} selectedRowKeysSet * @param {String} key */ export function isSelected(selectedRowKeysSet: Set, key: string | number) { return key !== null && selectedRowKeysSet.has(key); } /** * Whether the key is included in the disabledRowKeysSet * @param {Set} disabledRowKeysSet * @param {String} key */ export function isDisabled(disabledRowKeysSet: Set, key: string | number) { return key !== null && disabledRowKeysSet.has(key); } export function getRecord(data: any[], recordKey: string | number, rowKey: string | number | ((record: any) => string | number)) { if (rowKey === undefined) { rowKey = 'key'; } return find(data, record => recordKey != null && recordKey !== '' && getRecordKey(record, rowKey) === recordKey); } export function getRecordChildren(record: Record, childrenRecordName: string) { if (childrenRecordName === undefined) { childrenRecordName = 'children'; } return get(record, childrenRecordName); } export function genExpandedRowKey(recordKey = '', suffix?: string) { if (suffix === undefined) { suffix = '__expanded_row'; } return recordKey + suffix; } export function getDefaultVirtualizedRowConfig(size = '', sectionRow = false) { const config: { height?: number; minHeight?: number } = {}; if (size === 'small') { config.height = sectionRow ? numbers.DEFAULT_VIRTUALIZED_SECTION_ROW_SMALL_HEIGHT : numbers.DEFAULT_VIRTUALIZED_ROW_SMALL_HEIGHT; config.minHeight = numbers.DEFAULT_VIRTUALIZED_ROW_SMALL_MIN_HEIGHT; } else if (size === 'middle') { config.height = sectionRow ? numbers.DEFAULT_VIRTUALIZED_SECTION_ROW_MIDDLE_HEIGHT : numbers.DEFAULT_VIRTUALIZED_ROW_MIDDLE_HEIGHT; config.minHeight = numbers.DEFAULT_VIRTUALIZED_ROW_MIDDLE_MIN_HEIGHT; } else { config.height = sectionRow ? numbers.DEFAULT_VIRTUALIZED_SECTION_ROW_HEIGHT : numbers.DEFAULT_VIRTUALIZED_ROW_HEIGHT; config.minHeight = numbers.DEFAULT_VIRTUALIZED_ROW_MIN_HEIGHT; } return config; } export function flattenColumns(cols: Record[], childrenColumnName = 'children'): Record[] { const list = []; if (Array.isArray(cols) && cols.length) { for (const col of cols) { if (Array.isArray(col[childrenColumnName]) && col[childrenColumnName].length) { list.push(...flattenColumns(col[childrenColumnName], childrenColumnName)); } else { list.push(col); } } } return list; } export function assignColumnKeys(columns: Record[], childrenColumnName = 'children', level = 0) { const sameLevelCols: Record[] = []; each(columns, (column, index) => { if (column.key == null) { column.key = `${level}-${index}`; } if (Array.isArray(column[childrenColumnName]) && column[childrenColumnName].length) { sameLevelCols.push(...column[childrenColumnName]); } }); if (sameLevelCols.length) { assignColumnKeys(sameLevelCols, childrenColumnName, level + 1); } return columns; } export function sliceColumnsByLevel(columns: any[], targetLevel = 0, childrenColumnName = 'children', currentLevel = 0) { const slicedColumns: any[] = []; if (Array.isArray(columns) && columns.length && currentLevel <= targetLevel) { columns.forEach(column => { const children = column[childrenColumnName]; if (Array.isArray(children) && children.length && currentLevel < targetLevel) { slicedColumns.push(...sliceColumnsByLevel(children, targetLevel, childrenColumnName, currentLevel + 1)); } else { slicedColumns.push(column); } }); } return slicedColumns; } export function getColumnsByLevel( columns: Record[], targetLevel = 0, targetColumns: Record[] = [], currentLevel = 0, childrenColumnName = 'children' ) { if (Array.isArray(columns) && columns.length) { if (targetLevel === currentLevel) { targetColumns.push(...columns); } else { columns.forEach(column => { getColumnsByLevel( column[childrenColumnName], targetLevel, targetColumns, currentLevel + 1, childrenColumnName ); }); } } return targetColumns; } export function getAllLevelColumns(columns: Record[], childrenColumnName = 'children') { const all = []; if (Array.isArray(columns) && columns.length) { all.push([...columns]); const sameLevelColumns: Record[] = []; columns.forEach(column => { const children = column[childrenColumnName]; if (Array.isArray(children) && children.length) { sameLevelColumns.push(...children); } }); if (sameLevelColumns.length) { all.push(sameLevelColumns); } } return all; } export function getColumnByLevelIndex(columns: Record[], index: number, level = 0, childrenColumnName = 'children') { const allLevelColumns = getAllLevelColumns(columns, childrenColumnName); return allLevelColumns[level][index]; } export function findColumn(columns: Record[], column: Record, childrenColumnName = 'children') { let found: any; each(columns, item => { if (item && item.key != null && !found) { if (item.key === column.key) { found = item; } } if (item && Array.isArray(item[childrenColumnName]) && !found) { found = findColumn(item[childrenColumnName], column, childrenColumnName); } if (found) { return false; } return undefined; }); return found; } export function expandBtnShouldInRow(props: ExpandBtnShouldInRowProps) { const { expandedRowRender, dataSource, hideExpandedColumn, childrenRecordName, rowExpandable } = props; const hasExpandedRowRender = typeof expandedRowRender === 'function'; return ( (hideExpandedColumn && hasExpandedRowRender) || (!hasExpandedRowRender && dataSource.some(record => { const children = get(record, childrenRecordName); if ((Array.isArray(children) && children.length) || rowExpandable(record)) { return true; } else { return false; } })) ); } export type ExpandBtnShouldInRowProps = { expandedRowRender: (record?: Record, index?: number, expanded?: boolean) => any; dataSource: Record[]; hideExpandedColumn: boolean; childrenRecordName: string; rowExpandable: (record?: Record) => boolean; }; /** * merge query * @param {*} query * @param {*} queries */ export function mergeQueries(query: Record, queries: Record[] = []) { let _mergedQuery; const idx = queries.findIndex(item => { if (query.dataIndex === item.dataIndex) { _mergedQuery = { ...item, ...query }; return true; } return false; }); if (idx > -1) { queries.splice(idx, 1, _mergedQuery); } else { queries.push(_mergedQuery); } return [...queries]; } /** * Replace the width of the newColumns column with the width of the column after resize * @param {Object[]} columns columns retain the column width after resize * @param {Object[]} newColumns */ export function withResizeWidth(columns: Record[], newColumns: Record[]) { const _newColumns = cloneDeep(newColumns); for (const column of columns) { if (!isNullOrUndefined(column.width)) { const currentColumn = column.key; const columnIndex = findIndex(_newColumns, item => (item as any).key === currentColumn); if (columnIndex !== -1) { _newColumns[columnIndex].width = get(column, 'width'); } } } return _newColumns; } /** * Pure function version of the same function in table foundation * This is not accessible in getDerivedStateFromProps, so fork one out */ export function getAllDisabledRowKeys({ dataSource, getCheckboxProps, childrenRecordName, rowKey }: GetAllDisabledRowKeysProps): (string | number)[] { const disabledRowKeys = []; if (Array.isArray(dataSource) && dataSource.length && typeof getCheckboxProps === 'function') { for (const record of dataSource) { const props = getCheckboxProps(record); const recordKey = typeof rowKey === 'function' ? rowKey(record) : get(record, rowKey); if (props && props.disabled) { disabledRowKeys.push(recordKey); } const children = get(record, childrenRecordName); if (Array.isArray(children) && children.length) { const keys = getAllDisabledRowKeys({ dataSource: children, getCheckboxProps }); disabledRowKeys.push(...keys); } } } return disabledRowKeys; } export interface GetAllDisabledRowKeysProps { dataSource: Record[]; getCheckboxProps: (record?: Record) => any; childrenRecordName?: string; rowKey?: string | number | ((record: Record) => string | number); }