@seafile/sdoc-editor 0.5.55 → 0.5.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/basic-sdk/assets/css/layout.css +3 -0
- package/dist/basic-sdk/assets/css/simple-viewer.css +1 -1
- package/dist/basic-sdk/editor/editable-article.js +36 -3
- package/dist/basic-sdk/extension/core/queries/index.js +23 -0
- package/dist/basic-sdk/extension/plugins/check-list/plugin.js +5 -0
- package/dist/components/doc-operations/revision-operations/index.js +24 -39
- package/dist/pages/simple-viewer.js +21 -1
- package/package.json +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, { useCallback, useMemo, Fragment } from 'react';
|
|
2
2
|
import { Editable, ReactEditor, Slate } from '@seafile/slate-react';
|
|
3
|
-
import { Editor, Node,
|
|
3
|
+
import { Editor, Node, Transforms } from '@seafile/slate';
|
|
4
4
|
import scrollIntoView from 'scroll-into-view-if-needed';
|
|
5
5
|
import { renderLeaf, renderElement, ContextToolbar, SideToolbar } from '../extension';
|
|
6
|
-
import { getAboveBlockNode, getNextNode, getPrevNode, isSelectionAtBlockEnd, isSelectionAtBlockStart } from '../extension/core';
|
|
6
|
+
import { getAboveBlockNode, getNextNode, getPrevNode, isSelectionAtBlockEnd, isSelectionAtBlockStart, getCurrentNode, isCurrentLineEmpty, isCurrentLineHasText } from '../extension/core';
|
|
7
7
|
import EventProxy from '../utils/event-handler';
|
|
8
8
|
import { useCursors } from '../cursor/use-cursors';
|
|
9
9
|
import { INTERNAL_EVENT } from '../constants';
|
|
@@ -14,7 +14,7 @@ import EventBus from '../utils/event-bus';
|
|
|
14
14
|
import { ArticleContainer } from '../layout';
|
|
15
15
|
import { useScrollContext } from '../hooks/use-scroll-context';
|
|
16
16
|
import { SetNodeToDecorations } from '../highlight';
|
|
17
|
-
import { IMAGE, IMAGE_BLOCK } from '../extension/constants';
|
|
17
|
+
import { IMAGE, IMAGE_BLOCK, CODE_LINE } from '../extension/constants';
|
|
18
18
|
import { isPreventResetTableSelectedRange } from '../extension/plugins/table/helpers';
|
|
19
19
|
const EditableArticle = _ref => {
|
|
20
20
|
let {
|
|
@@ -83,6 +83,39 @@ const EditableArticle = _ref => {
|
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
85
|
if (event.key === 'Backspace') {
|
|
86
|
+
const [currentNode] = getCurrentNode(editor);
|
|
87
|
+
let prevNode = null;
|
|
88
|
+
let prevPath = null;
|
|
89
|
+
if (getPrevNode(editor)) {
|
|
90
|
+
[prevNode, prevPath] = getPrevNode(editor);
|
|
91
|
+
}
|
|
92
|
+
// If the cursor is at the beginning, and the current line is not empty, is not a CODE_LINE, and the previous line is a CODE_LINE.
|
|
93
|
+
if (prevNode && isSelectionAtBlockStart(editor) && !isCurrentLineEmpty(editor) && prevNode.type === CODE_LINE && currentNode.type !== CODE_LINE) {
|
|
94
|
+
if (!isCurrentLineHasText(currentNode)) {
|
|
95
|
+
const prevNodeText = Node.string(prevNode);
|
|
96
|
+
Transforms.removeNodes(editor, {
|
|
97
|
+
at: prevPath
|
|
98
|
+
});
|
|
99
|
+
Transforms.insertText(editor, prevNodeText);
|
|
100
|
+
event.preventDefault();
|
|
101
|
+
} else {
|
|
102
|
+
const path = prevPath;
|
|
103
|
+
path[path.length] = 0;
|
|
104
|
+
const end = prevNode.children[0].text.length;
|
|
105
|
+
const range = {
|
|
106
|
+
anchor: {
|
|
107
|
+
path,
|
|
108
|
+
offset: end
|
|
109
|
+
},
|
|
110
|
+
focus: {
|
|
111
|
+
path,
|
|
112
|
+
offset: end
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
Transforms.select(editor, range);
|
|
116
|
+
event.preventDefault();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
86
119
|
const {
|
|
87
120
|
y
|
|
88
121
|
} = getCursorPosition();
|
|
@@ -250,6 +250,15 @@ export const getPrevNode = editor => {
|
|
|
250
250
|
}
|
|
251
251
|
return prevNode;
|
|
252
252
|
};
|
|
253
|
+
export const getCurrentNode = editor => {
|
|
254
|
+
if (!editor.selection) return null;
|
|
255
|
+
const [nodeEntry] = Editor.nodes(editor, {
|
|
256
|
+
at: editor.selection,
|
|
257
|
+
match: n => Element.isElement(n) && Editor.isBlock(editor, n),
|
|
258
|
+
mode: 'lowest'
|
|
259
|
+
});
|
|
260
|
+
return nodeEntry || null;
|
|
261
|
+
};
|
|
253
262
|
export const getNextNode = editor => {
|
|
254
263
|
const [lowerNode, lowerPath] = getAboveNode(editor, {
|
|
255
264
|
mode: 'lowest',
|
|
@@ -423,4 +432,18 @@ export const isHasImg = editor => {
|
|
|
423
432
|
}
|
|
424
433
|
}
|
|
425
434
|
return hasImg;
|
|
435
|
+
};
|
|
436
|
+
export const isCurrentLineEmpty = editor => {
|
|
437
|
+
const {
|
|
438
|
+
selection
|
|
439
|
+
} = editor;
|
|
440
|
+
if (!selection || !ReactEditor.isFocused(editor)) return false;
|
|
441
|
+
const [node] = Editor.node(editor, selection.focus.path.slice(0, -1));
|
|
442
|
+
if (Element.isElement(node)) {
|
|
443
|
+
return node.children.every(child => Element.isElement(child) ? false : Node.string(child) === '');
|
|
444
|
+
}
|
|
445
|
+
return true;
|
|
446
|
+
};
|
|
447
|
+
export const isCurrentLineHasText = node => {
|
|
448
|
+
return Node.string(node).trim() !== '';
|
|
426
449
|
};
|
|
@@ -36,46 +36,31 @@ const RevisionOperations = _ref => {
|
|
|
36
36
|
if (!isSdocRevision) return;
|
|
37
37
|
if (isShowChanges) return;
|
|
38
38
|
if (isPublished) return;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
const baseVersionPromise = context.getRevisionBaseVersionContent();
|
|
47
|
-
const originVersionPromise = context.getSeadocOriginFileContent();
|
|
48
|
-
Promise.all([revisionPromise, baseVersionPromise, originVersionPromise]).then(results => {
|
|
49
|
-
const [revisionContent, baseRes, masterRes] = results;
|
|
50
|
-
const baseContent = JSON.parse(baseRes.data.content);
|
|
51
|
-
const masterContent = JSON.parse(masterRes.data.content);
|
|
52
|
-
timer = null;
|
|
39
|
+
const revisionPromise = loadDocument();
|
|
40
|
+
const baseVersionPromise = context.getRevisionBaseVersionContent();
|
|
41
|
+
const originVersionPromise = context.getSeadocOriginFileContent();
|
|
42
|
+
Promise.all([revisionPromise, baseVersionPromise, originVersionPromise]).then(results => {
|
|
43
|
+
const [revisionContent, baseRes, masterRes] = results;
|
|
44
|
+
const baseContent = JSON.parse(baseRes.data.content);
|
|
45
|
+
const masterContent = JSON.parse(masterRes.data.content);
|
|
53
46
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
toaster.danger(t('Error'));
|
|
72
|
-
setShowTip(false);
|
|
73
|
-
setTipType('');
|
|
74
|
-
});
|
|
75
|
-
}, 600);
|
|
76
|
-
return () => {
|
|
77
|
-
timer && clearTimeout(timer);
|
|
78
|
-
};
|
|
47
|
+
// no changes
|
|
48
|
+
if (masterContent.version === baseContent.version) return;
|
|
49
|
+
setShowTip(true);
|
|
50
|
+
const {
|
|
51
|
+
value
|
|
52
|
+
} = getRebase(masterContent, baseContent, revisionContent);
|
|
53
|
+
setMergeValue(value);
|
|
54
|
+
setTipType(TIP_TYPE.SOURCE_DOCUMENT_CHANGED);
|
|
55
|
+
}).catch(error => {
|
|
56
|
+
if (typeof error === 'string') {
|
|
57
|
+
toaster.danger(t(error));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
toaster.danger(t('Error'));
|
|
61
|
+
setShowTip(false);
|
|
62
|
+
setTipType('');
|
|
63
|
+
});
|
|
79
64
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
80
65
|
}, []);
|
|
81
66
|
const onDocumentReplaced = useCallback(() => {
|
|
@@ -4,7 +4,7 @@ import { SDocViewer } from '../basic-sdk';
|
|
|
4
4
|
import context from '../context';
|
|
5
5
|
import Loading from '../components/loading';
|
|
6
6
|
import Layout, { Header, Content } from '../layout';
|
|
7
|
-
import { generateDefaultDocContent } from '../utils';
|
|
7
|
+
import { generateDefaultDocContent, isMobile } from '../utils';
|
|
8
8
|
import ErrorBoundary from './error-boundary';
|
|
9
9
|
import '../assets/css/simple-viewer.css';
|
|
10
10
|
class SimpleViewer extends React.Component {
|
|
@@ -64,6 +64,26 @@ class SimpleViewer extends React.Component {
|
|
|
64
64
|
sharePermissionText,
|
|
65
65
|
downloadURL
|
|
66
66
|
} = context.getSettings();
|
|
67
|
+
if (isMobile) {
|
|
68
|
+
return /*#__PURE__*/React.createElement(ErrorBoundary, null, /*#__PURE__*/React.createElement(Layout, null, /*#__PURE__*/React.createElement(Header, null, /*#__PURE__*/React.createElement("div", {
|
|
69
|
+
className: "doc-info"
|
|
70
|
+
}, /*#__PURE__*/React.createElement("h2", {
|
|
71
|
+
className: "doc-name my-0"
|
|
72
|
+
}, docName), sharePermissionText && /*#__PURE__*/React.createElement("span", {
|
|
73
|
+
className: "sdoc-share-permission ml-2"
|
|
74
|
+
}, sharePermissionText)), /*#__PURE__*/React.createElement("div", {
|
|
75
|
+
className: "doc-ops"
|
|
76
|
+
}, downloadURL && /*#__PURE__*/React.createElement("a", {
|
|
77
|
+
href: downloadURL,
|
|
78
|
+
className: "op-item"
|
|
79
|
+
}, /*#__PURE__*/React.createElement("i", {
|
|
80
|
+
className: "sdocfont sdoc-download"
|
|
81
|
+
})))), /*#__PURE__*/React.createElement(Content, null, /*#__PURE__*/React.createElement(SDocViewer, {
|
|
82
|
+
document: document,
|
|
83
|
+
showToolbar: false,
|
|
84
|
+
showOutline: false
|
|
85
|
+
}))));
|
|
86
|
+
}
|
|
67
87
|
return /*#__PURE__*/React.createElement(ErrorBoundary, null, /*#__PURE__*/React.createElement(Layout, null, /*#__PURE__*/React.createElement(Header, null, /*#__PURE__*/React.createElement("div", {
|
|
68
88
|
className: "doc-info"
|
|
69
89
|
}, /*#__PURE__*/React.createElement("h2", {
|