vue-easytable
Version:
1,488 lines (1,378 loc) • 146 kB
JSX
import { cloneDeep, debounce } from "lodash";
import {
initGroupColumns,
clsName,
getNotFixedTotalWidthByColumnKey,
recursiveRemoveColumnByKey,
setHeaderContextmenuOptions,
setBodyContextmenuOptions,
createEmptyRowData,
isContextmenuPanelClicked,
getRowKey,
getColKeysByHeaderColumn,
getColumnByColkey,
getLeftmostColKey,
isCellInSelectionRange,
isClearSelectionByBodyCellRightClick,
cellAutofill,
isOperationColumn,
getSelectionRangeData,
getSelectionRangeKeys,
getSelectionRangeIndexes,
setColumnFixed,
cancelColumnFixed,
} from "./util";
import {
onBeforeCopy,
onAfterCopy,
onBeforePaste,
onAfterPaste,
onBeforeCut,
onAfterCut,
onBeforeDelete,
onAfterDelete,
} from "./util/clipboard";
import {
getValByUnit,
isFunction,
isNumber,
scrollTo,
isEmptyValue,
isEmptyArray,
isBoolean,
isDefined,
createLocale,
} from "../../src/utils/index.js";
import { KEY_CODES, MOUSE_EVENT_CLICK_TYPE } from "../../src/utils/constant";
import { getScrollbarWidth } from "../../src/utils/scroll-bar";
import {
requestAnimationTimeout,
cancelAnimationTimeout,
} from "../../src/utils/request-animation-timeout";
import { isInputKeyCode } from "../../src/utils/event-key-codes";
import Hooks from "../../src/utils/hooks-manager";
import { getMouseEventClickType } from "../../src/utils/mouse-event";
import emitter from "../../src/mixins/emitter";
import {
COMPS_NAME,
HOOKS_NAME,
EMIT_EVENTS,
COMPS_CUSTOM_ATTRS,
INSTANCE_METHODS,
CELL_SELECTION_DIRECTION,
LOCALE_COMP_NAME,
CONTEXTMENU_TYPES,
CONTEXTMENU_NODE_TYPES,
AUTOFILLING_DIRECTION,
CURRENT_CELL_SELECTION_TYPES,
COLUMN_FIXED_TYPE,
} from "./util/constant";
import Colgroup from "./colgroup";
import Header from "./header";
import Body from "./body";
import Footer from "./footer";
import EditInput from "./editor/index";
import Selection from "./selection/index";
import clickoutside from "../../src/directives/clickoutside";
import VueDomResizeObserver from "../../src/comps/resize-observer";
import VeContextmenu from "vue-easytable/packages/ve-contextmenu";
import ColumnResizer from "./column-resizer";
const t = createLocale(LOCALE_COMP_NAME);
export default {
name: COMPS_NAME.VE_TABLE,
directives: {
"click-outside": clickoutside,
},
mixins: [emitter],
props: {
tableData: {
required: true,
type: Array,
},
footerData: {
type: Array,
default: function () {
return [];
},
},
showHeader: {
type: Boolean,
default: true,
},
columns: {
type: Array,
required: true,
},
// row key field for row expand、row selection
rowKeyFieldName: {
type: String,
default: null,
},
// table scroll width
scrollWidth: {
type: [Number, String],
default: null,
},
// table max height
maxHeight: {
type: [Number, String],
default: null,
},
// fixed header
fixedHeader: {
type: Boolean,
default: true,
},
// fixed footer
fixedFooter: {
type: Boolean,
default: true,
},
// border around
borderAround: {
type: Boolean,
default: true,
},
// border horizontal
borderX: {
type: Boolean,
default: true,
},
// border vertical
borderY: {
type: Boolean,
default: false,
},
// event custom option
eventCustomOption: {
type: Object,
default: function () {
return null;
},
},
// cell style option
cellStyleOption: {
type: Object,
default: function () {
return null;
},
},
// cell span option
cellSpanOption: {
type: Object,
default: function () {
return null;
},
},
// row style option
rowStyleOption: {
type: Object,
default: function () {
return null;
},
},
/*
virual scroll option
{
enable:true,
bufferCount:10, // 缓冲的数据
minRowHeight:40,
scrolling:(startRowIndex,visibleStartIndex,visibleEndIndex,visibleAboveCount,visibleBelowCount)=>{}
}
*/
virtualScrollOption: {
type: Object,
default: null,
},
// sort option
sortOption: {
type: Object,
default: function () {
return null;
},
},
// expand row option
expandOption: {
type: Object,
default: function () {
return null;
},
},
// checkbox option
checkboxOption: {
type: Object,
default: function () {
return null;
},
},
// radio option
radioOption: {
type: Object,
default: function () {
return null;
},
},
// cell selection option
cellSelectionOption: {
type: Object,
default: function () {
return null;
},
},
// cell autofill option
cellAutofillOption: {
type: [Object, Boolean],
default: function () {
return null;
},
},
// edit option
editOption: {
type: Object,
default: function () {
return null;
},
},
// column hidden option
columnHiddenOption: {
type: Object,
default: function () {
return null;
},
},
// contextmenu header option
contextmenuHeaderOption: {
type: Object,
default: function () {
return null;
},
},
// contextmenu body option
contextmenuBodyOption: {
type: Object,
default: function () {
return null;
},
},
// clipboard option
clipboardOption: {
type: Object,
default: function () {
return null;
},
},
// column width resize option
columnWidthResizeOption: {
type: Object,
default: function () {
return null;
},
},
},
data() {
return {
// Hooks instance
hooks: {},
// is parent rendered
parentRendered: false,
// table viewport width except scroll bar width
tableViewportWidth: 0,
/*
列配置变化次数
依赖columns 配置渲染,都需要重新计算:粘性布局时,重新触发 on-dom-resize-change 事件
*/
columnsOptionResetTime: 0,
tableRootRef: "tableRootRef",
tableContainerWrapperRef: "tableContainerWrapperRef",
tableContainerRef: "tableContainerRef",
tableRef: "tableRef",
tableBodyRef: "tableBodyRef",
tableContentWrapperRef: "tableContentWrapperRef",
virtualPhantomRef: "virtualPhantomRef",
editInputRef: "editInputRef",
cellSelectionRef: "cellSelectionRef",
contextmenuRef: "contextmenuRef",
cloneColumns: [],
// is group header
isGroupHeader: false,
/*
header rows created by groupColumns
*/
headerRows: [
/* {
rowHeight:40
} */
],
/*
footer rows created by footerData
*/
footerRows: [
/* {
rowHeight:40
} */
],
// colgroups
colgroups: [],
// groupColumns
groupColumns: [],
/*
存储当前隐藏列信息
hidden columns
*/
hiddenColumns: [],
/*
// virtual scroll positions(非响应式)
virtualScrollPositions = [
{
rowKey: "", // 当前行数据 rowKey
top: 0, // 距离上一个项的高度
bottom: 100, // 距离下一个项的高度
height: 100 // 自身高度
}
],
*/
// virtual scroll visible data
virtualScrollVisibleData: [],
// virtual scroll visible indexs
virtualScrollVisibleIndexs: {
start: -1,
end: -1,
},
// default virtual scroll buffer scale
defaultVirtualScrollBufferScale: 1,
// default virtual scroll min row height
defaultVirtualScrollMinRowHeight: 40,
// default placeholder per scrolling row count
defaultPlaceholderPerScrollingRowCount: 8,
//起始索引
virtualScrollStartIndex: 0,
// preview virtual scroll start index
previewVirtualScrollStartIndex: 0,
//结束索引
virtualScrollEndIndex: 0,
// is scrolling
showVirtualScrollingPlaceholder: false,
// disable pointer events timeout id
disablePointerEventsTimeoutId: null,
// is scrolling left
isLeftScrolling: false,
// is scrolling right
isRightScrolling: false,
// is scrolling vertically
isVerticalScrolling: false,
// has horizontal scroll bar
hasXScrollBar: false,
// has vertical scroll bar
hasYScrollBar: false,
// scroll bar width
scrollBarWidth: 0,
// preview table container scrollLeft (处理左列或右列固定效果)
previewTableContainerScrollLeft: null,
// header cell selection colKeys
headerIndicatorColKeys: {
startColKey: "",
startColKeyIndex: -1,
endColKey: "",
endColKeyIndex: -1,
},
// body indicator rowKeys
bodyIndicatorRowKeys: {
startRowKey: "",
startRowKeyIndex: -1,
endRowKey: "",
endRowKeyIndex: -1,
},
// cell selection data
cellSelectionData: {
currentCell: {
rowKey: "",
colKey: "",
rowIndex: -1,
},
normalEndCell: {
rowKey: "",
colKey: "",
rowIndex: -1,
},
autoFillEndCell: {
rowKey: "",
colKey: "",
},
},
// cell selection range data
cellSelectionRangeData: {
leftColKey: "",
rightColKey: "",
topRowKey: "",
bottomRowKey: "",
},
// is header cell mousedown
isHeaderCellMousedown: false,
// is body cell mousedown
isBodyCellMousedown: false,
// is body operation column mousedown
isBodyOperationColumnMousedown: false,
// is cell selection corner mousedown
isAutofillStarting: false,
// autofilling direction
autofillingDirection: null,
// current cell selection type
currentCellSelectionType: "",
/*
table offest height(开启虚拟滚动时使用)
1、当 :max-height="500" 时使用 max-height
2、当 max-height="calc(100vh - 210px)" 或者 max-height="80%" 时使用 tableOffestHeight
*/
tableOffestHeight: 0,
// table height
tableHeight: 0,
// highlight row key
highlightRowKey: "",
/*
editing cell
*/
editingCell: {
rowKey: "",
colKey: "",
row: null,
column: null,
},
// 编辑单元格每次开始编辑前的初始值
editorInputStartValue: "",
/*
是否允许按下方向键时,停止编辑并移动选中单元格。当双击可编辑单元格或者点击输入文本框时设置为false值
像excel一样:如果直接在可编辑单元格上输入内容后,按下上、下、左、右按键可以直接选中其他单元格,并停止当前单元格编辑状态
like Excel:If you directly enter content in an editable cell, press the up, down, left and right buttons to directly select other cells and stop editing the current cell
*/
enableStopEditing: true,
// contextmenu event target
contextmenuEventTarget: "",
// contextmenu options
contextmenuOptions: [],
// column resize cursor
isColumnResizerHover: false,
// is column resizing
isColumnResizing: false,
};
},
computed: {
// actual render table data
actualRenderTableData() {
return this.isVirtualScroll
? this.virtualScrollVisibleData
: this.tableData;
},
// return row keys
allRowKeys() {
let result = [];
const { tableData, rowKeyFieldName } = this;
if (rowKeyFieldName) {
result = tableData.map((x) => {
return x[rowKeyFieldName];
});
}
return result;
},
// virtual scroll buffer count
virtualScrollBufferCount() {
let result = 0;
const {
virtualScrollOption,
defaultVirtualScrollBufferScale,
virtualScrollVisibleCount,
} = this;
if (virtualScrollOption) {
const { bufferScale } = virtualScrollOption;
let realBufferScale =
isNumber(bufferScale) && bufferScale > 0
? bufferScale
: defaultVirtualScrollBufferScale;
result = realBufferScale * virtualScrollVisibleCount;
}
return result;
},
// virtual scroll visible count
virtualScrollVisibleCount() {
let result = 0;
const {
isVirtualScroll,
virtualScrollOption,
defaultVirtualScrollMinRowHeight,
maxHeight,
tableOffestHeight,
} = this;
if (isVirtualScroll && maxHeight) {
const minRowHeight = isNumber(virtualScrollOption.minRowHeight)
? virtualScrollOption.minRowHeight
: defaultVirtualScrollMinRowHeight;
if (isNumber(maxHeight)) {
result = Math.ceil(maxHeight / minRowHeight);
} else if (tableOffestHeight) {
// 修复当动态高度 当 max-height="calc(100vh - 210px)" 或者 max-height="80%" 时无法计算的问题
result = Math.ceil(tableOffestHeight / minRowHeight);
}
}
return result;
},
// table container wrapper style
tableContainerWrapperStyle() {
return {
width: "100%",
};
},
// table container style
tableContainerStyle() {
let maxHeight = getValByUnit(this.maxHeight);
let tableContainerHeight = null;
if (this.isVirtualScroll) {
if (maxHeight) {
tableContainerHeight = maxHeight;
} else {
console.error(
"maxHeight prop is required when 'virtualScrollOption.enable = true'",
);
}
} else {
/*
fixed:虚拟滚动表格行展开的 ve-table 存在固定头时(sticky 冲突),表格样式错乱的问题
fixed:When there is a fixed header in the ve-table expanded by the row of the virtual rolling table(header sticky conflict),Incorrect table presentation
*/
const { tableHeight, hasXScrollBar } = this;
tableContainerHeight = tableHeight;
/*
有横向滚动条时,表格高度需要加上滚动条的宽度
When there is a horizontal scroll bar, the table height needs to be added with the width of the scroll bar
*/
if (hasXScrollBar) {
tableContainerHeight += this.getScrollBarWidth();
}
tableContainerHeight = getValByUnit(tableContainerHeight);
}
return {
"max-height": maxHeight,
// if virtual scroll
height: tableContainerHeight,
};
},
// table style
tableStyle() {
return {
width: getValByUnit(this.scrollWidth),
};
},
// table class
tableClass() {
return {
[clsName("border-x")]: this.borderX,
[clsName("border-y")]: this.borderY,
};
},
// table container class
tableContainerClass() {
const {
isVirtualScroll,
isLeftScrolling,
isRightScrolling,
isVerticalScrolling,
isCellEditing,
isAutofillStarting,
enableCellSelection,
} = this;
return {
[clsName("container")]: true,
[clsName("virtual-scroll")]: isVirtualScroll,
[clsName("container-left-scrolling")]: isLeftScrolling,
[clsName("container-right-scrolling")]: isRightScrolling,
[clsName("container-vertical-scrolling")]: isVerticalScrolling,
[clsName("is-cell-editing")]: isCellEditing,
[clsName("autofilling")]: isAutofillStarting,
// 如果开启单元格选择,则关闭 user-select
[clsName("enable-cell-selection")]: enableCellSelection,
};
},
// table body class
tableBodyClass() {
let result = null;
const { rowStyleOption } = this;
let hoverHighlight = true;
let clickHighlight = true;
let stripe = false;
if (rowStyleOption) {
hoverHighlight = rowStyleOption.hoverHighlight;
clickHighlight = rowStyleOption.clickHighlight;
stripe = rowStyleOption.stripe;
}
result = {
[clsName("stripe")]: stripe === true, // 默认不开启
[clsName("row-hover")]: hoverHighlight !== false, // 默认开启
[clsName("row-highlight")]: clickHighlight !== false, // 默认开启
};
return result;
},
// is virtual scroll
isVirtualScroll() {
const { virtualScrollOption } = this;
return virtualScrollOption && virtualScrollOption.enable;
},
// has fixed column
hasFixedColumn() {
return this.colgroups.some(
(x) =>
x.fixed === COLUMN_FIXED_TYPE.LEFT ||
x.fixed === COLUMN_FIXED_TYPE.RIGHT,
);
},
// has left fixed column
hasLeftFixedColumn() {
return this.colgroups.some(
(x) => x.fixed === COLUMN_FIXED_TYPE.LEFT,
);
},
// has right fixed column
hasRightFixedColumn() {
return this.colgroups.some(
(x) => x.fixed === COLUMN_FIXED_TYPE.RIGHT,
);
},
// is editing cell
isCellEditing() {
const { editingCell } = this;
return (
!isEmptyValue(editingCell.rowKey) &&
!isEmptyValue(editingCell.colKey)
);
},
// has edit column
hasEditColumn() {
return this.colgroups.some((x) => x.edit);
},
// enable header contextmenu
enableHeaderContextmenu() {
let result = false;
const { contextmenuHeaderOption } = this;
if (contextmenuHeaderOption) {
const { contextmenus } = contextmenuHeaderOption;
if (Array.isArray(contextmenus) && contextmenus.length) {
result = true;
}
}
return result;
},
// enable body contextmenu
enableBodyContextmenu() {
let result = false;
const { contextmenuBodyOption } = this;
if (contextmenuBodyOption) {
const { contextmenus } = contextmenuBodyOption;
if (Array.isArray(contextmenus) && contextmenus.length) {
result = true;
}
}
return result;
},
// contextmenu type
contextMenuType() {
if (this.headerIndicatorColKeys.startColKeyIndex > -1) {
return CONTEXTMENU_TYPES.HEADER_CONTEXTMENU;
} else {
return CONTEXTMENU_TYPES.BODY_CONTEXTMENU;
}
},
/*
enable cell selection
单元格编辑、剪贴板都依赖单元格选择
*/
enableCellSelection() {
let result = true;
const { cellSelectionOption, rowKeyFieldName } = this;
if (isEmptyValue(rowKeyFieldName)) {
result = false;
} else if (
cellSelectionOption &&
isBoolean(cellSelectionOption.enable) &&
cellSelectionOption.enable === false
) {
result = false;
}
return result;
},
// enable clipboard
enableClipboard() {
return this.rowKeyFieldName;
},
// eanble width resize
enableColumnResize() {
let result = false;
const { columnWidthResizeOption } = this;
if (columnWidthResizeOption) {
const { enable } = columnWidthResizeOption;
if (isBoolean(enable)) {
result = enable;
}
}
return result;
},
// header total height
headerTotalHeight() {
let result = 0;
if (this.showHeader) {
result = this.headerRows.reduce((total, currentVal) => {
return currentVal.rowHeight + total;
}, 0);
}
return result;
},
// footer total height
footerTotalHeight() {
return this.footerRows.reduce((total, currentVal) => {
return currentVal.rowHeight + total;
}, 0);
},
},
watch: {
// watch clone table data
tableData: {
handler(newVal, oldVal) {
this.initVirtualScrollPositions();
// 第一次不需要触发,仅数据变更触发
if (oldVal) {
this.initVirtualScroll();
}
},
immediate: true,
},
allRowKeys: {
handler(newVal) {
if (Array.isArray(newVal)) {
const { currentCell } = this.cellSelectionData;
// 行被移除,清空单元格选中
if (currentCell.rowIndex > -1) {
if (newVal.indexOf(currentCell.rowKey) === -1) {
this.clearCellSelectionCurrentCell();
}
}
}
},
immediate: false,
},
columns: {
handler(newVal, oldVal) {
this.initColumns();
this.initGroupColumns();
this.initColumnWidthByColumnResize();
// 排除首次
if (newVal != oldVal && oldVal) {
this.columnsOptionResetTime++;
// 需要等待 initColumns 和 initGroupColumns 先执行
this.initScrolling();
}
},
immediate: true,
},
cloneColumns: {
handler() {
this.initGroupColumns();
// 右键(取消)固定列会操作 cloneColumns
this.initColumnWidthByColumnResize();
this.columnsOptionResetTime++;
// 需要等待 initColumns 和 initGroupColumns 先执行
this.initScrolling();
},
immediate: false,
},
// group columns change watch
groupColumns: {
handler(val) {
if (!isEmptyArray(val)) {
this.initHeaderRows();
}
},
immediate: true,
},
// footer data
footerData: {
handler(val) {
if (!isEmptyArray(val)) {
this.initFooterRows();
}
},
immediate: true,
},
/*
watch virtualScrollOption enable
允许按需开启虚拟滚动
*/
"virtualScrollOption.enable": {
handler(newVal) {
// enable virtual scroll
if (newVal) {
this.initVirtualScrollPositions();
this.initVirtualScroll();
}
// disable virtual scroll
else {
// clear table content top value
this.setTableContentTopValue({ top: 0 });
}
},
immediate: false,
},
// is auto fill starting
isAutofillStarting: {
handler(val) {
if (!val) {
this.setCellSelectionByAutofill();
this.clearCellSelectionAutofillEndCell();
}
},
},
// watch current cell
"cellSelectionData.currentCell": {
handler: function () {
this.setCurrentCellSelectionType();
},
deep: true,
immediate: true,
},
// watch normal end cell
"cellSelectionData.normalEndCell": {
handler: function () {
this.setCurrentCellSelectionType();
},
deep: true,
immediate: true,
},
// watch header indicator colKeys
headerIndicatorColKeys: {
handler: function () {
this.setRangeCellSelectionByHeaderIndicator();
},
deep: true,
},
// watch body indicator rowKeys
bodyIndicatorRowKeys: {
handler: function () {
this.setRangeCellSelectionByBodyIndicator();
},
deep: true,
},
},
methods: {
// int header rows
initHeaderRows() {
const { groupColumns } = this;
if (Array.isArray(groupColumns)) {
this.headerRows = groupColumns.map(() => {
return { rowHeight: 0 };
});
}
},
// int footer rows
initFooterRows() {
const { footerData } = this;
if (Array.isArray(footerData)) {
this.footerRows = footerData.map(() => {
return { rowHeight: 0 };
});
}
},
// header tr height resize
headerRowHeightChange({ rowIndex, height }) {
this.headerRows.splice(rowIndex, 1, { rowHeight: height });
},
// footer row height resize
footRowHeightChange({ rowIndex, height }) {
this.footerRows.splice(rowIndex, 1, { rowHeight: height });
},
// body cell width change
bodyCellWidthChange(colWidths) {
this.colgroups = this.colgroups.map((item) => {
item._realTimeWidth = colWidths.get(item.key);
return item;
});
this.hooks.triggerHook(HOOKS_NAME.TABLE_CELL_WIDTH_CHANGE);
},
// set column width for column resize
setColumnWidth({ colKey, width }) {
this.colgroups = this.colgroups.map((item) => {
if (item.key === colKey) {
item._columnResizeWidth = width;
}
return item;
});
this.$nextTick(() => {
this.setScrollBarStatus();
});
this.hooks.triggerHook(HOOKS_NAME.TABLE_CELL_WIDTH_CHANGE);
},
// update colgroups by sort change
updateColgroupsBySortChange(sortColumns) {
this.colgroups = this.colgroups.map((item) => {
// update colgroups by sort columns
if (Object.keys(sortColumns).indexOf(item.field) > -1) {
item.sortBy = sortColumns[item.field];
}
return item;
});
},
// init column width by column resize
initColumnWidthByColumnResize() {
const { enableColumnResize } = this;
const columnDefaultWidth = 50;
if (enableColumnResize) {
this.colgroups = this.colgroups.map((item) => {
let columnWidth = columnDefaultWidth;
if (isNumber(item.width)) {
columnWidth = item.width;
}
item._columnResizeWidth = columnWidth;
return item;
});
}
},
// init columns
initColumns() {
const { columnHiddenOption } = this;
if (columnHiddenOption) {
const { defaultHiddenColumnKeys } = columnHiddenOption;
if (!isEmptyArray(defaultHiddenColumnKeys)) {
this.hiddenColumns = defaultHiddenColumnKeys;
}
}
this.showOrHideColumns();
},
// show or hide columns
showOrHideColumns() {
let cloneColumns = cloneDeep(this.columns);
cloneColumns = cloneColumns.map((col) => {
// 操作列默认左固定
if (col.operationColumn) {
col.fixed = COLUMN_FIXED_TYPE.LEFT;
}
return col;
});
const { hiddenColumns } = this;
if (!isEmptyArray(hiddenColumns)) {
// recursive remove column key
hiddenColumns.forEach((key) => {
cloneColumns = recursiveRemoveColumnByKey(
cloneColumns,
key,
);
});
}
this.cloneColumns = cloneColumns;
},
// 初始化分组表头
initGroupColumns() {
const result = initGroupColumns(this.cloneColumns);
// set is group header
this.isGroupHeader = result.isGroupHeader;
// set colgroups
this.colgroups = result.colgroups;
// set groupColumns
this.groupColumns = result.groupColumns;
},
// scroll bar width
getScrollBarWidth() {
let result = 0;
const { scrollBarWidth } = this;
if (scrollBarWidth) {
result = scrollBarWidth;
} else {
result = getScrollbarWidth();
this.scrollBarWidth = result;
}
return result;
},
/*
* @selectedAllChange
* @desc selected all change
* @param {bool} isSelected - is selected
*/
selectedAllChange({ isSelected }) {
this.broadcast(
COMPS_NAME.VE_TABLE_BODY,
EMIT_EVENTS.CHECKBOX_SELECTED_ALL_CHANGE,
{
isSelected,
},
);
},
/*
* @setSelectedAllInfo
* @desc set selected all info
* @param {bool} isSelected - is selected
* @param {bool} isIndeterminate - is indeterminate
*/
setSelectedAllInfo({ isSelected, isIndeterminate }) {
this.broadcast(
COMPS_NAME.VE_TABLE_HEADER_CHECKBOX_CONTENT,
EMIT_EVENTS.CHECKBOX_SELECTED_ALL_INFO,
{
isSelected,
isIndeterminate,
},
);
},
// cell selection current cell change
cellSelectionCurrentCellChange({ rowKey, colKey }) {
this.cellSelectionData.currentCell.colKey = colKey;
this.cellSelectionData.currentCell.rowKey = rowKey;
this.cellSelectionData.currentCell.rowIndex =
this.allRowKeys.indexOf(rowKey);
},
// cell selection end cell change
cellSelectionNormalEndCellChange({ rowKey, colKey }) {
this.cellSelectionData.normalEndCell.colKey = colKey;
this.cellSelectionData.normalEndCell.rowKey = rowKey;
this.cellSelectionData.normalEndCell.rowIndex =
this.allRowKeys.indexOf(rowKey);
},
// cell selection auto fill cell change
cellSelectionAutofillCellChange({ rowKey, colKey }) {
this.cellSelectionData.autoFillEndCell.colKey = colKey;
this.cellSelectionData.autoFillEndCell.rowKey = rowKey;
},
// clear cell selection current cell
clearCellSelectionCurrentCell() {
this.cellSelectionCurrentCellChange({
rowKey: "",
colKey: "",
rowIndex: -1,
});
},
// clear cell selection normal end cell
clearCellSelectionNormalEndCell() {
this.cellSelectionNormalEndCellChange({
rowKey: "",
colKey: "",
rowIndex: -1,
});
},
// clear cell selection autofill end cell
clearCellSelectionAutofillEndCell() {
this.cellSelectionAutofillCellChange({ rowKey: "", colKey: "" });
},
// header indicator colKeys change
headerIndicatorColKeysChange({ startColKey, endColKey }) {
const { colgroups } = this;
this.headerIndicatorColKeys.startColKey = startColKey;
this.headerIndicatorColKeys.startColKeyIndex = colgroups.findIndex(
(x) => x.key === startColKey,
);
this.headerIndicatorColKeys.endColKey = endColKey;
this.headerIndicatorColKeys.endColKeyIndex = colgroups.findIndex(
(x) => x.key === endColKey,
);
},
// clear header indicator colKeys
clearHeaderIndicatorColKeys() {
this.headerIndicatorColKeys.startColKey = "";
this.headerIndicatorColKeys.startColKeyIndex = -1;
this.headerIndicatorColKeys.endColKey = "";
this.headerIndicatorColKeys.endColKeyIndex = -1;
},
// body indicator rowKeys change
bodyIndicatorRowKeysChange({ startRowKey, endRowKey }) {
const { allRowKeys } = this;
this.bodyIndicatorRowKeys.startRowKey = startRowKey;
this.bodyIndicatorRowKeys.startRowKeyIndex =
allRowKeys.indexOf(startRowKey);
this.bodyIndicatorRowKeys.endRowKey = endRowKey;
this.bodyIndicatorRowKeys.endRowKeyIndex =
allRowKeys.indexOf(endRowKey);
},
// clear body indicator RowKeys
clearBodyIndicatorRowKeys() {
this.bodyIndicatorRowKeys.startRowKey = "";
this.bodyIndicatorRowKeys.startRowKeyIndex = -1;
this.bodyIndicatorRowKeys.endRowKey = "";
this.bodyIndicatorRowKeys.endRowKeyIndex = -1;
},
// set cell selection by autofill
setCellSelectionByAutofill() {
const {
cellAutofillOption,
cellSelectionRangeData,
colgroups,
allRowKeys,
autofillingDirection,
currentCellSelectionType,
} = this;
const { autoFillEndCell, currentCell } = this.cellSelectionData;
const { rowKey, colKey } = autoFillEndCell;
if (isEmptyValue(rowKey) || isEmptyValue(colKey)) {
return false;
}
let currentCellData = {};
let normalEndCellData = {};
const { leftColKey, rightColKey, topRowKey, bottomRowKey } =
cellSelectionRangeData;
// cell selection range auto fill
if (
currentCellSelectionType === CURRENT_CELL_SELECTION_TYPES.RANGE
) {
if (
!isCellInSelectionRange({
cellData: autoFillEndCell,
cellSelectionRangeData,
colgroups,
allRowKeys,
})
) {
if (autofillingDirection === AUTOFILLING_DIRECTION.RIGHT) {
currentCellData = {
rowKey: topRowKey,
colKey: leftColKey,
};
normalEndCellData = { rowKey: bottomRowKey, colKey };
} else if (
autofillingDirection === AUTOFILLING_DIRECTION.DOWN
) {
currentCellData = {
rowKey: topRowKey,
colKey: leftColKey,
};
normalEndCellData = { rowKey, colKey: rightColKey };
} else if (
autofillingDirection === AUTOFILLING_DIRECTION.UP
) {
currentCellData = {
rowKey,
colKey: leftColKey,
};
normalEndCellData = {
rowKey: bottomRowKey,
colKey: rightColKey,
};
} else if (
autofillingDirection === AUTOFILLING_DIRECTION.LEFT
) {
currentCellData = { rowKey: topRowKey, colKey };
normalEndCellData = {
rowKey: bottomRowKey,
colKey: rightColKey,
};
}
} else {
// return if within the range
return false;
}
}
// cell selection single auto fill
else if (
currentCellSelectionType === CURRENT_CELL_SELECTION_TYPES.SINGLE
) {
if (
currentCell.rowKey !== rowKey ||
currentCell.colKey !== colKey
) {
if (autofillingDirection === AUTOFILLING_DIRECTION.RIGHT) {
currentCellData = {
rowKey,
colKey: leftColKey,
};
normalEndCellData = {
rowKey,
colKey,
};
} else if (
autofillingDirection === AUTOFILLING_DIRECTION.DOWN
) {
currentCellData = {
rowKey: topRowKey,
colKey: leftColKey,
};
normalEndCellData = {
rowKey,
colKey: leftColKey,
};
} else if (
autofillingDirection === AUTOFILLING_DIRECTION.UP
) {
currentCellData = {
rowKey,
colKey: leftColKey,
};
normalEndCellData = {
rowKey: bottomRowKey,
colKey: leftColKey,
};
} else if (
autofillingDirection === AUTOFILLING_DIRECTION.LEFT
) {
currentCellData = {
rowKey,
colKey,
};
normalEndCellData = {
rowKey,
colKey: rightColKey,
};
}
} else {
// return if within the range
return false;
}
}
const cellAutofillParams = {
tableData: this.tableData,
allRowKeys: this.allRowKeys,
colgroups: this.colgroups,
rowKeyFieldName: this.rowKeyFieldName,
direction: autofillingDirection,
currentCellSelectionType,
cellSelectionRangeData,
nextCurrentCell: currentCellData,
nextNormalEndCell: normalEndCellData,
};
if (cellAutofillOption) {
const { beforeAutofill, afterAutofill } = cellAutofillOption;
if (isFunction(beforeAutofill)) {
// before autofill
const autofillResponse = cellAutofill({
isReplaceData: false,
...cellAutofillParams,
});
const callback = beforeAutofill(autofillResponse);
if (isBoolean(callback) && !callback) {
return false;
}
}
// after autofill
const autofillResponse = cellAutofill({
isReplaceData: true,
...cellAutofillParams,
});
if (isFunction(afterAutofill)) {
afterAutofill(autofillResponse);
}
}
if (!isEmptyValue(currentCellData.rowKey)) {
this.cellSelectionCurrentCellChange({
rowKey: currentCellData.rowKey,
colKey: currentCellData.colKey,
});
}
if (!isEmptyValue(normalEndCellData.rowKey)) {
this.cellSelectionNormalEndCellChange({
rowKey: normalEndCellData.rowKey,
colKey: normalEndCellData.colKey,
});
}
},
// cell selection range data change
cellSelectionRangeDataChange(newData) {
this.cellSelectionRangeData = Object.assign(
this.cellSelectionRangeData,
newData,
);
},
// autofilling direction change
autofillingDirectionChange(direction) {
this.autofillingDirection = direction;
},
// set current cell selection type
setCurrentCellSelectionType() {
const { currentCell, normalEndCell } = this.cellSelectionData;
let result;
if (
isEmptyValue(currentCell.rowKey) ||
isEmptyValue(currentCell.colKey)
) {
result = "";
} else {
if (
!isEmptyValue(normalEndCell.rowKey) &&
!isEmptyValue(normalEndCell.colKey)
) {
result = CURRENT_CELL_SELECTION_TYPES.RANGE;
} else {
result = CURRENT_CELL_SELECTION_TYPES.SINGLE;
}
}
this.currentCellSelectionType = result;
},
// deal keydown event
dealKeydownEvent(event) {
const {
colgroups,
cellSelectionData,
enableStopEditing,
isCellEditing,
} = this;
const { keyCode, ctrlKey, shiftKey, altKey } = event;
const { rowKey, colKey } = cellSelectionData.currentCell;
const currentColumn = colgroups.find((x) => x.key === colKey);
if (!isEmptyValue(rowKey) && !isEmptyValue(colKey)) {
switch (keyCode) {
case KEY_CODES.TAB: {
let direction;
if (shiftKey) {
direction = CELL_SELECTION_DIRECTION.LEFT;
} else {
direction = CELL_SELECTION_DIRECTION.RIGHT;
}
this.selectCellByDirection({
direction,
});
this.clearCellSelectionNormalEndCell();
this[INSTANCE_METHODS.STOP_EDITING_CELL]();
event.preventDefault();
break;
}
case KEY_CODES.ARROW_LEFT: {
const direction = CELL_SELECTION_DIRECTION.LEFT;
if (enableStopEditing) {
this.selectCellByDirection({
direction,
});
this.clearCellSelectionNormalEndCell();
this[INSTANCE_METHODS.STOP_EDITING_CELL]();
event.preventDefault();
}
break;
}
case KEY_CODES.ARROW_RIGHT: {
const direction = CELL_SELECTION_DIRECTION.RIGHT;
if (enableStopEditing) {
this.selectCellByDirection({
direction,
});
this.clearCellSelectionNormalEndCell();
this[INSTANCE_METHODS.STOP_EDITING_CELL]();
event.preventDefault();
}
break;
}
case KEY_CODES.ARROW_UP: {
const direction = CELL_SELECTION_DIRECTION.UP;
if (enableStopEditing) {
this.selectCellByDirection({
direction,
});
this.clearCellSelectionNormalEndCell();
this[INSTANCE_METHODS.STOP_EDITING_CELL]();
event.preventDefault();
}
break;
}
case KEY_CODES.ARROW_DOWN: {
const direction = CELL_SELECTION_DIRECTION.DOWN;
if (enableStopEditing) {
this.selectCellByDirection({
direction,
});
this.clearCellSelectionNormalEndCell();
this[INSTANCE_METHODS.STOP_EDITING_CELL]();
event.preventDefault();
}
break;
}
case KEY_CODES.ENTER: {
let direction;
// add new line
if (altKey) {
const editInputEditor =
this.$refs[this.editInputRef];