797 lines
29 KiB
JavaScript
797 lines
29 KiB
JavaScript
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
import { h, ref, defineComponent, inject, watchEffect, onUnmounted, computed, Fragment } from 'vue';
|
|
import { pxfy, repeat } from 'seemly';
|
|
import { VirtualList, VResizeObserver } from 'vueuc';
|
|
import { useMemo } from 'vooks';
|
|
import { cssrAnchorMetaName } from "../../../_mixins/common.mjs";
|
|
import { c } from "../../../_utils/cssr/index.mjs";
|
|
import { NScrollbar } from "../../../_internal/index.mjs";
|
|
import { formatLength, resolveSlot, warn } from "../../../_utils/index.mjs";
|
|
import { NEmpty } from "../../../empty/index.mjs";
|
|
import { dataTableInjectionKey } from "../interface.mjs";
|
|
import { createRowClassName, getColKey, isColumnSorting } from "../utils.mjs";
|
|
import Cell from "./Cell.mjs";
|
|
import ExpandTrigger from "./ExpandTrigger.mjs";
|
|
import RenderSafeCheckbox from "./BodyCheckbox.mjs";
|
|
import RenderSafeRadio from "./BodyRadio.mjs";
|
|
import TableHeader from "./Header.mjs";
|
|
function flatten(rowInfos, expandedRowKeys) {
|
|
const fRows = [];
|
|
function traverse(rs, rootIndex) {
|
|
rs.forEach(r => {
|
|
if (r.children && expandedRowKeys.has(r.key)) {
|
|
fRows.push({
|
|
tmNode: r,
|
|
striped: false,
|
|
key: r.key,
|
|
index: rootIndex
|
|
});
|
|
traverse(r.children, rootIndex);
|
|
} else {
|
|
fRows.push({
|
|
key: r.key,
|
|
tmNode: r,
|
|
striped: false,
|
|
index: rootIndex
|
|
});
|
|
}
|
|
});
|
|
}
|
|
rowInfos.forEach(rowInfo => {
|
|
fRows.push(rowInfo);
|
|
const {
|
|
children
|
|
} = rowInfo.tmNode;
|
|
if (children && expandedRowKeys.has(rowInfo.key)) {
|
|
traverse(children, rowInfo.index);
|
|
}
|
|
});
|
|
return fRows;
|
|
}
|
|
const VirtualListItemWrapper = defineComponent({
|
|
props: {
|
|
clsPrefix: {
|
|
type: String,
|
|
required: true
|
|
},
|
|
id: {
|
|
type: String,
|
|
required: true
|
|
},
|
|
cols: {
|
|
type: Array,
|
|
required: true
|
|
},
|
|
onMouseenter: Function,
|
|
onMouseleave: Function
|
|
},
|
|
render() {
|
|
const {
|
|
clsPrefix,
|
|
id,
|
|
cols,
|
|
onMouseenter,
|
|
onMouseleave
|
|
} = this;
|
|
return h("table", {
|
|
style: {
|
|
tableLayout: 'fixed'
|
|
},
|
|
class: `${clsPrefix}-data-table-table`,
|
|
onMouseenter: onMouseenter,
|
|
onMouseleave: onMouseleave
|
|
}, h("colgroup", null, cols.map(col => h("col", {
|
|
key: col.key,
|
|
style: col.style
|
|
}))), h("tbody", {
|
|
"data-n-id": id,
|
|
class: `${clsPrefix}-data-table-tbody`
|
|
}, this.$slots));
|
|
}
|
|
});
|
|
export default defineComponent({
|
|
name: 'DataTableBody',
|
|
props: {
|
|
onResize: Function,
|
|
showHeader: Boolean,
|
|
flexHeight: Boolean,
|
|
bodyStyle: Object
|
|
},
|
|
setup(props) {
|
|
const {
|
|
slots: dataTableSlots,
|
|
bodyWidthRef,
|
|
mergedExpandedRowKeysRef,
|
|
mergedClsPrefixRef,
|
|
mergedThemeRef,
|
|
scrollXRef,
|
|
colsRef,
|
|
paginatedDataRef,
|
|
rawPaginatedDataRef,
|
|
fixedColumnLeftMapRef,
|
|
fixedColumnRightMapRef,
|
|
mergedCurrentPageRef,
|
|
rowClassNameRef,
|
|
leftActiveFixedColKeyRef,
|
|
leftActiveFixedChildrenColKeysRef,
|
|
rightActiveFixedColKeyRef,
|
|
rightActiveFixedChildrenColKeysRef,
|
|
renderExpandRef,
|
|
hoverKeyRef,
|
|
summaryRef,
|
|
mergedSortStateRef,
|
|
virtualScrollRef,
|
|
componentId,
|
|
mergedTableLayoutRef,
|
|
childTriggerColIndexRef,
|
|
indentRef,
|
|
rowPropsRef,
|
|
maxHeightRef,
|
|
stripedRef,
|
|
loadingRef,
|
|
onLoadRef,
|
|
loadingKeySetRef,
|
|
expandableRef,
|
|
stickyExpandedRowsRef,
|
|
renderExpandIconRef,
|
|
summaryPlacementRef,
|
|
treeMateRef,
|
|
scrollbarPropsRef,
|
|
setHeaderScrollLeft,
|
|
doUpdateExpandedRowKeys,
|
|
handleTableBodyScroll,
|
|
doCheck,
|
|
doUncheck,
|
|
renderCell
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
} = inject(dataTableInjectionKey);
|
|
const scrollbarInstRef = ref(null);
|
|
const virtualListRef = ref(null);
|
|
const emptyElRef = ref(null);
|
|
const emptyRef = useMemo(() => paginatedDataRef.value.length === 0);
|
|
// If header is not inside & empty is displayed, no table part would be
|
|
// shown. So to collect a body width, we need to put a ref on empty element
|
|
const shouldDisplaySomeTablePartRef = useMemo(() => props.showHeader || !emptyRef.value);
|
|
// If no body is shown, we shouldn't show scrollbar
|
|
const bodyShowHeaderOnlyRef = useMemo(() => {
|
|
return props.showHeader || emptyRef.value;
|
|
});
|
|
let lastSelectedKey = '';
|
|
const mergedExpandedRowKeySetRef = computed(() => {
|
|
return new Set(mergedExpandedRowKeysRef.value);
|
|
});
|
|
function getRowInfo(key) {
|
|
var _a;
|
|
return (_a = treeMateRef.value.getNode(key)) === null || _a === void 0 ? void 0 : _a.rawNode;
|
|
}
|
|
function handleCheckboxUpdateChecked(tmNode, checked, shiftKey) {
|
|
const rowInfo = getRowInfo(tmNode.key);
|
|
if (!rowInfo) {
|
|
warn('data-table', `fail to get row data with key ${tmNode.key}`);
|
|
return;
|
|
}
|
|
if (shiftKey) {
|
|
const lastIndex = paginatedDataRef.value.findIndex(item => item.key === lastSelectedKey);
|
|
if (lastIndex !== -1) {
|
|
const currentIndex = paginatedDataRef.value.findIndex(item => item.key === tmNode.key);
|
|
const start = Math.min(lastIndex, currentIndex);
|
|
const end = Math.max(lastIndex, currentIndex);
|
|
const rowKeysToCheck = [];
|
|
paginatedDataRef.value.slice(start, end + 1).forEach(r => {
|
|
if (!r.disabled) {
|
|
rowKeysToCheck.push(r.key);
|
|
}
|
|
});
|
|
if (checked) {
|
|
doCheck(rowKeysToCheck, false, rowInfo);
|
|
} else {
|
|
doUncheck(rowKeysToCheck, rowInfo);
|
|
}
|
|
lastSelectedKey = tmNode.key;
|
|
return;
|
|
}
|
|
}
|
|
if (checked) {
|
|
doCheck(tmNode.key, false, rowInfo);
|
|
} else {
|
|
doUncheck(tmNode.key, rowInfo);
|
|
}
|
|
lastSelectedKey = tmNode.key;
|
|
}
|
|
function handleRadioUpdateChecked(tmNode) {
|
|
const rowInfo = getRowInfo(tmNode.key);
|
|
if (!rowInfo) {
|
|
warn('data-table', `fail to get row data with key ${tmNode.key}`);
|
|
return;
|
|
}
|
|
doCheck(tmNode.key, true, rowInfo);
|
|
}
|
|
function getScrollContainer() {
|
|
if (!shouldDisplaySomeTablePartRef.value) {
|
|
const {
|
|
value: emptyEl
|
|
} = emptyElRef;
|
|
if (emptyEl) {
|
|
return emptyEl;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
if (virtualScrollRef.value) {
|
|
return virtualListContainer();
|
|
}
|
|
const {
|
|
value
|
|
} = scrollbarInstRef;
|
|
if (value) return value.containerRef;
|
|
return null;
|
|
}
|
|
// For table row with children, tmNode is non-nullable
|
|
// For table row is expandable but is not tree data, tmNode is null
|
|
function handleUpdateExpanded(key, tmNode) {
|
|
var _a;
|
|
if (loadingKeySetRef.value.has(key)) return;
|
|
const {
|
|
value: mergedExpandedRowKeys
|
|
} = mergedExpandedRowKeysRef;
|
|
const index = mergedExpandedRowKeys.indexOf(key);
|
|
const nextExpandedKeys = Array.from(mergedExpandedRowKeys);
|
|
if (~index) {
|
|
nextExpandedKeys.splice(index, 1);
|
|
doUpdateExpandedRowKeys(nextExpandedKeys);
|
|
} else {
|
|
if (tmNode && !tmNode.isLeaf && !tmNode.shallowLoaded) {
|
|
loadingKeySetRef.value.add(key);
|
|
void ((_a = onLoadRef.value) === null || _a === void 0 ? void 0 : _a.call(onLoadRef, tmNode.rawNode).then(() => {
|
|
const {
|
|
value: futureMergedExpandedRowKeys
|
|
} = mergedExpandedRowKeysRef;
|
|
const futureNextExpandedKeys = Array.from(futureMergedExpandedRowKeys);
|
|
const index = futureNextExpandedKeys.indexOf(key);
|
|
if (!~index) {
|
|
futureNextExpandedKeys.push(key);
|
|
}
|
|
doUpdateExpandedRowKeys(futureNextExpandedKeys);
|
|
}).finally(() => {
|
|
loadingKeySetRef.value.delete(key);
|
|
}));
|
|
} else {
|
|
nextExpandedKeys.push(key);
|
|
doUpdateExpandedRowKeys(nextExpandedKeys);
|
|
}
|
|
}
|
|
}
|
|
function handleMouseleaveTable() {
|
|
hoverKeyRef.value = null;
|
|
}
|
|
function virtualListContainer() {
|
|
const {
|
|
value
|
|
} = virtualListRef;
|
|
return (value === null || value === void 0 ? void 0 : value.listElRef) || null;
|
|
}
|
|
function virtualListContent() {
|
|
const {
|
|
value
|
|
} = virtualListRef;
|
|
return (value === null || value === void 0 ? void 0 : value.itemsElRef) || null;
|
|
}
|
|
function handleVirtualListScroll(e) {
|
|
var _a;
|
|
handleTableBodyScroll(e);
|
|
(_a = scrollbarInstRef.value) === null || _a === void 0 ? void 0 : _a.sync();
|
|
}
|
|
function handleVirtualListResize(e) {
|
|
var _a;
|
|
const {
|
|
onResize
|
|
} = props;
|
|
if (onResize) onResize(e);
|
|
(_a = scrollbarInstRef.value) === null || _a === void 0 ? void 0 : _a.sync();
|
|
}
|
|
const exposedMethods = {
|
|
getScrollContainer,
|
|
scrollTo(arg0, arg1) {
|
|
var _a, _b;
|
|
if (virtualScrollRef.value) {
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
(_a = virtualListRef.value) === null || _a === void 0 ? void 0 : _a.scrollTo(arg0, arg1);
|
|
} else {
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
(_b = scrollbarInstRef.value) === null || _b === void 0 ? void 0 : _b.scrollTo(arg0, arg1);
|
|
}
|
|
}
|
|
};
|
|
// manually control shadow style to avoid rerender
|
|
const style = c([({
|
|
props: cProps
|
|
}) => {
|
|
const createActiveLeftFixedStyle = leftActiveFixedColKey => {
|
|
if (leftActiveFixedColKey === null) return null;
|
|
return c(`[data-n-id="${cProps.componentId}"] [data-col-key="${leftActiveFixedColKey}"]::after`, {
|
|
boxShadow: 'var(--n-box-shadow-after)'
|
|
});
|
|
};
|
|
const createActiveRightFixedStyle = rightActiveFixedColKey => {
|
|
if (rightActiveFixedColKey === null) return null;
|
|
return c(`[data-n-id="${cProps.componentId}"] [data-col-key="${rightActiveFixedColKey}"]::before`, {
|
|
boxShadow: 'var(--n-box-shadow-before)'
|
|
});
|
|
};
|
|
return c([createActiveLeftFixedStyle(cProps.leftActiveFixedColKey), createActiveRightFixedStyle(cProps.rightActiveFixedColKey), cProps.leftActiveFixedChildrenColKeys.map(leftActiveFixedColKey => createActiveLeftFixedStyle(leftActiveFixedColKey)), cProps.rightActiveFixedChildrenColKeys.map(rightActiveFixedColKey => createActiveRightFixedStyle(rightActiveFixedColKey))]);
|
|
}]);
|
|
let fixedStyleMounted = false;
|
|
watchEffect(() => {
|
|
const {
|
|
value: leftActiveFixedColKey
|
|
} = leftActiveFixedColKeyRef;
|
|
const {
|
|
value: leftActiveFixedChildrenColKeys
|
|
} = leftActiveFixedChildrenColKeysRef;
|
|
const {
|
|
value: rightActiveFixedColKey
|
|
} = rightActiveFixedColKeyRef;
|
|
const {
|
|
value: rightActiveFixedChildrenColKeys
|
|
} = rightActiveFixedChildrenColKeysRef;
|
|
if (!fixedStyleMounted && leftActiveFixedColKey === null && rightActiveFixedColKey === null) {
|
|
return;
|
|
}
|
|
const cProps = {
|
|
leftActiveFixedColKey,
|
|
leftActiveFixedChildrenColKeys,
|
|
rightActiveFixedColKey,
|
|
rightActiveFixedChildrenColKeys,
|
|
componentId
|
|
};
|
|
style.mount({
|
|
id: `n-${componentId}`,
|
|
force: true,
|
|
props: cProps,
|
|
anchorMetaName: cssrAnchorMetaName
|
|
});
|
|
fixedStyleMounted = true;
|
|
});
|
|
onUnmounted(() => {
|
|
style.unmount({
|
|
id: `n-${componentId}`
|
|
});
|
|
});
|
|
return Object.assign({
|
|
bodyWidth: bodyWidthRef,
|
|
summaryPlacement: summaryPlacementRef,
|
|
dataTableSlots,
|
|
componentId,
|
|
scrollbarInstRef,
|
|
virtualListRef,
|
|
emptyElRef,
|
|
summary: summaryRef,
|
|
mergedClsPrefix: mergedClsPrefixRef,
|
|
mergedTheme: mergedThemeRef,
|
|
scrollX: scrollXRef,
|
|
cols: colsRef,
|
|
loading: loadingRef,
|
|
bodyShowHeaderOnly: bodyShowHeaderOnlyRef,
|
|
shouldDisplaySomeTablePart: shouldDisplaySomeTablePartRef,
|
|
empty: emptyRef,
|
|
paginatedDataAndInfo: computed(() => {
|
|
const {
|
|
value: striped
|
|
} = stripedRef;
|
|
let hasChildren = false;
|
|
const data = paginatedDataRef.value.map(striped ? (tmNode, index) => {
|
|
if (!tmNode.isLeaf) hasChildren = true;
|
|
return {
|
|
tmNode,
|
|
key: tmNode.key,
|
|
striped: index % 2 === 1,
|
|
index
|
|
};
|
|
} : (tmNode, index) => {
|
|
if (!tmNode.isLeaf) hasChildren = true;
|
|
return {
|
|
tmNode,
|
|
key: tmNode.key,
|
|
striped: false,
|
|
index
|
|
};
|
|
});
|
|
return {
|
|
data,
|
|
hasChildren
|
|
};
|
|
}),
|
|
rawPaginatedData: rawPaginatedDataRef,
|
|
fixedColumnLeftMap: fixedColumnLeftMapRef,
|
|
fixedColumnRightMap: fixedColumnRightMapRef,
|
|
currentPage: mergedCurrentPageRef,
|
|
rowClassName: rowClassNameRef,
|
|
renderExpand: renderExpandRef,
|
|
mergedExpandedRowKeySet: mergedExpandedRowKeySetRef,
|
|
hoverKey: hoverKeyRef,
|
|
mergedSortState: mergedSortStateRef,
|
|
virtualScroll: virtualScrollRef,
|
|
mergedTableLayout: mergedTableLayoutRef,
|
|
childTriggerColIndex: childTriggerColIndexRef,
|
|
indent: indentRef,
|
|
rowProps: rowPropsRef,
|
|
maxHeight: maxHeightRef,
|
|
loadingKeySet: loadingKeySetRef,
|
|
expandable: expandableRef,
|
|
stickyExpandedRows: stickyExpandedRowsRef,
|
|
renderExpandIcon: renderExpandIconRef,
|
|
scrollbarProps: scrollbarPropsRef,
|
|
setHeaderScrollLeft,
|
|
handleVirtualListScroll,
|
|
handleVirtualListResize,
|
|
handleMouseleaveTable,
|
|
virtualListContainer,
|
|
virtualListContent,
|
|
handleTableBodyScroll,
|
|
handleCheckboxUpdateChecked,
|
|
handleRadioUpdateChecked,
|
|
handleUpdateExpanded,
|
|
renderCell
|
|
}, exposedMethods);
|
|
},
|
|
render() {
|
|
const {
|
|
mergedTheme,
|
|
scrollX,
|
|
mergedClsPrefix,
|
|
virtualScroll,
|
|
maxHeight,
|
|
mergedTableLayout,
|
|
flexHeight,
|
|
loadingKeySet,
|
|
onResize,
|
|
setHeaderScrollLeft
|
|
} = this;
|
|
const scrollable = scrollX !== undefined || maxHeight !== undefined || flexHeight;
|
|
// For a basic table with auto layout whose content may overflow we will
|
|
// make it scrollable, which differs from browser's native behavior.
|
|
// For native behavior, see
|
|
// https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout
|
|
const isBasicAutoLayout = !scrollable && mergedTableLayout === 'auto';
|
|
const xScrollable = scrollX !== undefined || isBasicAutoLayout;
|
|
const contentStyle = {
|
|
minWidth: formatLength(scrollX) || '100%'
|
|
};
|
|
if (scrollX) contentStyle.width = '100%';
|
|
const tableNode = h(NScrollbar, Object.assign({}, this.scrollbarProps, {
|
|
ref: "scrollbarInstRef",
|
|
scrollable: scrollable || isBasicAutoLayout,
|
|
class: `${mergedClsPrefix}-data-table-base-table-body`,
|
|
style: !this.empty ? this.bodyStyle : undefined,
|
|
theme: mergedTheme.peers.Scrollbar,
|
|
themeOverrides: mergedTheme.peerOverrides.Scrollbar,
|
|
contentStyle: contentStyle,
|
|
container: virtualScroll ? this.virtualListContainer : undefined,
|
|
content: virtualScroll ? this.virtualListContent : undefined,
|
|
horizontalRailStyle: {
|
|
zIndex: 3
|
|
},
|
|
verticalRailStyle: {
|
|
zIndex: 3
|
|
},
|
|
xScrollable: xScrollable,
|
|
onScroll: virtualScroll ? undefined : this.handleTableBodyScroll,
|
|
internalOnUpdateScrollLeft: setHeaderScrollLeft,
|
|
onResize: onResize
|
|
}), {
|
|
default: () => {
|
|
// coordinate to pass if there are cells that cross row & col
|
|
const cordToPass = {};
|
|
// coordinate to related hover keys
|
|
const cordKey = {};
|
|
const {
|
|
cols,
|
|
paginatedDataAndInfo,
|
|
mergedTheme,
|
|
fixedColumnLeftMap,
|
|
fixedColumnRightMap,
|
|
currentPage,
|
|
rowClassName,
|
|
mergedSortState,
|
|
mergedExpandedRowKeySet,
|
|
stickyExpandedRows,
|
|
componentId,
|
|
childTriggerColIndex,
|
|
expandable,
|
|
rowProps,
|
|
handleMouseleaveTable,
|
|
renderExpand,
|
|
summary,
|
|
handleCheckboxUpdateChecked,
|
|
handleRadioUpdateChecked,
|
|
handleUpdateExpanded
|
|
} = this;
|
|
const {
|
|
length: colCount
|
|
} = cols;
|
|
let mergedData;
|
|
// if there is children in data, we should expand mergedData first
|
|
const {
|
|
data: paginatedData,
|
|
hasChildren
|
|
} = paginatedDataAndInfo;
|
|
const mergedPaginationData = hasChildren ? flatten(paginatedData, mergedExpandedRowKeySet) : paginatedData;
|
|
if (summary) {
|
|
const summaryRows = summary(this.rawPaginatedData);
|
|
if (Array.isArray(summaryRows)) {
|
|
const summaryRowData = summaryRows.map((row, i) => ({
|
|
isSummaryRow: true,
|
|
key: `__n_summary__${i}`,
|
|
tmNode: {
|
|
rawNode: row,
|
|
disabled: true
|
|
},
|
|
index: -1
|
|
}));
|
|
mergedData = this.summaryPlacement === 'top' ? [...summaryRowData, ...mergedPaginationData] : [...mergedPaginationData, ...summaryRowData];
|
|
} else {
|
|
const summaryRowData = {
|
|
isSummaryRow: true,
|
|
key: '__n_summary__',
|
|
tmNode: {
|
|
rawNode: summaryRows,
|
|
disabled: true
|
|
},
|
|
index: -1
|
|
};
|
|
mergedData = this.summaryPlacement === 'top' ? [summaryRowData, ...mergedPaginationData] : [...mergedPaginationData, summaryRowData];
|
|
}
|
|
} else {
|
|
mergedData = mergedPaginationData;
|
|
}
|
|
const indentStyle = hasChildren ? {
|
|
width: pxfy(this.indent)
|
|
} : undefined;
|
|
// Tile the data of the expanded row
|
|
const displayedData = [];
|
|
mergedData.forEach(rowInfo => {
|
|
if (renderExpand && mergedExpandedRowKeySet.has(rowInfo.key) && (!expandable || expandable(rowInfo.tmNode.rawNode))) {
|
|
displayedData.push(rowInfo, {
|
|
isExpandedRow: true,
|
|
key: `${rowInfo.key}-expand`,
|
|
// solve key repeat of the expanded row
|
|
tmNode: rowInfo.tmNode,
|
|
index: rowInfo.index
|
|
});
|
|
} else {
|
|
displayedData.push(rowInfo);
|
|
}
|
|
});
|
|
const {
|
|
length: rowCount
|
|
} = displayedData;
|
|
const rowIndexToKey = {};
|
|
paginatedData.forEach(({
|
|
tmNode
|
|
}, rowIndex) => {
|
|
rowIndexToKey[rowIndex] = tmNode.key;
|
|
});
|
|
const bodyWidth = stickyExpandedRows ? this.bodyWidth : null;
|
|
const bodyWidthPx = bodyWidth === null ? undefined : `${bodyWidth}px`;
|
|
const renderRow = (rowInfo, displayedRowIndex, isVirtual) => {
|
|
const {
|
|
index: actualRowIndex
|
|
} = rowInfo;
|
|
if ('isExpandedRow' in rowInfo) {
|
|
const {
|
|
tmNode: {
|
|
key,
|
|
rawNode
|
|
}
|
|
} = rowInfo;
|
|
return h("tr", {
|
|
class: `${mergedClsPrefix}-data-table-tr ${mergedClsPrefix}-data-table-tr--expanded`,
|
|
key: `${key}__expand`
|
|
}, h("td", {
|
|
class: [`${mergedClsPrefix}-data-table-td`, `${mergedClsPrefix}-data-table-td--last-col`, displayedRowIndex + 1 === rowCount && `${mergedClsPrefix}-data-table-td--last-row`],
|
|
colspan: colCount
|
|
}, stickyExpandedRows ? h("div", {
|
|
class: `${mergedClsPrefix}-data-table-expand`,
|
|
style: {
|
|
width: bodyWidthPx
|
|
}
|
|
}, renderExpand(rawNode, actualRowIndex)) : renderExpand(rawNode, actualRowIndex)));
|
|
}
|
|
const isSummary = ('isSummaryRow' in rowInfo);
|
|
const striped = !isSummary && rowInfo.striped;
|
|
const {
|
|
tmNode,
|
|
key: rowKey
|
|
} = rowInfo;
|
|
const {
|
|
rawNode: rowData
|
|
} = tmNode;
|
|
const expanded = mergedExpandedRowKeySet.has(rowKey);
|
|
const props = rowProps ? rowProps(rowData, actualRowIndex) : undefined;
|
|
const mergedRowClassName = typeof rowClassName === 'string' ? rowClassName : createRowClassName(rowData, actualRowIndex, rowClassName);
|
|
const row = h("tr", Object.assign({
|
|
onMouseenter: () => {
|
|
this.hoverKey = rowKey;
|
|
},
|
|
key: rowKey,
|
|
class: [`${mergedClsPrefix}-data-table-tr`, isSummary && `${mergedClsPrefix}-data-table-tr--summary`, striped && `${mergedClsPrefix}-data-table-tr--striped`, expanded && `${mergedClsPrefix}-data-table-tr--expanded`, mergedRowClassName]
|
|
}, props), cols.map((col, colIndex) => {
|
|
var _a, _b, _c, _d, _e;
|
|
if (displayedRowIndex in cordToPass) {
|
|
const cordOfRowToPass = cordToPass[displayedRowIndex];
|
|
const indexInCordOfRowToPass = cordOfRowToPass.indexOf(colIndex);
|
|
if (~indexInCordOfRowToPass) {
|
|
cordOfRowToPass.splice(indexInCordOfRowToPass, 1);
|
|
return null;
|
|
}
|
|
}
|
|
// TODO: Simplify row calculation
|
|
const {
|
|
column
|
|
} = col;
|
|
const colKey = getColKey(col);
|
|
const {
|
|
rowSpan,
|
|
colSpan
|
|
} = column;
|
|
const mergedColSpan = isSummary ? ((_a = rowInfo.tmNode.rawNode[colKey]) === null || _a === void 0 ? void 0 : _a.colSpan) || 1 // optional for #1276
|
|
: colSpan ? colSpan(rowData, actualRowIndex) : 1;
|
|
const mergedRowSpan = isSummary ? ((_b = rowInfo.tmNode.rawNode[colKey]) === null || _b === void 0 ? void 0 : _b.rowSpan) || 1 // optional for #1276
|
|
: rowSpan ? rowSpan(rowData, actualRowIndex) : 1;
|
|
const isLastCol = colIndex + mergedColSpan === colCount;
|
|
const isLastRow = displayedRowIndex + mergedRowSpan === rowCount;
|
|
const isCrossRowTd = mergedRowSpan > 1;
|
|
if (isCrossRowTd) {
|
|
cordKey[displayedRowIndex] = {
|
|
[colIndex]: []
|
|
};
|
|
}
|
|
if (mergedColSpan > 1 || isCrossRowTd) {
|
|
for (let i = displayedRowIndex; i < displayedRowIndex + mergedRowSpan; ++i) {
|
|
if (isCrossRowTd) {
|
|
cordKey[displayedRowIndex][colIndex].push(rowIndexToKey[i]);
|
|
}
|
|
for (let j = colIndex; j < colIndex + mergedColSpan; ++j) {
|
|
if (i === displayedRowIndex && j === colIndex) {
|
|
continue;
|
|
}
|
|
if (!(i in cordToPass)) {
|
|
cordToPass[i] = [j];
|
|
} else {
|
|
cordToPass[i].push(j);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const hoverKey = isCrossRowTd ? this.hoverKey : null;
|
|
const {
|
|
cellProps
|
|
} = column;
|
|
const resolvedCellProps = cellProps === null || cellProps === void 0 ? void 0 : cellProps(rowData, actualRowIndex);
|
|
const indentOffsetStyle = {
|
|
'--indent-offset': ''
|
|
};
|
|
return h("td", Object.assign({}, resolvedCellProps, {
|
|
key: colKey,
|
|
style: [{
|
|
textAlign: column.align || undefined,
|
|
left: pxfy((_c = fixedColumnLeftMap[colKey]) === null || _c === void 0 ? void 0 : _c.start),
|
|
right: pxfy((_d = fixedColumnRightMap[colKey]) === null || _d === void 0 ? void 0 : _d.start)
|
|
}, indentOffsetStyle, (resolvedCellProps === null || resolvedCellProps === void 0 ? void 0 : resolvedCellProps.style) || ''],
|
|
colspan: mergedColSpan,
|
|
rowspan: isVirtual ? undefined : mergedRowSpan,
|
|
"data-col-key": colKey,
|
|
class: [`${mergedClsPrefix}-data-table-td`, column.className, resolvedCellProps === null || resolvedCellProps === void 0 ? void 0 : resolvedCellProps.class, isSummary && `${mergedClsPrefix}-data-table-td--summary`, (hoverKey !== null && cordKey[displayedRowIndex][colIndex].includes(hoverKey) || isColumnSorting(column, mergedSortState)) && `${mergedClsPrefix}-data-table-td--hover`, column.fixed && `${mergedClsPrefix}-data-table-td--fixed-${column.fixed}`, column.align && `${mergedClsPrefix}-data-table-td--${column.align}-align`, column.type === 'selection' && `${mergedClsPrefix}-data-table-td--selection`, column.type === 'expand' && `${mergedClsPrefix}-data-table-td--expand`, isLastCol && `${mergedClsPrefix}-data-table-td--last-col`, isLastRow && `${mergedClsPrefix}-data-table-td--last-row`]
|
|
}), hasChildren && colIndex === childTriggerColIndex ? [repeat(indentOffsetStyle['--indent-offset'] = isSummary ? 0 : rowInfo.tmNode.level, h("div", {
|
|
class: `${mergedClsPrefix}-data-table-indent`,
|
|
style: indentStyle
|
|
})), isSummary || rowInfo.tmNode.isLeaf ? h("div", {
|
|
class: `${mergedClsPrefix}-data-table-expand-placeholder`
|
|
}) : h(ExpandTrigger, {
|
|
class: `${mergedClsPrefix}-data-table-expand-trigger`,
|
|
clsPrefix: mergedClsPrefix,
|
|
expanded: expanded,
|
|
renderExpandIcon: this.renderExpandIcon,
|
|
loading: loadingKeySet.has(rowInfo.key),
|
|
onClick: () => {
|
|
handleUpdateExpanded(rowKey, rowInfo.tmNode);
|
|
}
|
|
})] : null, column.type === 'selection' ? !isSummary ? column.multiple === false ? h(RenderSafeRadio, {
|
|
key: currentPage,
|
|
rowKey: rowKey,
|
|
disabled: rowInfo.tmNode.disabled,
|
|
onUpdateChecked: () => {
|
|
handleRadioUpdateChecked(rowInfo.tmNode);
|
|
}
|
|
}) : h(RenderSafeCheckbox, {
|
|
key: currentPage,
|
|
rowKey: rowKey,
|
|
disabled: rowInfo.tmNode.disabled,
|
|
onUpdateChecked: (checked, e) => {
|
|
handleCheckboxUpdateChecked(rowInfo.tmNode, checked, e.shiftKey);
|
|
}
|
|
}) : null : column.type === 'expand' ? !isSummary ? !column.expandable || ((_e = column.expandable) === null || _e === void 0 ? void 0 : _e.call(column, rowData)) ? h(ExpandTrigger, {
|
|
clsPrefix: mergedClsPrefix,
|
|
expanded: expanded,
|
|
renderExpandIcon: this.renderExpandIcon,
|
|
onClick: () => {
|
|
handleUpdateExpanded(rowKey, null);
|
|
}
|
|
}) : null : null : h(Cell, {
|
|
clsPrefix: mergedClsPrefix,
|
|
index: actualRowIndex,
|
|
row: rowData,
|
|
column: column,
|
|
isSummary: isSummary,
|
|
mergedTheme: mergedTheme,
|
|
renderCell: this.renderCell
|
|
}));
|
|
}));
|
|
return row;
|
|
};
|
|
if (!virtualScroll) {
|
|
return h("table", {
|
|
class: `${mergedClsPrefix}-data-table-table`,
|
|
onMouseleave: handleMouseleaveTable,
|
|
style: {
|
|
tableLayout: this.mergedTableLayout
|
|
}
|
|
}, h("colgroup", null, cols.map(col => h("col", {
|
|
key: col.key,
|
|
style: col.style
|
|
}))), this.showHeader ? h(TableHeader, {
|
|
discrete: false
|
|
}) : null, !this.empty ? h("tbody", {
|
|
"data-n-id": componentId,
|
|
class: `${mergedClsPrefix}-data-table-tbody`
|
|
}, displayedData.map((rowInfo, displayedRowIndex) => {
|
|
return renderRow(rowInfo, displayedRowIndex, false);
|
|
})) : null);
|
|
} else {
|
|
return h(VirtualList, {
|
|
ref: "virtualListRef",
|
|
items: displayedData,
|
|
itemSize: 28,
|
|
visibleItemsTag: VirtualListItemWrapper,
|
|
visibleItemsProps: {
|
|
clsPrefix: mergedClsPrefix,
|
|
id: componentId,
|
|
cols,
|
|
onMouseleave: handleMouseleaveTable
|
|
},
|
|
showScrollbar: false,
|
|
onResize: this.handleVirtualListResize,
|
|
onScroll: this.handleVirtualListScroll,
|
|
itemsStyle: contentStyle,
|
|
itemResizable: true
|
|
}, {
|
|
default: ({
|
|
item,
|
|
index
|
|
}) => renderRow(item, index, true)
|
|
});
|
|
}
|
|
}
|
|
});
|
|
if (this.empty) {
|
|
const createEmptyNode = () => h("div", {
|
|
class: [`${mergedClsPrefix}-data-table-empty`, this.loading && `${mergedClsPrefix}-data-table-empty--hide`],
|
|
style: this.bodyStyle,
|
|
ref: "emptyElRef"
|
|
}, resolveSlot(this.dataTableSlots.empty, () => [h(NEmpty, {
|
|
theme: this.mergedTheme.peers.Empty,
|
|
themeOverrides: this.mergedTheme.peerOverrides.Empty
|
|
})]));
|
|
if (this.shouldDisplaySomeTablePart) {
|
|
return h(Fragment, null, tableNode, createEmptyNode());
|
|
} else {
|
|
return h(VResizeObserver, {
|
|
onResize: this.onResize
|
|
}, {
|
|
default: createEmptyNode
|
|
});
|
|
}
|
|
}
|
|
return tableNode;
|
|
}
|
|
}); |