tiptap: fix mind

This commit is contained in:
fantasticit 2022-08-19 18:20:56 +08:00
parent 3b68238249
commit acd266acc0
9 changed files with 112 additions and 28 deletions

View File

@ -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;

View File

@ -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',

View File

@ -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');

View File

@ -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();
}

View File

@ -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();

View File

@ -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,10 +77,15 @@ 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;
if (minder.getStatus() !== 'readonly') {
updatePosition();
}
});
if (minder.getStatus() !== 'readonly') {
updatePosition();
}
}
// edit entrance in hotbox
function setupHotbox() {
hotbox.state('main').button({
@ -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;

View File

@ -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();
});
}

View File

@ -46,7 +46,14 @@ export const MindSettingModal: React.FC<IProps> = ({ 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]);

View File

@ -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 (
<NodeViewWrapper className={cls(styles.wrap, isActive && styles.isActive)}>
<VisibilitySensor onChange={onViewportChange}>
@ -123,8 +114,8 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
{loading && <Spin spinning style={INHERIT_SIZE_STYLE}></Spin>}
{!loading && !error && visible && (
<div style={{ height: '100%', maxHeight: '100%', overflow: 'hidden' }} ref={setMind}></div>
{!loading && !error && (
<div style={{ height: '100%', maxHeight: '100%', overflow: 'hidden' }} ref={$div}></div>
)}
<div className={styles.title}>