224 lines
6.9 KiB
TypeScript
224 lines
6.9 KiB
TypeScript
import {
|
|
IPublicEnumContextMenuType,
|
|
IPublicEnumDragObjectType,
|
|
IPublicEnumTransformStage,
|
|
IPublicModelNode,
|
|
IPublicModelPluginContext,
|
|
IPublicTypeDragNodeDataObject,
|
|
IPublicTypeNodeSchema,
|
|
} from '@alilc/lowcode-types';
|
|
import { isProjectSchema } from '@alilc/lowcode-utils';
|
|
import { Message } from '@alifd/next';
|
|
import { intl } from '../locale';
|
|
|
|
function getNodesSchema(nodes: IPublicModelNode[]) {
|
|
const componentsTree = nodes.map((node) => node?.exportSchema(IPublicEnumTransformStage.Clone));
|
|
const data = { type: 'nodeSchema', componentsMap: {}, componentsTree };
|
|
return data;
|
|
}
|
|
|
|
async function getClipboardText(): Promise<IPublicTypeNodeSchema[]> {
|
|
return new Promise((resolve, reject) => {
|
|
// 使用 Clipboard API 读取剪贴板内容
|
|
navigator.clipboard.readText().then(
|
|
(text) => {
|
|
try {
|
|
const data = JSON.parse(text);
|
|
if (isProjectSchema(data)) {
|
|
resolve(data.componentsTree);
|
|
} else {
|
|
Message.error(intl('NotValidNodeData'));
|
|
reject(
|
|
new Error(intl('NotValidNodeData')),
|
|
);
|
|
}
|
|
} catch (error) {
|
|
Message.error(intl('NotValidNodeData'));
|
|
reject(error);
|
|
}
|
|
},
|
|
(err) => {
|
|
reject(err);
|
|
},
|
|
);
|
|
});
|
|
}
|
|
|
|
export const defaultContextMenu = (ctx: IPublicModelPluginContext) => {
|
|
const { material, canvas, common } = ctx;
|
|
const { clipboard } = canvas;
|
|
const { intl: utilsIntl } = common.utils;
|
|
|
|
return {
|
|
init() {
|
|
material.addContextMenuOption({
|
|
name: 'selectComponent',
|
|
title: intl('SelectComponents'),
|
|
condition: (nodes = []) => {
|
|
return nodes.length === 1;
|
|
},
|
|
items: [
|
|
{
|
|
name: 'nodeTree',
|
|
type: IPublicEnumContextMenuType.NODE_TREE,
|
|
},
|
|
],
|
|
});
|
|
|
|
material.addContextMenuOption({
|
|
name: 'copyAndPaste',
|
|
title: intl('CopyAndPaste'),
|
|
disabled: (nodes = []) => {
|
|
return nodes?.filter((node) => !node?.canPerformAction('copy')).length > 0;
|
|
},
|
|
condition: (nodes) => {
|
|
return nodes?.length === 1;
|
|
},
|
|
action(nodes) {
|
|
const node = nodes?.[0];
|
|
if (!node) {
|
|
return;
|
|
}
|
|
const { document: doc, parent, index } = node;
|
|
const data = getNodesSchema(nodes);
|
|
clipboard.setData(data);
|
|
|
|
if (parent) {
|
|
const newNode = doc?.insertNode(parent, node, (index ?? 0) + 1, true);
|
|
newNode?.select();
|
|
}
|
|
},
|
|
});
|
|
|
|
material.addContextMenuOption({
|
|
name: 'copy',
|
|
title: intl('Copy'),
|
|
disabled: (nodes = []) => {
|
|
return nodes?.filter((node) => !node?.canPerformAction('copy')).length > 0;
|
|
},
|
|
condition(nodes = []) {
|
|
return nodes?.length > 0;
|
|
},
|
|
action(nodes) {
|
|
if (!nodes || nodes.length < 1) {
|
|
return;
|
|
}
|
|
|
|
const data = getNodesSchema(nodes);
|
|
clipboard.setData(data);
|
|
},
|
|
});
|
|
|
|
material.addContextMenuOption({
|
|
name: 'pasteToBottom',
|
|
title: intl('PasteToTheBottom'),
|
|
condition: (nodes) => {
|
|
return nodes?.length === 1;
|
|
},
|
|
async action(nodes) {
|
|
if (!nodes || nodes.length < 1) {
|
|
return;
|
|
}
|
|
|
|
const node = nodes[0];
|
|
const { document: doc, parent, index } = node;
|
|
|
|
try {
|
|
const nodeSchema = await getClipboardText();
|
|
if (nodeSchema.length === 0) {
|
|
return;
|
|
}
|
|
if (parent) {
|
|
let canAddNodes = nodeSchema.filter((nodeSchema: IPublicTypeNodeSchema) => {
|
|
const dragNodeObject: IPublicTypeDragNodeDataObject = {
|
|
type: IPublicEnumDragObjectType.NodeData,
|
|
data: nodeSchema,
|
|
};
|
|
return doc?.checkNesting(parent, dragNodeObject);
|
|
});
|
|
if (canAddNodes.length === 0) {
|
|
Message.error(`${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(parent.title || parent.componentName as any)}内`);
|
|
return;
|
|
}
|
|
const nodes: IPublicModelNode[] = [];
|
|
canAddNodes.forEach((schema, schemaIndex) => {
|
|
const node = doc?.insertNode(parent, schema, (index ?? 0) + 1 + schemaIndex, true);
|
|
node && nodes.push(node);
|
|
});
|
|
doc?.selection.selectAll(nodes.map((node) => node?.id));
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
},
|
|
});
|
|
|
|
material.addContextMenuOption({
|
|
name: 'pasteToInner',
|
|
title: intl('PasteToTheInside'),
|
|
condition: (nodes) => {
|
|
return nodes?.length === 1;
|
|
},
|
|
disabled: (nodes = []) => {
|
|
// 获取粘贴数据
|
|
const node = nodes?.[0];
|
|
return !node.isContainerNode;
|
|
},
|
|
async action(nodes) {
|
|
const node = nodes?.[0];
|
|
if (!node) {
|
|
return;
|
|
}
|
|
const { document: doc } = node;
|
|
|
|
try {
|
|
const nodeSchema = await getClipboardText();
|
|
const index = node.children?.size || 0;
|
|
if (nodeSchema.length === 0) {
|
|
return;
|
|
}
|
|
let canAddNodes = nodeSchema.filter((nodeSchema: IPublicTypeNodeSchema) => {
|
|
const dragNodeObject: IPublicTypeDragNodeDataObject = {
|
|
type: IPublicEnumDragObjectType.NodeData,
|
|
data: nodeSchema,
|
|
};
|
|
return doc?.checkNesting(node, dragNodeObject);
|
|
});
|
|
if (canAddNodes.length === 0) {
|
|
Message.error(`${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(node.title || node.componentName as any)}内`);
|
|
return;
|
|
}
|
|
|
|
const nodes: IPublicModelNode[] = [];
|
|
nodeSchema.forEach((schema, schemaIndex) => {
|
|
const newNode = doc?.insertNode(node, schema, (index ?? 0) + 1 + schemaIndex, true);
|
|
newNode && nodes.push(newNode);
|
|
});
|
|
doc?.selection.selectAll(nodes.map((node) => node?.id));
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
},
|
|
});
|
|
|
|
material.addContextMenuOption({
|
|
name: 'delete',
|
|
title: intl('Delete'),
|
|
disabled(nodes = []) {
|
|
return nodes?.filter((node) => !node?.canPerformAction('remove')).length > 0;
|
|
},
|
|
condition(nodes = []) {
|
|
return nodes.length > 0;
|
|
},
|
|
action(nodes) {
|
|
nodes?.forEach((node) => {
|
|
node.remove();
|
|
});
|
|
},
|
|
});
|
|
},
|
|
};
|
|
};
|
|
|
|
defaultContextMenu.pluginName = '___default_context_menu___';
|