From acd266acc011cb4c6e6eb5b44f71b91defa0c99a Mon Sep 17 00:00:00 2001 From: fantasticit Date: Fri, 19 Aug 2022 18:20:56 +0800 Subject: [PATCH] tiptap: fix mind --- .../client/src/thirtypart/kityminder/index.ts | 10 +++++ .../kityminder/kity-core/core/event.js | 3 ++ .../kityminder/kity-core/core/focus.js | 4 ++ .../kityminder/kity-core/core/keyreceiver.js | 18 ++++++++ .../kityminder/kity-core/module/expand.js | 2 + .../kityminder/kity-editor/runtime/input.js | 34 ++++++++++++++- .../kityminder/kity-editor/runtime/jumping.js | 19 ++++++++ .../src/tiptap/core/menus/mind/modal.tsx | 7 +++ .../src/tiptap/core/wrappers/mind/index.tsx | 43 ++++++++----------- 9 files changed, 112 insertions(+), 28 deletions(-) diff --git a/packages/client/src/thirtypart/kityminder/index.ts b/packages/client/src/thirtypart/kityminder/index.ts index 07a6c01a..bcbb7fd3 100644 --- a/packages/client/src/thirtypart/kityminder/index.ts +++ b/packages/client/src/thirtypart/kityminder/index.ts @@ -24,15 +24,25 @@ export function renderMind(options: Options) { const Editor = window.kityminder.Editor; const editor = new Editor(options.container); const mind = editor.minder; + mind.editor = editor; options.data && mind.importJson(options.data); if (!options.isEditable) { mind.disable(); + mind.setStatus('readonly'); } setTimeout(() => { mind.execCommand('camera'); + + if (!options.isEditable) { + const selectedNodes = mind.getSelectedNodes(); + + if (selectedNodes.length) { + mind.removeSelectedNodes(selectedNodes); + } + } }, 0); return mind; diff --git a/packages/client/src/thirtypart/kityminder/kity-core/core/event.js b/packages/client/src/thirtypart/kityminder/kity-core/core/event.js index 043bcf57..83201fb3 100644 --- a/packages/client/src/thirtypart/kityminder/kity-core/core/event.js +++ b/packages/client/src/thirtypart/kityminder/kity-core/core/event.js @@ -138,6 +138,9 @@ define(function (require, exports, module) { }, _bindEvents: function () { + if (this.getStatus() === 'readonly') { + return this; + } /* jscs:disable maximumLineLength */ this._paper.on( 'click dblclick mousedown contextmenu mouseup mousemove mouseover mousewheel DOMMouseScroll touchstart touchmove touchend dragenter dragleave drop', diff --git a/packages/client/src/thirtypart/kityminder/kity-core/core/focus.js b/packages/client/src/thirtypart/kityminder/kity-core/core/focus.js index e9785b1b..d12ae91e 100644 --- a/packages/client/src/thirtypart/kityminder/kity-core/core/focus.js +++ b/packages/client/src/thirtypart/kityminder/kity-core/core/focus.js @@ -17,6 +17,10 @@ define(function (require, exports, module) { kity.extendClass(Minder, { focus: function () { + if (this.getStatus() === 'readonly') { + return this; + } + if (!this.isFocused()) { var renderTarget = this._renderTarget; renderTarget.classList.add('focus'); diff --git a/packages/client/src/thirtypart/kityminder/kity-core/core/keyreceiver.js b/packages/client/src/thirtypart/kityminder/kity-core/core/keyreceiver.js index 53b0663e..12d8796d 100644 --- a/packages/client/src/thirtypart/kityminder/kity-core/core/keyreceiver.js +++ b/packages/client/src/thirtypart/kityminder/kity-core/core/keyreceiver.js @@ -23,6 +23,10 @@ define(function (require, exports, module) { kity.extendClass(Minder, { _initKeyReceiver: function () { + if (this.getStatus() === 'readonly') { + return; + } + if (this._keyReceiver) return; var receiver = (this._keyReceiver = document.createElement('input')); @@ -34,6 +38,10 @@ define(function (require, exports, module) { var minder = this; listen(receiver, 'keydown keyup keypress copy paste blur focus input', function (e) { + if (minder.getStatus() === 'readonly') { + return; + } + switch (e.type) { case 'blur': minder.blur(); @@ -50,14 +58,24 @@ define(function (require, exports, module) { }); this.on('focus', function () { + if (this.getStatus() === 'readonly') { + return; + } receiver.select(); receiver.focus(); }); this.on('blur', function () { + if (this.getStatus() === 'readonly') { + return; + } receiver.blur(); }); if (this.isFocused()) { + if (this.getStatus() === 'readonly') { + return; + } + receiver.select(); receiver.focus(); } diff --git a/packages/client/src/thirtypart/kityminder/kity-core/module/expand.js b/packages/client/src/thirtypart/kityminder/kity-core/module/expand.js index e8fc84f1..880f4892 100644 --- a/packages/client/src/thirtypart/kityminder/kity-core/module/expand.js +++ b/packages/client/src/thirtypart/kityminder/kity-core/module/expand.js @@ -142,6 +142,8 @@ define(function (require, exports, module) { initEvent: function (node) { this.on('mousedown', function (e) { + if (minder._status === 'readonly') return; + minder.select([node], true); if (node.isExpanded()) { node.collapse(); diff --git a/packages/client/src/thirtypart/kityminder/kity-editor/runtime/input.js b/packages/client/src/thirtypart/kityminder/kity-editor/runtime/input.js index 1bb3a9d2..9f5fc1d3 100644 --- a/packages/client/src/thirtypart/kityminder/kity-editor/runtime/input.js +++ b/packages/client/src/thirtypart/kityminder/kity-editor/runtime/input.js @@ -21,9 +21,11 @@ define(function (require, exports, module) { var receiverElement = receiver.element; var isGecko = window.kity.Browser.gecko; // setup everything to go + setupReciverElement(); setupFsm(); setupHotbox(); + // expose editText() this.editText = editText; // listen the fsm changes, make action. @@ -32,6 +34,8 @@ define(function (require, exports, module) { fsm.when('* -> input', enterInputMode); // when exited, commit or exit depends on the exit reason fsm.when('input -> *', function (exit, enter, reason) { + if (minder._status === 'readonly') return; + switch (reason) { case 'input-cancel': return exitInputMode(); @@ -43,11 +47,15 @@ define(function (require, exports, module) { }); // lost focus to commit receiver.onblur(function (e) { + if (minder._status === 'readonly') return; + if (fsm.state() == 'input') { fsm.jump('normal', 'input-commit'); } }); minder.on('beforemousedown', function () { + if (minder._status === 'readonly') return; + if (fsm.state() == 'input') { fsm.jump('normal', 'input-commit'); } @@ -69,9 +77,14 @@ define(function (require, exports, module) { minder.on('layoutallfinish viewchange viewchanged selectionchange', function (e) { // viewchange event is too frequenced, lazy it if (e.type == 'viewchange' && fsm.state() != 'input') return; - updatePosition(); + + if (minder.getStatus() !== 'readonly') { + updatePosition(); + } }); - updatePosition(); + if (minder.getStatus() !== 'readonly') { + updatePosition(); + } } // edit entrance in hotbox function setupHotbox() { @@ -121,6 +134,8 @@ define(function (require, exports, module) { * @Date 2015-12-2 */ function enterInputMode() { + if (minder._status === 'readonly') return; + var node = minder.getSelectedNode(); if (node) { var fontSize = node.getData('font-size') || node.getStyle('font-size'); @@ -141,6 +156,13 @@ define(function (require, exports, module) { * @Date: 2015.9.16 */ function commitInputText(textNodes) { + if (minder._status === 'readonly') return; + + var node = minder.getSelectedNode(); + if (!node) { + return; + } + var text = ''; var TAB_CHAR = '\t', ENTER_CHAR = '\n', @@ -282,6 +304,8 @@ define(function (require, exports, module) { * @Date: 2015.9.16 */ function commitInputNode(node, text) { + if (minder._status === 'readonly') return; + try { minder.decodeData('text', text).then(function (json) { function importText(node, json, minder) { @@ -309,6 +333,8 @@ define(function (require, exports, module) { } } function commitInputResult() { + if (minder._status === 'readonly') return; + /** * @Desc: 进行如下处理: * 根据用户的输入判断是否生成新的节点 @@ -338,10 +364,14 @@ define(function (require, exports, module) { } } function exitInputMode() { + if (minder._status === 'readonly') return; + receiverElement.classList.remove('input'); receiver.selectAll(); } function updatePosition() { + if (minder._status === 'readonly') return; + var planed = updatePosition; var focusNode = minder.getSelectedNode(); if (!focusNode) return; diff --git a/packages/client/src/thirtypart/kityminder/kity-editor/runtime/jumping.js b/packages/client/src/thirtypart/kityminder/kity-editor/runtime/jumping.js index 83e8426d..0b084efc 100644 --- a/packages/client/src/thirtypart/kityminder/kity-editor/runtime/jumping.js +++ b/packages/client/src/thirtypart/kityminder/kity-editor/runtime/jumping.js @@ -48,18 +48,26 @@ define(function (require, exports, module) { var receiverElement = receiver.element; var hotbox = this.hotbox; var compositionLock = false; + var that = this; // normal -> * receiver.listen('normal', function (e) { + if (minder._status === 'readonly') return; // 为了防止处理进入edit模式而丢失处理的首字母,此时receiver必须为enable receiver.enable(); // normal -> hotbox if (e.is('Space')) { + // 非编辑模式 + if (that.minder.getStatus() === 'readonly') { + return; + } + e.preventDefault(); // safari下Space触发hotbox,然而这时Space已在receiver上留下作案痕迹,因此抹掉 if (kity.Browser.safari) { receiverElement.innerHTML = ''; } + return fsm.jump('hotbox', 'space-trigger'); } @@ -91,6 +99,8 @@ define(function (require, exports, module) { // hotbox -> normal receiver.listen('hotbox', function (e) { + if (minder._status === 'readonly') return; + receiver.disable(); e.preventDefault(); var handleResult = hotbox.dispatch(e); @@ -101,6 +111,8 @@ define(function (require, exports, module) { // input => normal receiver.listen('input', function (e) { + if (minder._status === 'readonly') return; + receiver.enable(); if (e.type == 'keydown') { if (e.is('Enter')) { @@ -138,6 +150,8 @@ define(function (require, exports, module) { container.addEventListener( 'mousedown', function (e) { + if (minder._status === 'readonly') return; + if (e.button == MOUSE_RB) { e.preventDefault(); } @@ -155,6 +169,8 @@ define(function (require, exports, module) { container.addEventListener( 'mousewheel', function (e) { + if (minder._status === 'readonly') return; + if (fsm.state() == 'hotbox') { hotbox.active(Hotbox.STATE_IDLE); fsm.jump('normal', 'mousemove-blur'); @@ -164,12 +180,14 @@ define(function (require, exports, module) { ); container.addEventListener('contextmenu', function (e) { + if (minder._status === 'readonly') return; e.preventDefault(); }); container.addEventListener( 'mouseup', function (e) { + if (minder._status === 'readonly') return; if (fsm.state() != 'normal') { return; } @@ -186,6 +204,7 @@ define(function (require, exports, module) { // 阻止热盒事件冒泡,在热盒正确执行前导致热盒关闭 hotbox.$element.addEventListener('mousedown', function (e) { + if (minder._status === 'readonly') return; e.stopPropagation(); }); } diff --git a/packages/client/src/tiptap/core/menus/mind/modal.tsx b/packages/client/src/tiptap/core/menus/mind/modal.tsx index f9518dc8..63cc322a 100644 --- a/packages/client/src/tiptap/core/menus/mind/modal.tsx +++ b/packages/client/src/tiptap/core/menus/mind/modal.tsx @@ -46,7 +46,14 @@ export const MindSettingModal: React.FC = ({ editor }) => { return; } const data = mind.exportJson(); + /** + * FIXME: 百度脑图更新后会滚动 dom 到顶点,原因未知,在此 hack 修复下! + */ + const currentScrollTop = document.querySelector('main#js-tocs-container')?.scrollTop; editor.chain().focus().setMind({ data }).run(); + setTimeout(() => { + document.querySelector('main#js-tocs-container').scrollTop = currentScrollTop; + }); toggleVisible(false); }, [editor, toggleVisible, mind]); diff --git a/packages/client/src/tiptap/core/wrappers/mind/index.tsx b/packages/client/src/tiptap/core/wrappers/mind/index.tsx index f914af24..383ee4ce 100644 --- a/packages/client/src/tiptap/core/wrappers/mind/index.tsx +++ b/packages/client/src/tiptap/core/wrappers/mind/index.tsx @@ -20,6 +20,7 @@ const { Text } = Typography; const INHERIT_SIZE_STYLE = { width: '100%', height: '100%', maxWidth: '100%' }; export const MindWrapper = ({ editor, node, updateAttributes }) => { + const $div = useRef(null); const $mind = useRef(null); const isEditable = editor.isEditable; const isActive = editor.isActive(Mind.name); @@ -32,7 +33,7 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => { const setCenter = useCallback(() => { const mind = $mind.current; if (!mind) return; - mind.execCommand('camera'); + mind.execCommand('camera', mind.getRoot(), 600); }, []); const setZoom = useCallback((type: 'minus' | 'plus') => { @@ -55,29 +56,6 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => { [updateAttributes, setCenter] ); - const render = useCallback( - (div) => { - if (!div) return; - - if (!$mind.current) { - const graph = renderMind({ - container: div, - data, - isEditable: false, - }); - $mind.current = graph; - } - }, - [data] - ); - - const setMind = useCallback( - (div) => { - render(div); - }, - [render] - ); - const onViewportChange = useCallback( (visible) => { if (visible) { @@ -107,6 +85,19 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => { setCenter(); }, [width, height, setCenter]); + useEffect(() => { + if (visible && !loading && !error) { + if (!$mind.current) { + const graph = renderMind({ + container: $div.current, + data, + isEditable: false, + }); + $mind.current = graph; + } + } + }, [visible, data, loading, error]); + return ( @@ -123,8 +114,8 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => { {loading && } - {!loading && !error && visible && ( -
+ {!loading && !error && ( +
)}