@visactor/vue-vtable
Version:
The vue version of VTable
219 lines (215 loc) • 8.14 kB
JavaScript
'use strict';
var vutils = require('@visactor/vutils');
var vue = require('vue');
var VTable = require('@visactor/vtable');
/**
* @description: 自定义渲染式编辑器
*/
class DynamicRenderEditor {
constructor(currentContext) {
this.currentContext = currentContext;
this.tableContainer = null;
this.currentValue = null;
this.wrapContainer = null;
this.nodeMap = new Map();
}
registerNode(tableId, key, getNode) {
if (!vutils.isValid(tableId) || !vutils.isValid(key) || typeof getNode !== 'function') {
return;
}
if (!this.nodeMap.has(tableId)) {
this.nodeMap.set(tableId, new Map());
}
this.nodeMap.get(tableId).set(key, getNode);
}
getNode(tableId, key) {
var _a;
return (_a = this.nodeMap.get(tableId)) === null || _a === void 0 ? void 0 : _a.get(key);
}
removeNode(tableId) {
this.nodeMap.delete(tableId);
}
release(tableId) {
if (!vutils.isValid(tableId)) {
this.nodeMap.clear();
}
else {
this.removeNode(tableId);
}
}
async onStart(editorContext) {
const { value } = editorContext;
// 先设置初始值(因为校验不通过也会走正常流程)
this.setValue(value);
if (!(await this.createElement(editorContext))) {
return;
}
}
async createElement(editorContext) {
const { row, col, value, table, container, referencePosition } = editorContext;
if (!container) {
return false;
}
const define = table.getBodyColumnDefine(col, row);
const { editConfig } = define || {};
const { id } = table;
const key = this.getColumnKeyField(define);
if (!vutils.isValid(key) || !vutils.isValid(id)) {
return false;
}
if (typeof (editConfig === null || editConfig === void 0 ? void 0 : editConfig.editBefore) === 'function') {
// 编辑前校验
const v = await editConfig.editBefore(editorContext);
if (!v) {
table.showTooltip(col, row, {
// TODO 多语言
content: editConfig.disablePrompt || 'This field is not allowed to be edited',
referencePosition: { rect: referencePosition === null || referencePosition === void 0 ? void 0 : referencePosition.rect, placement: VTable.TYPES.Placement.top },
style: {
bgColor: 'black',
color: 'white',
arrowMark: true
},
disappearDelay: 1000
});
return false;
}
}
const record = table === null || table === void 0 ? void 0 : table.getCellOriginRecord(col, row);
const renderVNodeFn = this.getNode(id, key);
if (!renderVNodeFn) {
return false;
}
const vnode = vue.h(renderVNodeFn, {
row,
col,
value,
refValue: vue.customRef((track, trigger) => {
return {
get: () => {
track();
return this.getValue();
},
set: value => {
this.setValue(value);
trigger();
}
};
}),
record,
table,
onChange: (value) => this.setValue(value)
});
if (!vnode || !vue.isVNode(vnode)) {
return false;
}
this.checkToPassAppContext(vnode, table);
// 创建包裹容器
const wrapContainer = document.createElement('div');
wrapContainer.style.position = 'absolute';
wrapContainer.style.width = '100%';
wrapContainer.style.boxSizing = 'border-box';
const { bgColor } = table.getCellStyle(col, row) || {};
wrapContainer.style.backgroundColor = bgColor || '#FFFFFF';
this.wrapContainer = wrapContainer;
this.tableContainer = container;
this.tableContainer.appendChild(wrapContainer);
vue.render(vnode, wrapContainer);
// 位置同步
if (referencePosition === null || referencePosition === void 0 ? void 0 : referencePosition.rect) {
this.adjustPosition(referencePosition.rect);
}
return true;
}
/**
* @description: 校验并传递上下文
* @param {VNode} vnode
* @param {any} table
* @return {*}
*/
checkToPassAppContext(vnode, table) {
var _a, _b, _c, _d;
try {
const userAppContext = (_d = (_c = (_b = (_a = table.options) === null || _a === void 0 ? void 0 : _a.customConfig) === null || _b === void 0 ? void 0 : _b.getVueUserAppContext) === null || _c === void 0 ? void 0 : _c.call(_b)) !== null && _d !== void 0 ? _d : this.currentContext;
// 简单校验合法性
if (!!(userAppContext === null || userAppContext === void 0 ? void 0 : userAppContext.components) && !!(userAppContext === null || userAppContext === void 0 ? void 0 : userAppContext.directives)) {
vnode.appContext = userAppContext;
}
}
catch (error) { }
}
/**
* @description: 获取渲染式编辑器的列配置主键
* @param {any} column
* @return {*}
*/
getColumnKeyField(column) {
const { field, key } = column || {};
// 兼容取 field
return vutils.isValid(key) ? key : field;
}
getValue() {
return this.currentValue;
}
setValue(value) {
this.currentValue = value;
}
adjustPosition(rect) {
if (this.wrapContainer) {
this.wrapContainer.style.top = `${rect.top}px`;
this.wrapContainer.style.left = `${rect.left}px`;
this.wrapContainer.style.width = `${rect.width}px`;
this.wrapContainer.style.height = `${rect.height}px`;
}
}
async validateValue(value, oldValue, editCell, table) {
const { col, row } = editCell || {};
if (!vutils.isValid(col) || !vutils.isValid(row)) {
return true;
}
const define = table.getBodyColumnDefine(col, row);
const { editConfig } = define || {};
if (typeof (editConfig === null || editConfig === void 0 ? void 0 : editConfig.validateValue) === 'function') {
const validate = await editConfig.validateValue({ col, row, value, oldValue, table });
if (validate === false) {
const rect = table.getVisibleCellRangeRelativeRect({ col, row });
table.showTooltip(col, row, {
content: editConfig.invalidPrompt || 'invalid',
referencePosition: { rect, placement: VTable.TYPES.Placement.top },
style: {
bgColor: 'red',
color: 'white',
arrowMark: true
},
disappearDelay: 1000
});
return false;
}
return validate;
}
return true;
}
onEnd() {
if (this.wrapContainer && this.tableContainer) {
vue.render(null, this.wrapContainer);
this.tableContainer.removeChild(this.wrapContainer);
}
this.wrapContainer = null;
this.tableContainer = null;
}
isEditorElement(target) {
var _a;
return ((_a = this.wrapContainer) === null || _a === void 0 ? void 0 : _a.contains(target)) || this.isClickEditorElement(target);
}
isClickEditorElement(target) {
while (target) {
// 约定的类名
if (target.classList && target.classList.contains('table-editor-element')) {
return true;
}
target = target.parentNode;
}
return false;
}
}
exports.DynamicRenderEditor = DynamicRenderEditor;