fix(脑图): 移除 hotbox、子孙级模块保存错误修复

This commit is contained in:
baiqi 2024-06-26 10:24:27 +08:00 committed by 刘瑞斌
parent 362b175a2e
commit 43b0e2ec2f
15 changed files with 12 additions and 570 deletions

View File

@ -61,7 +61,6 @@
"echarts": "^5.4.3",
"fastq": "^1.15.0",
"github-markdown-css": "^5.5.1",
"hotbox-minder": "1.0.15",
"jsencrypt": "^3.3.2",
"jsonpath-plus": "^8.0.0",
"localforage": "^1.10.0",

View File

@ -809,9 +809,14 @@
}
}
const minderNode: MinderJsonNode = window.minder.getNodeById(node.data.id);
if (minderNode.data) {
if (minderNode?.data) {
// isNew changed
minderNode.data.isNew = false;
minderNode.data.changed = false;
} else {
// isNew changed
node.data.isNew = false;
node.data.changed = false;
}
return true;
});

View File

@ -1,5 +1,4 @@
import '@7polo/kity/dist/kity';
import 'hotbox-minder/hotbox';
import '@7polo/kityminder-core';
import clipboard from './runtime/clipboard';
import clipboardMimetype from './runtime/clipboard-mimetype';
@ -8,15 +7,10 @@ import drag from './runtime/drag';
import exportsRuntime from './runtime/exports';
import fsm from './runtime/fsm';
import history from './runtime/history';
import hotbox from './runtime/hotbox';
import input from './runtime/input';
import jumping from './runtime/jumping';
import minder from './runtime/minder';
import node from './runtime/node';
import priority from './runtime/priority';
import progress from './runtime/progress';
import receiver from './runtime/receiver';
import tag from './runtime/tag';
type EditMenuProps = {
sequenceEnable: boolean;
@ -74,18 +68,13 @@ assemble(container);
assemble(fsm);
assemble(minder);
assemble(receiver);
assemble(hotbox);
assemble(input);
assemble(clipboardMimetype);
assemble(clipboard);
assemble(drag);
assemble(node);
assemble(history);
assemble(jumping);
assemble(priority);
assemble(progress);
assemble(exportsRuntime);
assemble(tag);
window.kityminder.Editor = KMEditor;

View File

@ -10,12 +10,11 @@
interface DragRuntimeOptions {
fsm: any;
minder: any;
hotbox: any;
receiver: any;
}
function createDragRuntime(this: DragRuntimeOptions) {
const { fsm, minder, hotbox } = this;
const { fsm, minder } = this;
// listen the fsm changes, make action.
function setupFsm() {
@ -159,10 +158,6 @@ function createDragRuntime(this: DragRuntimeOptions) {
minder.getSelectedNode() &&
(Math.abs(downX - e.originEvent.clientX) > BOUND_CHECK || Math.abs(downY - e.originEvent.clientY) > BOUND_CHECK)
) {
if (fsm.state() === 'hotbox') {
hotbox.active(window.HotBox.STATE_IDLE);
}
fsm.jump('drag', 'user-drag');
}
});

View File

@ -9,7 +9,7 @@ import useLocaleNotVue from '../tool/useLocaleNotVue';
const tran = useLocaleNotVue;
export default function ExportRuntime(this: any) {
const { minder, hotbox } = this;
const { minder } = this;
function canExp() {
return true;
@ -47,39 +47,4 @@ export default function ExportRuntime(this: any) {
{ label: '.md', key: 'm', cmd: exportMarkdown },
{ label: '.mm', key: 'f', cmd: exportFreeMind },
];
const main = hotbox.state('main');
main.button({
position: 'top',
label: tran('minder.commons.export'),
key: 'E',
enable: canExp,
beforeShow() {
this.$button.children[0].innerHTML = tran('minder.commons.export');
},
next: 'exp',
});
const exp = hotbox.state('exp');
exps.forEach((item) => {
exp.button({
position: 'ring',
label: item.label,
key: null,
action: item.cmd,
beforeShow() {
this.$button.children[0].innerHTML = tran(item.label);
},
});
});
exp.button({
position: 'center',
label: tran('minder.commons.cancel'),
key: 'esc',
beforeShow() {
this.$button.children[0].innerHTML = tran('minder.commons.cancel');
},
next: 'back',
});
}

View File

@ -1,9 +1,3 @@
/* eslint-disable no-underscore-dangle */
import useLocaleNotVue from '../tool/useLocaleNotVue';
import { isDisableNode } from '../tool/utils';
const tran = useLocaleNotVue;
interface History {
reset: () => void;
undo: () => void;
@ -12,8 +6,8 @@ interface History {
hasRedo: () => boolean;
}
export default function HistoryRuntime(this: { minder: any; hotbox: any; editText: () => void; history: History }) {
const { minder, hotbox } = this;
export default function HistoryRuntime(this: { minder: any; editText: () => void; history: History }) {
const { minder } = this;
const MAX_HISTORY = 100;
let lastSnap: string;
@ -185,38 +179,4 @@ export default function HistoryRuntime(this: { minder: any; hotbox: any; editTex
minder.on('contentchange', changed);
minder.on('import', reset);
minder.on('patch', updateSelection);
const main = hotbox.state('main');
main.button({
position: 'bottom',
label: tran('minder.main.history.undo'),
key: 'Ctrl + Z',
enable() {
if (isDisableNode(minder)) {
return false;
}
return hasUndo;
},
action: undo,
beforeShow() {
this.$button.children[0].innerHTML = tran('minder.main.history.undo');
},
next: 'idle',
});
main.button({
position: 'bottom',
label: tran('minder.main.history.redo'),
key: 'Ctrl + Y',
enable() {
if (isDisableNode(minder)) {
return false;
}
return hasRedo;
},
action: redo,
beforeShow() {
this.$button.children[0].innerHTML = tran('minder.main.history.undo');
},
next: 'idle',
});
}

View File

@ -1,74 +0,0 @@
import useMinderStore from '@/store/modules/components/minder-editor';
import { MinderEventName } from '@/enums/minderEnum';
function HotboxRuntime(this: any) {
const { fsm } = this;
const { minder } = this;
const { receiver } = this;
const { container } = this;
const { HotBox } = window;
const hotbox = new HotBox(container);
const minderStore = useMinderStore();
hotbox.setParentFSM(fsm);
function handleHotBoxShow() {
const node = minder.getSelectedNode();
if (node) {
const box = node.getRenderBox();
minderStore.dispatchEvent(MinderEventName.HOTBOX, undefined, box, node.rc.node);
}
}
fsm.when('normal -> hotbox', () => {
handleHotBoxShow();
});
fsm.when('hotbox -> hotbox', () => {
handleHotBoxShow();
});
// TODO: 未来需要支持自定义快捷键处理逻辑
// function handleShortcut(e: any) {
// // 检查是否按下Ctrl键Windows和Linux或Command键Mac
// const isCtrlKey = e.ctrlKey || e.metaKey;
// // 检查是否按下Enter键
// const isEnterKey = e.key === 'Enter';
// // 检查是否同时按下Ctrl或Command和Enter键
// if (isCtrlKey && isEnterKey) {
// // 处理Ctrl+Enter组合键事件
// e.preventDefault(); // 阻止默认行为
// // 执行进入模块方法
// const node = minder.getSelectedNode();
// let position: MinderNodePosition | undefined;
// if (node) {
// const box = node.getRenderBox();
// position = {
// x: box.cx,
// y: box.cy,
// };
// minderStore.dispatchEvent(MinderEventName.ENTER_NODE, position, node.rc.node, node.data);
// return;
// }
// }
// minder.dispatchKeyEvent(e);
// }
// fsm.when('normal -> normal', (exit: any, enter: any, reason: any, e: any) => {
// if (reason === 'shortcut-handle') {
// handleShortcut(e);
// }
// });
fsm.when('modal -> normal', (exit: any, enter: any, reason: any) => {
if (reason === 'import-text-finish') {
receiver.element.focus();
}
});
this.hotbox = hotbox;
minder.hotbox = hotbox;
}
export default HotboxRuntime;

View File

@ -9,7 +9,6 @@
* @copyright: Baidu FEX, 2014
*/
import Debug from '../tool/debug';
import useLocaleNotVue from '../tool/useLocaleNotVue';
import { isDisableNode, markChangeNode } from '../tool/utils';
if (!('innerText' in document.createElement('a')) && 'getSelection' in window) {
@ -45,7 +44,6 @@ if (!('innerText' in document.createElement('a')) && 'getSelection' in window) {
});
}
const tran = useLocaleNotVue;
const debug = new Debug('input') as any;
function InputRuntime(this: any) {
@ -400,27 +398,6 @@ function InputRuntime(this: any) {
};
setupFsm();
// edit entrance in hotbox
const setupHotbox = () => {
this.hotbox.state('main').button({
position: 'center',
label: tran('minder.commons.edit'),
key: 'F2',
enable: () => {
if (isDisableNode(this.minder)) {
return false;
}
return this.minder.queryCommandState('text') !== -1;
},
action: this.editText,
beforeShow() {
this.$button.children[0].innerHTML = tran('minder.commons.edit');
},
});
};
setupHotbox();
}
export default InputRuntime;

View File

@ -1,5 +1,3 @@
const { HotBox } = window;
/**
* @Desc: 使receiver.enable()receiver.disable()
* div contenteditable属性的hack来解决开启热核后依然无法屏蔽浏览器输入的bug;
@ -15,13 +13,6 @@ interface IReceiver {
listen(type: string, callback: (e: KeyboardEvent) => void): void;
}
interface IHotbox {
state(): number;
$element: HTMLElement;
active(state: number): void;
dispatch(e: KeyboardEvent): void;
}
interface IMinder {
getSelectedNode(): any;
}
@ -36,7 +27,6 @@ interface IJumpingRuntime {
minder: IMinder;
receiver: IReceiver;
container: HTMLElement;
hotbox: IHotbox;
}
// Nice: http://unixpapa.com/js/key.html
@ -63,22 +53,12 @@ function isIntendToInput(e: KeyboardEvent): boolean {
}
function JumpingRuntime(this: IJumpingRuntime): void {
const { fsm, minder, receiver, container, hotbox } = this;
const { fsm, minder, receiver } = this;
const receiverElement = receiver.element;
// normal -> *
receiver.listen('normal', (e: KeyboardEvent) => {
// 为了防止处理进入edit模式而丢失处理的首字母,此时receiver必须为enable
receiver.enable();
// normal -> hotbox
if (e.code === 'Space') {
e.preventDefault();
// safari下Space触发hotbox,然而这时Space已在receiver上留下作案痕迹,因此抹掉
if (window.kity.Browser.safari) {
receiverElement.innerHTML = '';
}
return fsm.jump('hotbox', 'space-trigger');
}
/**
* check
* @editor Naixor
@ -104,15 +84,6 @@ function JumpingRuntime(this: IJumpingRuntime): void {
}
});
// hotbox -> normal
receiver.listen('hotbox', (e: KeyboardEvent) => {
receiver.disable();
e.preventDefault();
if (hotbox.state() === HotBox.STATE_IDLE && fsm.state() === 'hotbox') {
return fsm.jump('normal', 'hotbox-idle');
}
});
// input => normal
receiver.listen('input', (e: KeyboardEvent) => {
receiver.enable();
@ -133,68 +104,6 @@ function JumpingRuntime(this: IJumpingRuntime): void {
return fsm.jump('normal', 'input-cancel');
}
});
/// ///////////////////////////////////////////
/// 右键呼出热盒
/// 判断的标准是:按下的位置和结束的位置一致
/// ///////////////////////////////////////////
let downX: number;
let downY: number;
const MOUSE_LB = 1; // 左键
const MOUSE_RB = 2; // 右键
container.addEventListener(
'mousedown',
(e: MouseEvent) => {
if (e.button === MOUSE_RB) {
e.preventDefault();
}
if (fsm.state() === 'hotbox' && e.button === MOUSE_LB) {
fsm.jump('normal', 'blur');
} else if (e.button === MOUSE_RB) {
downX = e.clientX;
downY = e.clientY;
}
},
false
);
container.addEventListener(
'mousewheel',
() => {
if (fsm.state() === 'hotbox') {
fsm.jump('normal', 'mousemove-blur');
}
},
false
);
container.addEventListener('contextmenu', (e: MouseEvent) => {
e.preventDefault();
});
container.addEventListener(
'mouseup',
(e) => {
if (fsm.state() !== 'normal' && e.button === MOUSE_LB) {
return;
}
if (e.button !== MOUSE_RB || e.clientX !== downX || e.clientY !== downY) {
return;
}
if (!minder.getSelectedNode()) {
return false;
}
fsm.jump('hotbox', 'content-menu');
},
false
);
// 阻止热盒事件冒泡,在热盒正确执行前导致热盒关闭
hotbox.$element.addEventListener('mousedown', (e) => {
e.stopPropagation();
});
}
export default JumpingRuntime;

View File

@ -1,113 +0,0 @@
import useLocaleNotVue from '../tool/useLocaleNotVue';
import { isDeleteDisableNode, isDisableNode, markDeleteNode } from '../tool/utils';
const tran = useLocaleNotVue;
const buttons = [
`minder.menu.move.forward:Alt+Up:ArrangeUp`,
`minder.menu.insert._down:Tab|Insert:AppendChildNode`,
`minder.menu.insert._same:Enter:AppendSiblingNode`,
`minder.menu.move.backward:Alt+Down:ArrangeDown`,
`minder.commons.delete:Delete|Backspace:RemoveNode`,
`minder.menu.insert._up:Shift+Tab|Shift+Insert:AppendParentNode`,
];
export default function NodeRuntime(this: { minder: any; hotbox: any; editText: () => any }) {
const { minder, hotbox } = this;
// eslint-disable-next-line @typescript-eslint/no-this-alias
const runtime = this;
const main = hotbox.state('main');
let AppendLock = 0;
buttons.forEach((button: string) => {
const parts = button.split(':');
const label = parts.shift();
const key = parts.shift();
const command = parts.shift() || '';
main.button({
position: 'ring',
label: tran(label || ''),
key,
action() {
if (command?.indexOf('Append') === 0) {
AppendLock++;
minder.execCommand(command, tran('minder.main.subject.branch'));
const afterAppend = () => {
if (!--AppendLock) {
runtime.editText();
}
minder.off('layoutallfinish', afterAppend);
};
minder.on('layoutallfinish', afterAppend);
} else {
if (command.indexOf('RemoveNode') > -1) {
if (window.minderProps?.delConfirm) {
// 如果有删除确认,不删除,调用确认方法
window.minderProps.delConfirm();
return;
}
markDeleteNode(minder);
} else if (command.indexOf('ArrangeUp') > -1 || command.indexOf('ArrangeDown') > -1) {
if (
!window.minderProps.moveEnable ||
(window.minderProps.moveConfirm && !window.minderProps.moveConfirm())
) {
return;
}
}
minder.execCommand(command);
}
},
enable() {
if (command.indexOf('RemoveNode') > -1) {
if (
isDeleteDisableNode(minder) &&
command.indexOf('AppendChildNode') < 0 &&
command.indexOf('AppendSiblingNode') < 0
) {
return false;
}
} else if (command.indexOf('ArrangeUp') > 0 || command.indexOf('ArrangeDown') > 0) {
if (!minder.moveEnable) {
return false;
}
} else if (command.indexOf('AppendChildNode') < 0 && command.indexOf('AppendSiblingNode') < 0) {
if (isDisableNode(minder)) return false;
}
const node = minder.getSelectedNode();
if (node && node.parent === null && command.indexOf('AppendSiblingNode') > -1) {
return false;
}
return minder.queryCommandState(command) !== -1;
},
beforeShow() {
this.$button.children[0].innerHTML = tran(label || '');
},
});
});
main.button({
position: 'ring',
key: '/',
action() {
if (!minder.queryCommandState('expand')) {
minder.execCommand('expand');
} else if (!minder.queryCommandState('collapse')) {
minder.execCommand('collapse');
}
},
enable() {
return minder.queryCommandState('expand') !== -1 || minder.queryCommandState('collapse') !== -1;
},
beforeShow() {
if (!minder.queryCommandState('expand')) {
this.$button.children[0].innerHTML = tran('minder.menu.expand.expand');
} else {
this.$button.children[0].innerHTML = tran('minder.menu.expand.folding');
}
},
});
}

View File

@ -1,50 +0,0 @@
import useLocaleNotVue from '../tool/useLocaleNotVue';
import { isDisableNode } from '../tool/utils';
const tran = useLocaleNotVue;
export default function PriorityRuntime(this: any): void {
const { minder, hotbox } = this;
const main = hotbox.state('main');
main.button({
position: 'top',
label: tran('minder.main.priority'),
key: 'P',
next: 'priority',
enable() {
if (isDisableNode(minder)) {
return false;
}
return minder.queryCommandState('priority') !== -1;
},
beforeShow() {
this.$button.children[0].innerHTML = tran('minder.main.priority');
},
});
const priority = hotbox.state('priority');
priority.button({
position: 'center',
label: tran('minder.commons.remove'),
key: 'Del',
action() {
minder.execCommand('Priority', 0);
},
beforeShow() {
this.$button.children[0].innerHTML = tran('minder.commons.remove');
},
});
priority.button({
position: 'top',
label: tran('minder.commons.return'),
key: 'esc',
beforeShow() {
this.$button.children[0].innerHTML = tran('minder.commons.return');
},
next: 'back',
});
}

View File

@ -1,53 +0,0 @@
import { useI18n } from '@/hooks/useI18n';
import { isDisableNode } from '../tool/utils';
const { t } = useI18n();
export default function ProgressRuntime(this: any) {
const { minder, hotbox } = this;
const main = hotbox.state('main');
main.button({
position: 'top',
label: t('minder.menu.progress.progress'),
key: 'G',
next: 'progress',
enable() {
if (isDisableNode(minder)) {
return false;
}
return minder.queryCommandState('progress') !== -1;
},
});
const progress = hotbox.state('progress');
'012345678'.replace(/./g, (p) => {
progress.button({
position: 'ring',
label: `G${p}`,
key: p,
action() {
minder.execCommand('Progress', parseInt(p, 10) + 1);
},
});
return p;
});
progress.button({
position: 'center',
label: t('minder.commons.remove'),
key: 'Del',
action() {
minder.execCommand('Progress', 0);
},
});
progress.button({
position: 'top',
label: t('minder.commons.return'),
key: 'esc',
next: 'back',
});
}

View File

@ -95,10 +95,9 @@ function ReceiverRuntime(this: any) {
this.minder.on('beforemousedown', receiver.selectAll);
this.minder.on('receiverfocus', receiver.selectAll);
this.minder.on('readonly', () => {
// 屏蔽 minder 的事件接受,删除 receiver 和 hotbox
// 屏蔽 minder 的事件接受,删除 receiver
this.minder.disable();
window.editor.receiver.element.parentElement.removeChild(window.editor.receiver.element);
window.editor.hotbox.$container.removeChild(window.editor.hotbox.$element);
});
this.receiver = receiver as any;

View File

@ -1,50 +0,0 @@
import useLocaleNotVue from '../tool/useLocaleNotVue';
import { isDisableNode, isTagEnable } from '../tool/utils';
const tran = useLocaleNotVue;
// eslint-disable-next-line no-unused-vars
export default function TagRuntime(this: any) {
const { minder, hotbox } = this;
const main = hotbox.state('main');
main.button({
position: 'top',
label: tran('minder.main.tag'),
key: 'H',
next: 'tag',
enable() {
if (isDisableNode(minder) && !isTagEnable(minder)) {
return false;
}
return minder.queryCommandState('tag') !== -1;
},
beforeShow() {
this.$button.children[0].innerHTML = tran('minder.main.tag');
},
});
const tag = hotbox.state('tag');
tag.button({
position: 'center',
label: tran('minder.commons.remove'),
key: 'Del',
action() {
minder.execCommand('Tag', 0);
},
beforeShow() {
this.$button.children[0].innerHTML = tran('minder.commons.remove');
},
});
tag.button({
position: 'top',
label: tran('minder.commons.return'),
key: 'esc',
beforeShow() {
this.$button.children[0].innerHTML = tran('minder.commons.return');
},
next: 'back',
});
}

View File

@ -62,19 +62,3 @@ div.minder-editor-container {
width: 2px;
background-color: rgb(251 251 251);
}
.hotbox .state .button.enabled.selected .key,
.hotbox .state .ring .key {
margin-top: 5px;
font-size: 13px;
}
.hotbox .state .bottom .button .label,
.hotbox .state .top .button .label {
@apply font-semibold;
}
.hotbox .exp .ring .button .label {
margin-top: 28px;
margin-left: -2px;
}
.hotbox .exp .ring .button .key {
@apply hidden;
}