feat(脑图): 快捷键优化&交互优化
This commit is contained in:
parent
40445cb4c5
commit
748b4e93e4
|
@ -13,6 +13,7 @@
|
||||||
:can-show-enter-node="canShowEnterNode"
|
:can-show-enter-node="canShowEnterNode"
|
||||||
:can-show-more-menu-node-operation="false"
|
:can-show-more-menu-node-operation="false"
|
||||||
:more-menu-other-operation-list="canShowFloatMenu ? moreMenuOtherOperationList : []"
|
:more-menu-other-operation-list="canShowFloatMenu ? moreMenuOtherOperationList : []"
|
||||||
|
:shortcut-list="['expand']"
|
||||||
disabled
|
disabled
|
||||||
@node-select="handleNodeSelect"
|
@node-select="handleNodeSelect"
|
||||||
@node-unselect="handleNodeUnselect"
|
@node-unselect="handleNodeUnselect"
|
||||||
|
@ -93,6 +94,16 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<template #shortCutList>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem">
|
||||||
|
<div>{{ t('common.pass') }}</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem-icon ms-minder-shortcut-trigger-listitem-icon-auto"> P </div>
|
||||||
|
</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem">
|
||||||
|
<div>{{ t('common.unPass') }}</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem-icon ms-minder-shortcut-trigger-listitem-icon-auto"> R </div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</MsMinderEditor>
|
</MsMinderEditor>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -191,7 +202,7 @@
|
||||||
data: {
|
data: {
|
||||||
...e.data,
|
...e.data,
|
||||||
id: e.id || e.data?.id || '',
|
id: e.id || e.data?.id || '',
|
||||||
text: e.name || e.data?.text || '',
|
text: e.name || e.data?.text.replace(/<\/?p\b[^>]*>/gi, '') || '',
|
||||||
resource: modulesCount.value[e.id] !== undefined ? [moduleTag] : e.data?.resource,
|
resource: modulesCount.value[e.id] !== undefined ? [moduleTag] : e.data?.resource,
|
||||||
expandState: e.level === 0 ? 'expand' : 'collapse',
|
expandState: e.level === 0 ? 'expand' : 'collapse',
|
||||||
count: modulesCount.value[e.id],
|
count: modulesCount.value[e.id],
|
||||||
|
|
|
@ -68,6 +68,28 @@
|
||||||
<caseCommentList v-else-if="activeExtraKey === 'comments'" :active-case="activeCase" />
|
<caseCommentList v-else-if="activeExtraKey === 'comments'" :active-case="activeCase" />
|
||||||
<bugList v-else :active-case="activeCase" />
|
<bugList v-else :active-case="activeCase" />
|
||||||
</template>
|
</template>
|
||||||
|
<template #shortCutList>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem">
|
||||||
|
<div>{{ t('ms.minders.createSiblingModule') }}</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem-icon ms-minder-shortcut-trigger-listitem-icon-auto"> M </div>
|
||||||
|
</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem">
|
||||||
|
<div>{{ t('ms.minders.createSiblingCase') }}</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem-icon ms-minder-shortcut-trigger-listitem-icon-auto"> C </div>
|
||||||
|
</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem">
|
||||||
|
<div>{{ t('ms.minders.createChildModule') }}</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem-icon ms-minder-shortcut-trigger-listitem-icon-auto">
|
||||||
|
Shift + M
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem">
|
||||||
|
<div>{{ t('ms.minders.createChildCase') }}</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem-icon ms-minder-shortcut-trigger-listitem-icon-auto">
|
||||||
|
Shift + C
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</MsMinderEditor>
|
</MsMinderEditor>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -76,6 +98,7 @@
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
|
import useShortCut from '@/components/pure/ms-minder-editor/hooks/useShortCut';
|
||||||
import MsMinderEditor from '@/components/pure/ms-minder-editor/minderEditor.vue';
|
import MsMinderEditor from '@/components/pure/ms-minder-editor/minderEditor.vue';
|
||||||
import type { MinderJson, MinderJsonNode, MinderJsonNodeData } from '@/components/pure/ms-minder-editor/props';
|
import type { MinderJson, MinderJsonNode, MinderJsonNodeData } from '@/components/pure/ms-minder-editor/props';
|
||||||
import {
|
import {
|
||||||
|
@ -181,7 +204,7 @@
|
||||||
data: {
|
data: {
|
||||||
...e.data,
|
...e.data,
|
||||||
id: e.id || e.data?.id || '',
|
id: e.id || e.data?.id || '',
|
||||||
text: e.name || e.data?.text || '',
|
text: e.name || e.data?.text.replace(/<\/?p\b[^>]*>/gi, '') || '',
|
||||||
resource: props.modulesCount[e.id] !== undefined ? [moduleTag] : e.data?.resource,
|
resource: props.modulesCount[e.id] !== undefined ? [moduleTag] : e.data?.resource,
|
||||||
expandState: e.level === 0 ? 'expand' : 'collapse',
|
expandState: e.level === 0 ? 'expand' : 'collapse',
|
||||||
count: props.modulesCount[e.id],
|
count: props.modulesCount[e.id],
|
||||||
|
@ -634,6 +657,28 @@
|
||||||
setPriorityView(true, 'P');
|
setPriorityView(true, 'P');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { unbindShortcuts } = useShortCut(
|
||||||
|
{
|
||||||
|
addChildModule: () => {
|
||||||
|
const node: MinderJsonNode = window.minder.getSelectedNode();
|
||||||
|
insertNode(node, 'AppendChildNode', moduleTag);
|
||||||
|
},
|
||||||
|
addChildCase: () => {
|
||||||
|
const node: MinderJsonNode = window.minder.getSelectedNode();
|
||||||
|
insertNode(node, 'AppendChildNode', caseTag);
|
||||||
|
},
|
||||||
|
addSiblingModule: () => {
|
||||||
|
const node: MinderJsonNode = window.minder.getSelectedNode();
|
||||||
|
insertNode(node, 'AppendSiblingNode', moduleTag);
|
||||||
|
},
|
||||||
|
addSiblingCase: () => {
|
||||||
|
const node: MinderJsonNode = window.minder.getSelectedNode();
|
||||||
|
insertNode(node, 'AppendSiblingNode', caseTag);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 标签编辑后,如果将标签修改为模块,则删除已添加的优先级
|
* 标签编辑后,如果将标签修改为模块,则删除已添加的优先级
|
||||||
* @param node 选中节点
|
* @param node 选中节点
|
||||||
|
@ -953,6 +998,10 @@
|
||||||
deep: true,
|
deep: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
unbindShortcuts();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
export default {
|
|
||||||
'ms.minders.allModule': 'All Modules',
|
|
||||||
'ms.minders.precondition': 'Pre-condition',
|
|
||||||
'ms.minders.stepDesc': 'Step Description',
|
|
||||||
'ms.minders.stepExpect': 'Expected Result',
|
|
||||||
'ms.minders.textDesc': 'Text Description',
|
|
||||||
'ms.minders.remark': 'Remark Information',
|
|
||||||
'ms.minders.caseName': 'Test Case Name',
|
|
||||||
'ms.minders.caseNameNotNull': 'Test Case Name cannot be empty',
|
|
||||||
'ms.minders.commentTotal': '{num} Comments in Total',
|
|
||||||
'ms.minders.text': 'Text',
|
|
||||||
'ms.minders.leaveUnsavedTip': 'The mind map has unsaved changes, are you sure you want to exit?',
|
|
||||||
};
|
|
|
@ -1,13 +0,0 @@
|
||||||
export default {
|
|
||||||
'ms.minders.allModule': '全部模块',
|
|
||||||
'ms.minders.precondition': '前置条件',
|
|
||||||
'ms.minders.stepDesc': '步骤描述',
|
|
||||||
'ms.minders.stepExpect': '预期结果',
|
|
||||||
'ms.minders.textDesc': '文本描述',
|
|
||||||
'ms.minders.remark': '备注信息',
|
|
||||||
'ms.minders.caseName': '用例名称',
|
|
||||||
'ms.minders.caseNameNotNull': '用例名称不能为空',
|
|
||||||
'ms.minders.commentTotal': '共 {num} 评论',
|
|
||||||
'ms.minders.text': '文本',
|
|
||||||
'ms.minders.leaveUnsavedTip': '脑图有未保存的更改,确认离开吗?',
|
|
||||||
};
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import usePriority from '@/components/pure/ms-minder-editor/hooks/useMinderPriority';
|
||||||
import type {
|
import type {
|
||||||
MinderEvent,
|
MinderEvent,
|
||||||
MinderJsonNode,
|
MinderJsonNode,
|
||||||
|
@ -16,6 +17,7 @@ import { getGenerateId } from '@/utils';
|
||||||
export default function useMinderBaseApi({ hasEditPermission }: { hasEditPermission?: boolean }) {
|
export default function useMinderBaseApi({ hasEditPermission }: { hasEditPermission?: boolean }) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const minderStore = useMinderStore();
|
const minderStore = useMinderStore();
|
||||||
|
const { setPriority } = usePriority({ priorityStartWithZero: true, priorityPrefix: 'P' });
|
||||||
|
|
||||||
const caseTag = t('common.case');
|
const caseTag = t('common.case');
|
||||||
const moduleTag = t('common.module');
|
const moduleTag = t('common.module');
|
||||||
|
@ -361,13 +363,33 @@ export default function useMinderBaseApi({ hasEditPermission }: { hasEditPermiss
|
||||||
* @param value 节点类型
|
* @param value 节点类型
|
||||||
*/
|
*/
|
||||||
function insertSpecifyNode(type: string, value: string) {
|
function insertSpecifyNode(type: string, value: string) {
|
||||||
|
const nodeId = getGenerateId();
|
||||||
execInert(type, {
|
execInert(type, {
|
||||||
id: getGenerateId(),
|
id: nodeId,
|
||||||
text: value !== t('ms.minders.text') ? value : '',
|
text: value !== t('ms.minders.text') ? value : '',
|
||||||
resource: value !== t('ms.minders.text') ? [value] : [],
|
resource: value !== t('ms.minders.text') ? [value] : [],
|
||||||
expandState: 'expand',
|
expandState: 'expand',
|
||||||
isNew: true,
|
isNew: true,
|
||||||
|
priority: value === caseTag ? 1 : undefined,
|
||||||
});
|
});
|
||||||
|
if (value === caseTag) {
|
||||||
|
// 用例节点插入后,插入子节点
|
||||||
|
setPriority('1');
|
||||||
|
nextTick(() => {
|
||||||
|
insertSpecifyNode('AppendChildNode', prerequisiteTag);
|
||||||
|
// 上面插入了子节点前置条件后会选中该节点,所以下面插入同级
|
||||||
|
insertSpecifyNode('AppendSiblingNode', stepTag);
|
||||||
|
insertSpecifyNode('AppendChildNode', stepExpectTag);
|
||||||
|
window.minder.selectById(nodeId);
|
||||||
|
insertSpecifyNode('AppendChildNode', remarkTag);
|
||||||
|
nextTick(() => {
|
||||||
|
// 取消选中备注节点,选中用例节点
|
||||||
|
const remarkNode: MinderJsonNode = window.minder.getSelectedNode();
|
||||||
|
window.minder.toggleSelect(remarkNode);
|
||||||
|
window.minder.selectById(nodeId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,4 +1,21 @@
|
||||||
export default {
|
export default {
|
||||||
|
// 功能用例脑图文案
|
||||||
|
'ms.minders.allModule': 'All Modules',
|
||||||
|
'ms.minders.precondition': 'Pre-condition',
|
||||||
|
'ms.minders.stepDesc': 'Step Description',
|
||||||
|
'ms.minders.stepExpect': 'Expected Result',
|
||||||
|
'ms.minders.textDesc': 'Text Description',
|
||||||
|
'ms.minders.remark': 'Remark Information',
|
||||||
|
'ms.minders.caseName': 'Test Case Name',
|
||||||
|
'ms.minders.caseNameNotNull': 'Test Case Name cannot be empty',
|
||||||
|
'ms.minders.commentTotal': '{num} Comments in Total',
|
||||||
|
'ms.minders.text': 'Text',
|
||||||
|
'ms.minders.leaveUnsavedTip': 'The mind map has unsaved changes, are you sure you want to exit?',
|
||||||
|
'ms.minders.createSiblingModule': 'Insert sibling Module',
|
||||||
|
'ms.minders.createSiblingCase': 'Insert sibling Case',
|
||||||
|
'ms.minders.createChildModule': 'Insert child Module',
|
||||||
|
'ms.minders.createChildCase': 'Insert child Case',
|
||||||
|
// 测试规划脑图文案
|
||||||
'ms.minders.failStop': 'Failure stop',
|
'ms.minders.failStop': 'Failure stop',
|
||||||
'ms.minders.failRetry': 'Retry on failure',
|
'ms.minders.failRetry': 'Retry on failure',
|
||||||
'ms.minders.stepRetry': 'Step Retry',
|
'ms.minders.stepRetry': 'Step Retry',
|
|
@ -1,4 +1,21 @@
|
||||||
export default {
|
export default {
|
||||||
|
// 功能用例脑图文案
|
||||||
|
'ms.minders.allModule': '全部模块',
|
||||||
|
'ms.minders.precondition': '前置条件',
|
||||||
|
'ms.minders.stepDesc': '步骤描述',
|
||||||
|
'ms.minders.stepExpect': '预期结果',
|
||||||
|
'ms.minders.textDesc': '文本描述',
|
||||||
|
'ms.minders.remark': '备注信息',
|
||||||
|
'ms.minders.caseName': '用例名称',
|
||||||
|
'ms.minders.caseNameNotNull': '用例名称不能为空',
|
||||||
|
'ms.minders.commentTotal': '共 {num} 评论',
|
||||||
|
'ms.minders.text': '文本',
|
||||||
|
'ms.minders.leaveUnsavedTip': '脑图有未保存的更改,确认离开吗?',
|
||||||
|
'ms.minders.createSiblingModule': '添加同级模块',
|
||||||
|
'ms.minders.createSiblingCase': '添加同级用例',
|
||||||
|
'ms.minders.createChildModule': '添加子级模块',
|
||||||
|
'ms.minders.createChildCase': '添加子级用例',
|
||||||
|
// 测试规划脑图文案
|
||||||
'ms.minders.failStop': '失败停止',
|
'ms.minders.failStop': '失败停止',
|
||||||
'ms.minders.failRetry': '失败重试',
|
'ms.minders.failRetry': '失败重试',
|
||||||
'ms.minders.stepRetry': '步骤重试',
|
'ms.minders.stepRetry': '步骤重试',
|
|
@ -13,6 +13,7 @@
|
||||||
:can-show-enter-node="canShowEnterNode"
|
:can-show-enter-node="canShowEnterNode"
|
||||||
:can-show-more-menu-node-operation="false"
|
:can-show-more-menu-node-operation="false"
|
||||||
:more-menu-other-operation-list="canShowFloatMenu && hasOperationPermission ? moreMenuOtherOperationList : []"
|
:more-menu-other-operation-list="canShowFloatMenu && hasOperationPermission ? moreMenuOtherOperationList : []"
|
||||||
|
:shortcut-list="['expand']"
|
||||||
disabled
|
disabled
|
||||||
@node-batch-select="handleNodeBatchSelect"
|
@node-batch-select="handleNodeBatchSelect"
|
||||||
@node-select="handleNodeSelect"
|
@node-select="handleNodeSelect"
|
||||||
|
@ -134,6 +135,20 @@
|
||||||
</template>
|
</template>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
</template>
|
</template>
|
||||||
|
<template #shortCutList>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem">
|
||||||
|
<div>{{ t('common.success') }}</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem-icon ms-minder-shortcut-trigger-listitem-icon-auto"> S </div>
|
||||||
|
</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem">
|
||||||
|
<div>{{ t('common.fail') }}</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem-icon ms-minder-shortcut-trigger-listitem-icon-auto"> E </div>
|
||||||
|
</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem">
|
||||||
|
<div>{{ t('common.block') }}</div>
|
||||||
|
<div class="ms-minder-shortcut-trigger-listitem-icon ms-minder-shortcut-trigger-listitem-icon-auto"> B </div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</MsMinderEditor>
|
</MsMinderEditor>
|
||||||
<LinkDefectDrawer
|
<LinkDefectDrawer
|
||||||
v-if="isMinderOperation"
|
v-if="isMinderOperation"
|
||||||
|
@ -302,7 +317,7 @@
|
||||||
...e.data,
|
...e.data,
|
||||||
type: e.type || e.data?.type,
|
type: e.type || e.data?.type,
|
||||||
id: e.id || e.data?.id || '',
|
id: e.id || e.data?.id || '',
|
||||||
text: e.name || e.data?.text || '',
|
text: e.name || e.data?.text.replace(/<\/?p\b[^>]*>/gi, '') || '',
|
||||||
resource: modulesCount.value[e.id] !== undefined ? [moduleTag] : e.data?.resource,
|
resource: modulesCount.value[e.id] !== undefined ? [moduleTag] : e.data?.resource,
|
||||||
expandState: e.level === 0 ? 'expand' : 'collapse',
|
expandState: e.level === 0 ? 'expand' : 'collapse',
|
||||||
count: modulesCount.value[e.id],
|
count: modulesCount.value[e.id],
|
||||||
|
@ -608,14 +623,18 @@
|
||||||
);
|
);
|
||||||
if (actualResultNode) {
|
if (actualResultNode) {
|
||||||
if (content.length) {
|
if (content.length) {
|
||||||
actualResultNode.setData('text', content).render();
|
actualResultNode.setData('text', content.replace(/<\/?p\b[^>]*>/gi, '')).render();
|
||||||
} else {
|
} else {
|
||||||
// 删除实际结果节点
|
// 删除实际结果节点
|
||||||
window.minder.removeNode(actualResultNode);
|
window.minder.removeNode(actualResultNode);
|
||||||
}
|
}
|
||||||
} else if (content.length) {
|
} else if (content.length) {
|
||||||
actualResultNode = createNode(
|
actualResultNode = createNode(
|
||||||
{ resource: [actualResultTag], text: content, id: `actualResult-${node.data?.id}` },
|
{
|
||||||
|
resource: [actualResultTag],
|
||||||
|
text: content.replace(/<\/?p\b[^>]*>/gi, ''),
|
||||||
|
id: `actualResult-${node.data?.id}`,
|
||||||
|
},
|
||||||
node
|
node
|
||||||
);
|
);
|
||||||
handleRenderNode(node, [actualResultNode]);
|
handleRenderNode(node, [actualResultNode]);
|
||||||
|
@ -983,6 +1002,9 @@
|
||||||
[executionResultMap.ERROR.statusText]: 5,
|
[executionResultMap.ERROR.statusText]: 5,
|
||||||
[executionResultMap.BLOCKED.statusText]: 6,
|
[executionResultMap.BLOCKED.statusText]: 6,
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
unbindShortcuts();
|
unbindShortcuts();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
:can-show-dropdown="canShowDropdown"
|
:can-show-dropdown="canShowDropdown"
|
||||||
:dropdown-list="dropdownList"
|
:dropdown-list="dropdownList"
|
||||||
:checked-val="checkedVal"
|
:checked-val="checkedVal"
|
||||||
|
:shortcut-list="['expand', 'addSibling', 'addChild', 'delete']"
|
||||||
custom-priority
|
custom-priority
|
||||||
single-tag
|
single-tag
|
||||||
tag-enable
|
tag-enable
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { isMacOs } from '@/utils';
|
import { isMacOs } from '@/utils';
|
||||||
|
|
||||||
export default defineComponent(() => {
|
export default defineComponent((props: { size?: number }) => {
|
||||||
const isMac = isMacOs();
|
const isMac = isMacOs();
|
||||||
|
|
||||||
return () => (isMac ? <icon-command size={14} /> : 'Ctrl');
|
return () => (isMac ? <icon-command size={props.size || 14} /> : 'Ctrl');
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,6 +2,7 @@ import type { MinderJsonNode } from '../props';
|
||||||
import useMinderOperation, { type MinderOperationProps } from './useMinderOperation';
|
import useMinderOperation, { type MinderOperationProps } from './useMinderOperation';
|
||||||
|
|
||||||
type ShortcutKey =
|
type ShortcutKey =
|
||||||
|
| 'save'
|
||||||
| 'expand'
|
| 'expand'
|
||||||
| 'enter'
|
| 'enter'
|
||||||
| 'appendSiblingNode'
|
| 'appendSiblingNode'
|
||||||
|
@ -11,7 +12,11 @@ type ShortcutKey =
|
||||||
| 'delete'
|
| 'delete'
|
||||||
| 'executeToSuccess'
|
| 'executeToSuccess'
|
||||||
| 'executeToBlocked'
|
| 'executeToBlocked'
|
||||||
| 'executeToError';
|
| 'executeToError'
|
||||||
|
| 'addChildCase'
|
||||||
|
| 'addChildModule'
|
||||||
|
| 'addSiblingModule'
|
||||||
|
| 'addSiblingCase';
|
||||||
// 快捷键事件映射,combinationShortcuts中定义了组合键事件,key为组合键,value为事件名称;
|
// 快捷键事件映射,combinationShortcuts中定义了组合键事件,key为组合键,value为事件名称;
|
||||||
type Shortcuts = {
|
type Shortcuts = {
|
||||||
[key in ShortcutKey]?: () => void;
|
[key in ShortcutKey]?: () => void;
|
||||||
|
@ -38,12 +43,14 @@ export default function useShortCut(shortcuts: Shortcuts, options: MinderOperati
|
||||||
}
|
}
|
||||||
const key = event.key.toLowerCase();
|
const key = event.key.toLowerCase();
|
||||||
const isCtrlOrCmd = event.ctrlKey || event.metaKey;
|
const isCtrlOrCmd = event.ctrlKey || event.metaKey;
|
||||||
|
const isShift = event.shiftKey;
|
||||||
|
|
||||||
// 定义组合键事件
|
// 定义组合键事件
|
||||||
const combinationShortcuts: { [key: string]: ShortcutKey } = {
|
const combinationShortcuts: { [key: string]: ShortcutKey } = {
|
||||||
// z: 'undo', // 撤销 TODO:暂时不上撤销和重做
|
// z: 'undo', // 撤销 TODO:暂时不上撤销和重做
|
||||||
// y: 'redo', // 重做
|
// y: 'redo', // 重做
|
||||||
enter: 'enter', // 进入节点
|
enter: 'enter', // 进入节点
|
||||||
|
save: 'save', // 保存
|
||||||
};
|
};
|
||||||
// 定义单键事件
|
// 定义单键事件
|
||||||
const singleShortcuts: { [key: string]: ShortcutKey } = {
|
const singleShortcuts: { [key: string]: ShortcutKey } = {
|
||||||
|
@ -57,12 +64,21 @@ export default function useShortCut(shortcuts: Shortcuts, options: MinderOperati
|
||||||
s: 'executeToSuccess', // 执行结果为成功
|
s: 'executeToSuccess', // 执行结果为成功
|
||||||
b: 'executeToBlocked', // 执行结果为阻塞
|
b: 'executeToBlocked', // 执行结果为阻塞
|
||||||
e: 'executeToError', // 执行结果为失败
|
e: 'executeToError', // 执行结果为失败
|
||||||
|
m: 'addSiblingModule', // 添加同级模块
|
||||||
|
c: 'addSiblingCase', // 添加同级用例
|
||||||
|
};
|
||||||
|
const shiftCombinationShortcuts: { [key: string]: ShortcutKey } = {
|
||||||
|
m: 'addChildModule', // 添加子级模块
|
||||||
|
c: 'addChildCase', // 添加子级用例
|
||||||
};
|
};
|
||||||
|
|
||||||
let action;
|
let action;
|
||||||
if (isCtrlOrCmd && combinationShortcuts[key]) {
|
if (isCtrlOrCmd && combinationShortcuts[key]) {
|
||||||
// 执行组合键事件
|
// 执行组合键事件
|
||||||
action = combinationShortcuts[key];
|
action = combinationShortcuts[key];
|
||||||
|
} else if (isShift && shiftCombinationShortcuts[key]) {
|
||||||
|
// 执行 shift 组合键事件
|
||||||
|
action = shiftCombinationShortcuts[key];
|
||||||
} else if (singleShortcuts[key]) {
|
} else if (singleShortcuts[key]) {
|
||||||
// 执行单键事件
|
// 执行单键事件
|
||||||
action = singleShortcuts[key];
|
action = singleShortcuts[key];
|
||||||
|
|
|
@ -43,14 +43,22 @@
|
||||||
<MsIcon type="icon-icon_full_screen_one" class="text-[var(--color-text-4)]" />
|
<MsIcon type="icon-icon_full_screen_one" class="text-[var(--color-text-4)]" />
|
||||||
</MsButton>
|
</MsButton>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-button v-if="!props.disabled" type="outline" class="px-[8px] py-[2px] text-[12px]" size="small" @click="save">
|
<a-button
|
||||||
|
v-if="!props.disabled"
|
||||||
|
type="outline"
|
||||||
|
class="flex items-center gap-[2px] px-[8px] py-[2px] text-[12px]"
|
||||||
|
size="small"
|
||||||
|
@click="save"
|
||||||
|
>
|
||||||
{{ t('minder.main.main.save') }}
|
{{ t('minder.main.main.save') }}
|
||||||
|
<div>(<MsCtrlOrCommand :size="12" /> + S)</div>
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
|
import MsCtrlOrCommand from '@/components/pure/ms-ctrl-or-command';
|
||||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||||
|
|
||||||
import useFullScreen from '@/hooks/useFullScreen';
|
import useFullScreen from '@/hooks/useFullScreen';
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
:disabled="props.disabled"
|
:disabled="props.disabled"
|
||||||
@save="save"
|
@save="save"
|
||||||
/>
|
/>
|
||||||
<Navigator />
|
<Navigator :shortcut-list="props.shortcutList">
|
||||||
|
<template #shortCutList>
|
||||||
|
<slot name="shortCutList"></slot>
|
||||||
|
</template>
|
||||||
|
</Navigator>
|
||||||
<div
|
<div
|
||||||
v-if="currentTreePath?.length > 0"
|
v-if="currentTreePath?.length > 0"
|
||||||
class="absolute left-[50%] top-[16px] z-[9] w-[60%] translate-x-[-50%] overflow-hidden bg-white p-[8px]"
|
class="absolute left-[50%] top-[16px] z-[9] w-[60%] translate-x-[-50%] overflow-hidden bg-white p-[8px]"
|
||||||
|
@ -64,6 +68,7 @@
|
||||||
MinderJson,
|
MinderJson,
|
||||||
MinderJsonNode,
|
MinderJsonNode,
|
||||||
MinderJsonNodeData,
|
MinderJsonNodeData,
|
||||||
|
navigatorProps,
|
||||||
priorityProps,
|
priorityProps,
|
||||||
tagProps,
|
tagProps,
|
||||||
} from '../props';
|
} from '../props';
|
||||||
|
@ -80,6 +85,7 @@
|
||||||
...priorityProps,
|
...priorityProps,
|
||||||
...batchMenuProps,
|
...batchMenuProps,
|
||||||
...dropdownMenuProps,
|
...dropdownMenuProps,
|
||||||
|
...navigatorProps,
|
||||||
});
|
});
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'save', data: MinderJson, callback: () => void): void;
|
(e: 'save', data: MinderJson, callback: () => void): void;
|
||||||
|
@ -341,7 +347,7 @@
|
||||||
right: 7px;
|
right: 7px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-family: iconfont;
|
font-family: iconfont;
|
||||||
content: '\e6d5';
|
content: '\e6fe';
|
||||||
color: var(--color-text-brand);
|
color: var(--color-text-brand);
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
|
|
|
@ -40,8 +40,8 @@
|
||||||
</MsButton>
|
</MsButton>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-trigger
|
<a-trigger
|
||||||
:popup-translate="[5, -105]"
|
:popup-translate="[5, -20]"
|
||||||
position="right"
|
position="rb"
|
||||||
class="ms-minder-shortcut-trigger"
|
class="ms-minder-shortcut-trigger"
|
||||||
@popup-visible-change="(val) => (shortcutTriggerVisible = val)"
|
@popup-visible-change="(val) => (shortcutTriggerVisible = val)"
|
||||||
>
|
>
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
<div>{{ t('minder.expand') }}</div>
|
<div>{{ t('minder.expand') }}</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon">/</div>
|
<div class="ms-minder-shortcut-trigger-listitem-icon">/</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem">
|
<div v-if="props.shortcutList.includes('copy')" class="ms-minder-shortcut-trigger-listitem">
|
||||||
<div>{{ t('common.copy') }}</div>
|
<div>{{ t('common.copy') }}</div>
|
||||||
<div class="flex items-center gap-[4px]">
|
<div class="flex items-center gap-[4px]">
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
||||||
|
@ -69,13 +69,13 @@
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon">C</div>
|
<div class="ms-minder-shortcut-trigger-listitem-icon">C</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem">
|
<div v-if="props.shortcutList.includes('addSibling')" class="ms-minder-shortcut-trigger-listitem">
|
||||||
<div>{{ t('minder.hotboxMenu.insetBrother') }}</div>
|
<div>{{ t('minder.hotboxMenu.insetBrother') }}</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
||||||
<MsIcon type="icon-icon_carriage_return2" />
|
<MsIcon type="icon-icon_carriage_return2" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem">
|
<div v-if="props.shortcutList.includes('paste')" class="ms-minder-shortcut-trigger-listitem">
|
||||||
<div>{{ t('minder.hotboxMenu.paste') }}</div>
|
<div>{{ t('minder.hotboxMenu.paste') }}</div>
|
||||||
<div class="flex items-center gap-[4px]">
|
<div class="flex items-center gap-[4px]">
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
||||||
|
@ -84,13 +84,13 @@
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon">V</div>
|
<div class="ms-minder-shortcut-trigger-listitem-icon">V</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem">
|
<div v-if="props.shortcutList.includes('addChild')" class="ms-minder-shortcut-trigger-listitem">
|
||||||
<div>{{ t('minder.hotboxMenu.insetSon') }}</div>
|
<div>{{ t('minder.hotboxMenu.insetSon') }}</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon ms-minder-shortcut-trigger-listitem-icon-auto">
|
<div class="ms-minder-shortcut-trigger-listitem-icon ms-minder-shortcut-trigger-listitem-icon-auto">
|
||||||
Tab
|
Tab
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem">
|
<div v-if="props.shortcutList.includes('cut')" class="ms-minder-shortcut-trigger-listitem">
|
||||||
<div>{{ t('minder.hotboxMenu.cut') }}</div>
|
<div>{{ t('minder.hotboxMenu.cut') }}</div>
|
||||||
<div class="flex items-center gap-[4px]">
|
<div class="flex items-center gap-[4px]">
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
||||||
|
@ -99,7 +99,7 @@
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon">X</div>
|
<div class="ms-minder-shortcut-trigger-listitem-icon">X</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem">
|
<div v-if="props.shortcutList.includes('enter')" class="ms-minder-shortcut-trigger-listitem">
|
||||||
<div>{{ t('minder.hotboxMenu.enterNode') }}</div>
|
<div>{{ t('minder.hotboxMenu.enterNode') }}</div>
|
||||||
<div class="flex items-center gap-[4px]">
|
<div class="flex items-center gap-[4px]">
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon">Z</div>
|
<div class="ms-minder-shortcut-trigger-listitem-icon">Z</div>
|
||||||
</div>
|
</div>
|
||||||
</div> -->
|
</div> -->
|
||||||
<div class="ms-minder-shortcut-trigger-listitem">
|
<div v-if="props.shortcutList.includes('delete')" class="ms-minder-shortcut-trigger-listitem">
|
||||||
<div>{{ t('common.delete') }}</div>
|
<div>{{ t('common.delete') }}</div>
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
<div class="ms-minder-shortcut-trigger-listitem-icon">
|
||||||
<MsIcon type="icon-icon_carriage_return1" />
|
<MsIcon type="icon-icon_carriage_return1" />
|
||||||
|
@ -134,6 +134,7 @@
|
||||||
<div class="ms-minder-shortcut-trigger-listitem-icon">Y</div>
|
<div class="ms-minder-shortcut-trigger-listitem-icon">Y</div>
|
||||||
</div>
|
</div>
|
||||||
</div> -->
|
</div> -->
|
||||||
|
<slot name="shortCutList"></slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</a-trigger>
|
</a-trigger>
|
||||||
|
@ -149,14 +150,17 @@
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
|
import { navigatorProps } from '../props';
|
||||||
import { getLocalStorage, setLocalStorage } from '../script/store';
|
import { getLocalStorage, setLocalStorage } from '../script/store';
|
||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps(navigatorProps);
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const navPreviewer: Ref<HTMLDivElement | null> = ref(null);
|
const navPreviewer: Ref<HTMLDivElement | null> = ref(null);
|
||||||
|
|
||||||
const isNavOpen = ref(true);
|
const isNavOpen = ref(false);
|
||||||
const previewNavigator: Ref<HTMLDivElement | null> = ref(null);
|
const previewNavigator: Ref<HTMLDivElement | null> = ref(null);
|
||||||
const contentView = ref('');
|
const contentView = ref('');
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
<template #batchMenu>
|
<template #batchMenu>
|
||||||
<slot name="batchMenu"></slot>
|
<slot name="batchMenu"></slot>
|
||||||
</template>
|
</template>
|
||||||
|
<template #shortCutList>
|
||||||
|
<slot name="shortCutList"></slot>
|
||||||
|
</template>
|
||||||
</mainEditor>
|
</mainEditor>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-minder-editor-extra" :class="[extraVisible ? 'ms-minder-editor-extra--visible' : '']">
|
<div class="ms-minder-editor-extra" :class="[extraVisible ? 'ms-minder-editor-extra--visible' : '']">
|
||||||
|
@ -51,6 +54,7 @@
|
||||||
MinderJson,
|
MinderJson,
|
||||||
MinderJsonNode,
|
MinderJsonNode,
|
||||||
moleProps,
|
moleProps,
|
||||||
|
navigatorProps,
|
||||||
priorityProps,
|
priorityProps,
|
||||||
tagProps,
|
tagProps,
|
||||||
viewMenuProps,
|
viewMenuProps,
|
||||||
|
@ -82,6 +86,7 @@
|
||||||
...viewMenuProps,
|
...viewMenuProps,
|
||||||
...batchMenuProps,
|
...batchMenuProps,
|
||||||
...dropdownMenuProps,
|
...dropdownMenuProps,
|
||||||
|
...navigatorProps,
|
||||||
});
|
});
|
||||||
|
|
||||||
const minderStore = useMinderStore();
|
const minderStore = useMinderStore();
|
||||||
|
@ -138,6 +143,9 @@
|
||||||
minderStore.dispatchEvent(MinderEventName.ENTER_NODE, undefined, undefined, undefined, [selectedNodes[0]]);
|
minderStore.dispatchEvent(MinderEventName.ENTER_NODE, undefined, undefined, undefined, [selectedNodes[0]]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
save: () => {
|
||||||
|
minderStore.dispatchEvent(MinderEventName.SAVE_MINDER);
|
||||||
|
},
|
||||||
delete: () => {
|
delete: () => {
|
||||||
const selectedNodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
const selectedNodes: MinderJsonNode[] = window.minder.getSelectedNodes();
|
||||||
minderDelete(selectedNodes);
|
minderDelete(selectedNodes);
|
||||||
|
|
|
@ -328,3 +328,13 @@ export const viewMenuProps = {
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const navigatorProps = {
|
||||||
|
// 显示的快捷键列表
|
||||||
|
shortcutList: {
|
||||||
|
type: Array as PropType<string[]>,
|
||||||
|
default() {
|
||||||
|
return ['expand', 'addSibling', 'addChild', 'delete', 'cut', 'copy', 'paste', 'enter'];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import '@7polo/kity/dist/kity';
|
import '@7polo/kity/dist/kity';
|
||||||
import '@7polo/kityminder-core';
|
import '@7polo/kityminder-core';
|
||||||
import clipboard from './runtime/clipboard';
|
|
||||||
import clipboardMimetype from './runtime/clipboard-mimetype';
|
import clipboardMimetype from './runtime/clipboard-mimetype';
|
||||||
import container from './runtime/container';
|
import container from './runtime/container';
|
||||||
import drag from './runtime/drag';
|
import drag from './runtime/drag';
|
||||||
|
@ -70,7 +69,6 @@ assemble(minder);
|
||||||
assemble(receiver);
|
assemble(receiver);
|
||||||
assemble(input);
|
assemble(input);
|
||||||
assemble(clipboardMimetype);
|
assemble(clipboardMimetype);
|
||||||
assemble(clipboard);
|
|
||||||
assemble(drag);
|
assemble(drag);
|
||||||
assemble(history);
|
assemble(history);
|
||||||
assemble(jumping);
|
assemble(jumping);
|
||||||
|
|
|
@ -1,196 +0,0 @@
|
||||||
import { markDeleteNode, resetNodes } from '../tool/utils';
|
|
||||||
|
|
||||||
interface INode {
|
|
||||||
getLevel(): number;
|
|
||||||
isAncestorOf(node: INode): boolean;
|
|
||||||
appendChild(node: INode): INode;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IData {
|
|
||||||
getRegisterProtocol(protocol: string): {
|
|
||||||
encode: (nodes: Array<INode>) => Array<INode>;
|
|
||||||
decode: (nodes: Array<INode>) => Array<INode>;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ClipboardRuntime(this: any) {
|
|
||||||
const { minder } = this;
|
|
||||||
const { receiver } = this;
|
|
||||||
const Data: IData = window.kityminder.data;
|
|
||||||
|
|
||||||
if (!minder.supportClipboardEvent || window.kity.Browser.gecko) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const kmencode = this.MimeType.getMimeTypeProtocol('application/km');
|
|
||||||
const { decode } = Data.getRegisterProtocol('json');
|
|
||||||
let _selectedNodes: Array<INode> = [];
|
|
||||||
|
|
||||||
function encode(nodes: Array<INode>): string {
|
|
||||||
const _nodes = [];
|
|
||||||
for (let i = 0, l = nodes.length; i < l; i++) {
|
|
||||||
// @ts-ignore
|
|
||||||
_nodes.push(minder.exportNode(nodes[i]));
|
|
||||||
}
|
|
||||||
return kmencode(Data.getRegisterProtocol('json').encode(_nodes));
|
|
||||||
}
|
|
||||||
|
|
||||||
const beforeCopy = (e: ClipboardEvent) => {
|
|
||||||
if (document.activeElement === receiver.element) {
|
|
||||||
const clipBoardEvent = e;
|
|
||||||
const state = this.fsm.state();
|
|
||||||
switch (state) {
|
|
||||||
case 'input': {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'normal': {
|
|
||||||
const nodes = [...minder.getSelectedNodes()];
|
|
||||||
if (nodes.length) {
|
|
||||||
if (nodes.length > 1) {
|
|
||||||
let targetLevel;
|
|
||||||
nodes.sort((a: any, b: any) => {
|
|
||||||
return a.getLevel() - b.getLevel();
|
|
||||||
});
|
|
||||||
// eslint-disable-next-line prefer-const
|
|
||||||
targetLevel = nodes[0].getLevel();
|
|
||||||
if (targetLevel !== nodes[nodes.length - 1].getLevel()) {
|
|
||||||
let pnode;
|
|
||||||
let idx = 0;
|
|
||||||
const l = nodes.length;
|
|
||||||
let pidx = l - 1;
|
|
||||||
|
|
||||||
pnode = nodes[pidx];
|
|
||||||
|
|
||||||
while (pnode.getLevel() !== targetLevel) {
|
|
||||||
idx = 0;
|
|
||||||
while (idx < l && nodes[idx].getLevel() === targetLevel) {
|
|
||||||
if (nodes[idx].isAncestorOf(pnode)) {
|
|
||||||
nodes.splice(pidx, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
pidx--;
|
|
||||||
pnode = nodes[pidx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const str = encode(nodes);
|
|
||||||
clipBoardEvent.clipboardData?.setData('text/plain', str);
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const beforeCut = (e: ClipboardEvent) => {
|
|
||||||
const { activeElement } = document;
|
|
||||||
if (activeElement === receiver.element) {
|
|
||||||
if (minder.getStatus() !== 'normal') {
|
|
||||||
e.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const clipBoardEvent = e;
|
|
||||||
const state = this.fsm.state();
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case 'input': {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'normal': {
|
|
||||||
markDeleteNode(minder);
|
|
||||||
const nodes = minder.getSelectedNodes();
|
|
||||||
if (nodes.length) {
|
|
||||||
clipBoardEvent.clipboardData?.setData('text/plain', encode(nodes));
|
|
||||||
minder.execCommand('removenode');
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const beforePaste = (e: ClipboardEvent) => {
|
|
||||||
if (document.activeElement === receiver.element) {
|
|
||||||
if (minder.getStatus() !== 'normal') {
|
|
||||||
e.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const clipBoardEvent = e;
|
|
||||||
const state = this.fsm.state();
|
|
||||||
const textData = clipBoardEvent.clipboardData?.getData('text/plain');
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case 'input': {
|
|
||||||
// input状态下如果格式为application/km则不进行paste操作
|
|
||||||
if (!this.MimeType.isPureText(textData)) {
|
|
||||||
e.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'normal': {
|
|
||||||
/*
|
|
||||||
* 针对normal状态下通过对选中节点粘贴导入子节点文本进行单独处理
|
|
||||||
*/
|
|
||||||
const sNodes = minder.getSelectedNodes();
|
|
||||||
|
|
||||||
if (this.MimeType.whichMimeType(textData) === 'application/km') {
|
|
||||||
const nodes = decode(this.MimeType.getPureText(textData));
|
|
||||||
resetNodes(nodes);
|
|
||||||
let _node;
|
|
||||||
sNodes.forEach((node: INode) => {
|
|
||||||
// 由于粘贴逻辑中为了排除子节点重新排序导致逆序,因此复制的时候倒过来
|
|
||||||
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
||||||
_node = minder.createNode(null, node);
|
|
||||||
minder.importNode(_node, nodes[i]);
|
|
||||||
_selectedNodes.push(_node);
|
|
||||||
node.appendChild(_node);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
minder.select(_selectedNodes, true);
|
|
||||||
_selectedNodes = [];
|
|
||||||
|
|
||||||
minder.refresh();
|
|
||||||
} else if (clipBoardEvent.clipboardData && clipBoardEvent.clipboardData.items[0].type.indexOf('image') > -1) {
|
|
||||||
const imageFile = clipBoardEvent.clipboardData.items[0].getAsFile();
|
|
||||||
const serverService = window.angular.element(document.body).injector().get('server');
|
|
||||||
|
|
||||||
return serverService.uploadImage(imageFile).then((json: Record<string, any>) => {
|
|
||||||
const resp = json.data;
|
|
||||||
if (resp.errno === 0) {
|
|
||||||
minder.execCommand('image', resp.data.url);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
sNodes.forEach((node: INode) => {
|
|
||||||
minder.Text2Children(node, textData);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
// 触发命令监听
|
|
||||||
minder.execCommand('paste');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 由editor的receiver统一处理全部事件,包括clipboard事件
|
|
||||||
* @Editor: Naixor
|
|
||||||
* @Date: 2015.9.24
|
|
||||||
*/
|
|
||||||
// TODO: 未来需要支持自定义快捷键处理逻辑
|
|
||||||
// document.addEventListener('copy', (e) => beforeCopy(e));
|
|
||||||
// document.addEventListener('cut', (e) => beforeCut(e));
|
|
||||||
// document.addEventListener('paste', (e) => beforePaste(e));
|
|
||||||
}
|
|
|
@ -132,6 +132,12 @@ class FSM {
|
||||||
|
|
||||||
function FSMRuntime(this: any) {
|
function FSMRuntime(this: any) {
|
||||||
this.fsm = new FSM('normal');
|
this.fsm = new FSM('normal');
|
||||||
|
this.fsm.when('normal -> normal', (exit: any, enter: any, reason: string, e: KeyboardEvent) => {
|
||||||
|
const arrowKey = ['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'];
|
||||||
|
if (reason === 'shortcut-handle' && arrowKey.includes(e.code)) {
|
||||||
|
this.minder.dispatchKeyEvent(e); // 触发脑图本身的方向快捷键事件
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default FSMRuntime;
|
export default FSMRuntime;
|
||||||
|
|
|
@ -275,7 +275,7 @@ function InputRuntime(this: any) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
text = text.replace(/^\n*|\n*$/g, '');
|
text = text.replace(/^\n*|\n*$/g, '').replace(/<\/?p\b[^>]*>/gi, ''); // 去除富文本内p标签
|
||||||
text = text.replace(new RegExp(`(\n|\r|\n\r)(\u0020|${String.fromCharCode(160)}){4}`, 'g'), '$1\t');
|
text = text.replace(new RegExp(`(\n|\r|\n\r)(\u0020|${String.fromCharCode(160)}){4}`, 'g'), '$1\t');
|
||||||
this.minder.getSelectedNode().setText(text);
|
this.minder.getSelectedNode().setText(text);
|
||||||
if (isBold) {
|
if (isBold) {
|
||||||
|
|
|
@ -32,6 +32,30 @@ interface IJumpingRuntime {
|
||||||
function JumpingRuntime(this: IJumpingRuntime): void {
|
function JumpingRuntime(this: IJumpingRuntime): void {
|
||||||
const { fsm, receiver } = this;
|
const { fsm, receiver } = this;
|
||||||
|
|
||||||
|
// normal -> *
|
||||||
|
receiver.listen('normal', (e: any) => {
|
||||||
|
// 为了防止处理进入edit模式而丢失处理的首字母,此时receiver必须为enable
|
||||||
|
receiver.enable();
|
||||||
|
/**
|
||||||
|
* check
|
||||||
|
* @editor Naixor
|
||||||
|
* @Date 2015-12-2
|
||||||
|
*/
|
||||||
|
switch (e.type) {
|
||||||
|
case 'keydown': {
|
||||||
|
// normal -> normal shortcut
|
||||||
|
fsm.jump('normal', 'shortcut-handle', e); // 触发快捷键事件,这里可能会被脑图自定义快捷键拦截处理,若非自定义快捷键则触发脑图本身的快捷键
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'keyup': {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// input => normal
|
// input => normal
|
||||||
receiver.listen('input', (e: KeyboardEvent) => {
|
receiver.listen('input', (e: KeyboardEvent) => {
|
||||||
receiver.enable();
|
receiver.enable();
|
||||||
|
|
|
@ -209,6 +209,7 @@ export function createNode(data?: MinderJsonNodeData, parentNode?: MinderJsonNod
|
||||||
return window.minder.createNode(
|
return window.minder.createNode(
|
||||||
{
|
{
|
||||||
...data,
|
...data,
|
||||||
|
text: data?.text.replace(/<\/?p\b[^>]*>/gi, '') || '',
|
||||||
expandState: 'collapse',
|
expandState: 'collapse',
|
||||||
disabled: true,
|
disabled: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -87,6 +87,8 @@
|
||||||
class="w-[130px]"
|
class="w-[130px]"
|
||||||
:disabled="fileSizeLimitLoading || !hasAnyPermission(['SYSTEM_PARAMETER_SETTING_BASE:READ+UPDATE'])"
|
:disabled="fileSizeLimitLoading || !hasAnyPermission(['SYSTEM_PARAMETER_SETTING_BASE:READ+UPDATE'])"
|
||||||
:min="0"
|
:min="0"
|
||||||
|
:max="1024"
|
||||||
|
:precision="0"
|
||||||
mode="button"
|
mode="button"
|
||||||
@blur="() => saveFileSizeLimitConfig()"
|
@blur="() => saveFileSizeLimitConfig()"
|
||||||
/>
|
/>
|
||||||
|
|
Loading…
Reference in New Issue