mirror of https://github.com/fantasticit/think.git
tiptap: fix mind
This commit is contained in:
parent
3b68238249
commit
acd266acc0
|
@ -24,15 +24,25 @@ export function renderMind(options: Options) {
|
||||||
const Editor = window.kityminder.Editor;
|
const Editor = window.kityminder.Editor;
|
||||||
const editor = new Editor(options.container);
|
const editor = new Editor(options.container);
|
||||||
const mind = editor.minder;
|
const mind = editor.minder;
|
||||||
|
mind.editor = editor;
|
||||||
|
|
||||||
options.data && mind.importJson(options.data);
|
options.data && mind.importJson(options.data);
|
||||||
|
|
||||||
if (!options.isEditable) {
|
if (!options.isEditable) {
|
||||||
mind.disable();
|
mind.disable();
|
||||||
|
mind.setStatus('readonly');
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
mind.execCommand('camera');
|
mind.execCommand('camera');
|
||||||
|
|
||||||
|
if (!options.isEditable) {
|
||||||
|
const selectedNodes = mind.getSelectedNodes();
|
||||||
|
|
||||||
|
if (selectedNodes.length) {
|
||||||
|
mind.removeSelectedNodes(selectedNodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
return mind;
|
return mind;
|
||||||
|
|
|
@ -138,6 +138,9 @@ define(function (require, exports, module) {
|
||||||
},
|
},
|
||||||
|
|
||||||
_bindEvents: function () {
|
_bindEvents: function () {
|
||||||
|
if (this.getStatus() === 'readonly') {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
/* jscs:disable maximumLineLength */
|
/* jscs:disable maximumLineLength */
|
||||||
this._paper.on(
|
this._paper.on(
|
||||||
'click dblclick mousedown contextmenu mouseup mousemove mouseover mousewheel DOMMouseScroll touchstart touchmove touchend dragenter dragleave drop',
|
'click dblclick mousedown contextmenu mouseup mousemove mouseover mousewheel DOMMouseScroll touchstart touchmove touchend dragenter dragleave drop',
|
||||||
|
|
|
@ -17,6 +17,10 @@ define(function (require, exports, module) {
|
||||||
|
|
||||||
kity.extendClass(Minder, {
|
kity.extendClass(Minder, {
|
||||||
focus: function () {
|
focus: function () {
|
||||||
|
if (this.getStatus() === 'readonly') {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.isFocused()) {
|
if (!this.isFocused()) {
|
||||||
var renderTarget = this._renderTarget;
|
var renderTarget = this._renderTarget;
|
||||||
renderTarget.classList.add('focus');
|
renderTarget.classList.add('focus');
|
||||||
|
|
|
@ -23,6 +23,10 @@ define(function (require, exports, module) {
|
||||||
|
|
||||||
kity.extendClass(Minder, {
|
kity.extendClass(Minder, {
|
||||||
_initKeyReceiver: function () {
|
_initKeyReceiver: function () {
|
||||||
|
if (this.getStatus() === 'readonly') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this._keyReceiver) return;
|
if (this._keyReceiver) return;
|
||||||
|
|
||||||
var receiver = (this._keyReceiver = document.createElement('input'));
|
var receiver = (this._keyReceiver = document.createElement('input'));
|
||||||
|
@ -34,6 +38,10 @@ define(function (require, exports, module) {
|
||||||
var minder = this;
|
var minder = this;
|
||||||
|
|
||||||
listen(receiver, 'keydown keyup keypress copy paste blur focus input', function (e) {
|
listen(receiver, 'keydown keyup keypress copy paste blur focus input', function (e) {
|
||||||
|
if (minder.getStatus() === 'readonly') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (e.type) {
|
switch (e.type) {
|
||||||
case 'blur':
|
case 'blur':
|
||||||
minder.blur();
|
minder.blur();
|
||||||
|
@ -50,14 +58,24 @@ define(function (require, exports, module) {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.on('focus', function () {
|
this.on('focus', function () {
|
||||||
|
if (this.getStatus() === 'readonly') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
receiver.select();
|
receiver.select();
|
||||||
receiver.focus();
|
receiver.focus();
|
||||||
});
|
});
|
||||||
this.on('blur', function () {
|
this.on('blur', function () {
|
||||||
|
if (this.getStatus() === 'readonly') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
receiver.blur();
|
receiver.blur();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.isFocused()) {
|
if (this.isFocused()) {
|
||||||
|
if (this.getStatus() === 'readonly') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
receiver.select();
|
receiver.select();
|
||||||
receiver.focus();
|
receiver.focus();
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,6 +142,8 @@ define(function (require, exports, module) {
|
||||||
|
|
||||||
initEvent: function (node) {
|
initEvent: function (node) {
|
||||||
this.on('mousedown', function (e) {
|
this.on('mousedown', function (e) {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
|
|
||||||
minder.select([node], true);
|
minder.select([node], true);
|
||||||
if (node.isExpanded()) {
|
if (node.isExpanded()) {
|
||||||
node.collapse();
|
node.collapse();
|
||||||
|
|
|
@ -21,9 +21,11 @@ define(function (require, exports, module) {
|
||||||
var receiverElement = receiver.element;
|
var receiverElement = receiver.element;
|
||||||
var isGecko = window.kity.Browser.gecko;
|
var isGecko = window.kity.Browser.gecko;
|
||||||
// setup everything to go
|
// setup everything to go
|
||||||
|
|
||||||
setupReciverElement();
|
setupReciverElement();
|
||||||
setupFsm();
|
setupFsm();
|
||||||
setupHotbox();
|
setupHotbox();
|
||||||
|
|
||||||
// expose editText()
|
// expose editText()
|
||||||
this.editText = editText;
|
this.editText = editText;
|
||||||
// listen the fsm changes, make action.
|
// listen the fsm changes, make action.
|
||||||
|
@ -32,6 +34,8 @@ define(function (require, exports, module) {
|
||||||
fsm.when('* -> input', enterInputMode);
|
fsm.when('* -> input', enterInputMode);
|
||||||
// when exited, commit or exit depends on the exit reason
|
// when exited, commit or exit depends on the exit reason
|
||||||
fsm.when('input -> *', function (exit, enter, reason) {
|
fsm.when('input -> *', function (exit, enter, reason) {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
|
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case 'input-cancel':
|
case 'input-cancel':
|
||||||
return exitInputMode();
|
return exitInputMode();
|
||||||
|
@ -43,11 +47,15 @@ define(function (require, exports, module) {
|
||||||
});
|
});
|
||||||
// lost focus to commit
|
// lost focus to commit
|
||||||
receiver.onblur(function (e) {
|
receiver.onblur(function (e) {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
|
|
||||||
if (fsm.state() == 'input') {
|
if (fsm.state() == 'input') {
|
||||||
fsm.jump('normal', 'input-commit');
|
fsm.jump('normal', 'input-commit');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
minder.on('beforemousedown', function () {
|
minder.on('beforemousedown', function () {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
|
|
||||||
if (fsm.state() == 'input') {
|
if (fsm.state() == 'input') {
|
||||||
fsm.jump('normal', 'input-commit');
|
fsm.jump('normal', 'input-commit');
|
||||||
}
|
}
|
||||||
|
@ -69,9 +77,14 @@ define(function (require, exports, module) {
|
||||||
minder.on('layoutallfinish viewchange viewchanged selectionchange', function (e) {
|
minder.on('layoutallfinish viewchange viewchanged selectionchange', function (e) {
|
||||||
// viewchange event is too frequenced, lazy it
|
// viewchange event is too frequenced, lazy it
|
||||||
if (e.type == 'viewchange' && fsm.state() != 'input') return;
|
if (e.type == 'viewchange' && fsm.state() != 'input') return;
|
||||||
updatePosition();
|
|
||||||
|
if (minder.getStatus() !== 'readonly') {
|
||||||
|
updatePosition();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
updatePosition();
|
if (minder.getStatus() !== 'readonly') {
|
||||||
|
updatePosition();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// edit entrance in hotbox
|
// edit entrance in hotbox
|
||||||
function setupHotbox() {
|
function setupHotbox() {
|
||||||
|
@ -121,6 +134,8 @@ define(function (require, exports, module) {
|
||||||
* @Date 2015-12-2
|
* @Date 2015-12-2
|
||||||
*/
|
*/
|
||||||
function enterInputMode() {
|
function enterInputMode() {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
|
|
||||||
var node = minder.getSelectedNode();
|
var node = minder.getSelectedNode();
|
||||||
if (node) {
|
if (node) {
|
||||||
var fontSize = node.getData('font-size') || node.getStyle('font-size');
|
var fontSize = node.getData('font-size') || node.getStyle('font-size');
|
||||||
|
@ -141,6 +156,13 @@ define(function (require, exports, module) {
|
||||||
* @Date: 2015.9.16
|
* @Date: 2015.9.16
|
||||||
*/
|
*/
|
||||||
function commitInputText(textNodes) {
|
function commitInputText(textNodes) {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
|
|
||||||
|
var node = minder.getSelectedNode();
|
||||||
|
if (!node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var text = '';
|
var text = '';
|
||||||
var TAB_CHAR = '\t',
|
var TAB_CHAR = '\t',
|
||||||
ENTER_CHAR = '\n',
|
ENTER_CHAR = '\n',
|
||||||
|
@ -282,6 +304,8 @@ define(function (require, exports, module) {
|
||||||
* @Date: 2015.9.16
|
* @Date: 2015.9.16
|
||||||
*/
|
*/
|
||||||
function commitInputNode(node, text) {
|
function commitInputNode(node, text) {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
minder.decodeData('text', text).then(function (json) {
|
minder.decodeData('text', text).then(function (json) {
|
||||||
function importText(node, json, minder) {
|
function importText(node, json, minder) {
|
||||||
|
@ -309,6 +333,8 @@ define(function (require, exports, module) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function commitInputResult() {
|
function commitInputResult() {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Desc: 进行如下处理:
|
* @Desc: 进行如下处理:
|
||||||
* 根据用户的输入判断是否生成新的节点
|
* 根据用户的输入判断是否生成新的节点
|
||||||
|
@ -338,10 +364,14 @@ define(function (require, exports, module) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function exitInputMode() {
|
function exitInputMode() {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
|
|
||||||
receiverElement.classList.remove('input');
|
receiverElement.classList.remove('input');
|
||||||
receiver.selectAll();
|
receiver.selectAll();
|
||||||
}
|
}
|
||||||
function updatePosition() {
|
function updatePosition() {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
|
|
||||||
var planed = updatePosition;
|
var planed = updatePosition;
|
||||||
var focusNode = minder.getSelectedNode();
|
var focusNode = minder.getSelectedNode();
|
||||||
if (!focusNode) return;
|
if (!focusNode) return;
|
||||||
|
|
|
@ -48,18 +48,26 @@ define(function (require, exports, module) {
|
||||||
var receiverElement = receiver.element;
|
var receiverElement = receiver.element;
|
||||||
var hotbox = this.hotbox;
|
var hotbox = this.hotbox;
|
||||||
var compositionLock = false;
|
var compositionLock = false;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
// normal -> *
|
// normal -> *
|
||||||
receiver.listen('normal', function (e) {
|
receiver.listen('normal', function (e) {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
// 为了防止处理进入edit模式而丢失处理的首字母,此时receiver必须为enable
|
// 为了防止处理进入edit模式而丢失处理的首字母,此时receiver必须为enable
|
||||||
receiver.enable();
|
receiver.enable();
|
||||||
// normal -> hotbox
|
// normal -> hotbox
|
||||||
if (e.is('Space')) {
|
if (e.is('Space')) {
|
||||||
|
// 非编辑模式
|
||||||
|
if (that.minder.getStatus() === 'readonly') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
// safari下Space触发hotbox,然而这时Space已在receiver上留下作案痕迹,因此抹掉
|
// safari下Space触发hotbox,然而这时Space已在receiver上留下作案痕迹,因此抹掉
|
||||||
if (kity.Browser.safari) {
|
if (kity.Browser.safari) {
|
||||||
receiverElement.innerHTML = '';
|
receiverElement.innerHTML = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return fsm.jump('hotbox', 'space-trigger');
|
return fsm.jump('hotbox', 'space-trigger');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +99,8 @@ define(function (require, exports, module) {
|
||||||
|
|
||||||
// hotbox -> normal
|
// hotbox -> normal
|
||||||
receiver.listen('hotbox', function (e) {
|
receiver.listen('hotbox', function (e) {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
|
|
||||||
receiver.disable();
|
receiver.disable();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var handleResult = hotbox.dispatch(e);
|
var handleResult = hotbox.dispatch(e);
|
||||||
|
@ -101,6 +111,8 @@ define(function (require, exports, module) {
|
||||||
|
|
||||||
// input => normal
|
// input => normal
|
||||||
receiver.listen('input', function (e) {
|
receiver.listen('input', function (e) {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
|
|
||||||
receiver.enable();
|
receiver.enable();
|
||||||
if (e.type == 'keydown') {
|
if (e.type == 'keydown') {
|
||||||
if (e.is('Enter')) {
|
if (e.is('Enter')) {
|
||||||
|
@ -138,6 +150,8 @@ define(function (require, exports, module) {
|
||||||
container.addEventListener(
|
container.addEventListener(
|
||||||
'mousedown',
|
'mousedown',
|
||||||
function (e) {
|
function (e) {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
|
|
||||||
if (e.button == MOUSE_RB) {
|
if (e.button == MOUSE_RB) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
@ -155,6 +169,8 @@ define(function (require, exports, module) {
|
||||||
container.addEventListener(
|
container.addEventListener(
|
||||||
'mousewheel',
|
'mousewheel',
|
||||||
function (e) {
|
function (e) {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
|
|
||||||
if (fsm.state() == 'hotbox') {
|
if (fsm.state() == 'hotbox') {
|
||||||
hotbox.active(Hotbox.STATE_IDLE);
|
hotbox.active(Hotbox.STATE_IDLE);
|
||||||
fsm.jump('normal', 'mousemove-blur');
|
fsm.jump('normal', 'mousemove-blur');
|
||||||
|
@ -164,12 +180,14 @@ define(function (require, exports, module) {
|
||||||
);
|
);
|
||||||
|
|
||||||
container.addEventListener('contextmenu', function (e) {
|
container.addEventListener('contextmenu', function (e) {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
container.addEventListener(
|
container.addEventListener(
|
||||||
'mouseup',
|
'mouseup',
|
||||||
function (e) {
|
function (e) {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
if (fsm.state() != 'normal') {
|
if (fsm.state() != 'normal') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -186,6 +204,7 @@ define(function (require, exports, module) {
|
||||||
|
|
||||||
// 阻止热盒事件冒泡,在热盒正确执行前导致热盒关闭
|
// 阻止热盒事件冒泡,在热盒正确执行前导致热盒关闭
|
||||||
hotbox.$element.addEventListener('mousedown', function (e) {
|
hotbox.$element.addEventListener('mousedown', function (e) {
|
||||||
|
if (minder._status === 'readonly') return;
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,14 @@ export const MindSettingModal: React.FC<IProps> = ({ editor }) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const data = mind.exportJson();
|
const data = mind.exportJson();
|
||||||
|
/**
|
||||||
|
* FIXME: 百度脑图更新后会滚动 dom 到顶点,原因未知,在此 hack 修复下!
|
||||||
|
*/
|
||||||
|
const currentScrollTop = document.querySelector('main#js-tocs-container')?.scrollTop;
|
||||||
editor.chain().focus().setMind({ data }).run();
|
editor.chain().focus().setMind({ data }).run();
|
||||||
|
setTimeout(() => {
|
||||||
|
document.querySelector('main#js-tocs-container').scrollTop = currentScrollTop;
|
||||||
|
});
|
||||||
toggleVisible(false);
|
toggleVisible(false);
|
||||||
}, [editor, toggleVisible, mind]);
|
}, [editor, toggleVisible, mind]);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ const { Text } = Typography;
|
||||||
const INHERIT_SIZE_STYLE = { width: '100%', height: '100%', maxWidth: '100%' };
|
const INHERIT_SIZE_STYLE = { width: '100%', height: '100%', maxWidth: '100%' };
|
||||||
|
|
||||||
export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
|
const $div = useRef(null);
|
||||||
const $mind = useRef(null);
|
const $mind = useRef(null);
|
||||||
const isEditable = editor.isEditable;
|
const isEditable = editor.isEditable;
|
||||||
const isActive = editor.isActive(Mind.name);
|
const isActive = editor.isActive(Mind.name);
|
||||||
|
@ -32,7 +33,7 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
const setCenter = useCallback(() => {
|
const setCenter = useCallback(() => {
|
||||||
const mind = $mind.current;
|
const mind = $mind.current;
|
||||||
if (!mind) return;
|
if (!mind) return;
|
||||||
mind.execCommand('camera');
|
mind.execCommand('camera', mind.getRoot(), 600);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const setZoom = useCallback((type: 'minus' | 'plus') => {
|
const setZoom = useCallback((type: 'minus' | 'plus') => {
|
||||||
|
@ -55,29 +56,6 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
[updateAttributes, setCenter]
|
[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(
|
const onViewportChange = useCallback(
|
||||||
(visible) => {
|
(visible) => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
|
@ -107,6 +85,19 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
setCenter();
|
setCenter();
|
||||||
}, [width, height, 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 (
|
return (
|
||||||
<NodeViewWrapper className={cls(styles.wrap, isActive && styles.isActive)}>
|
<NodeViewWrapper className={cls(styles.wrap, isActive && styles.isActive)}>
|
||||||
<VisibilitySensor onChange={onViewportChange}>
|
<VisibilitySensor onChange={onViewportChange}>
|
||||||
|
@ -123,8 +114,8 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
|
|
||||||
{loading && <Spin spinning style={INHERIT_SIZE_STYLE}></Spin>}
|
{loading && <Spin spinning style={INHERIT_SIZE_STYLE}></Spin>}
|
||||||
|
|
||||||
{!loading && !error && visible && (
|
{!loading && !error && (
|
||||||
<div style={{ height: '100%', maxHeight: '100%', overflow: 'hidden' }} ref={setMind}></div>
|
<div style={{ height: '100%', maxHeight: '100%', overflow: 'hidden' }} ref={$div}></div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className={styles.title}>
|
<div className={styles.title}>
|
||||||
|
|
Loading…
Reference in New Issue