@seafile/sdoc-editor 0.5.3 → 0.5.5
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/assets/css/simple-editor.css +15 -0
- package/dist/basic-sdk/assets/css/layout.css +15 -0
- package/dist/basic-sdk/comment/components/comment-editor.js +49 -33
- package/dist/basic-sdk/comment/components/comment-item-content.js +11 -3
- package/dist/basic-sdk/comment/components/comment-item-reply.js +13 -5
- package/dist/basic-sdk/comment/components/comment-item-wrapper.js +1 -1
- package/dist/basic-sdk/comment/components/comment-list.css +27 -19
- package/dist/basic-sdk/comment/components/comment-list.js +0 -1
- package/dist/basic-sdk/comment/components/global-comment/index.css +2 -6
- package/dist/basic-sdk/comment/utils/index.js +5 -5
- package/dist/basic-sdk/constants/index.js +5 -2
- package/dist/basic-sdk/editor/comment-article.js +175 -0
- package/dist/basic-sdk/editor/editable-article.js +2 -1
- package/dist/basic-sdk/editor/sdoc-comment-editor.js +108 -0
- package/dist/basic-sdk/extension/commons/insert-element-dialog/index.js +12 -7
- package/dist/basic-sdk/extension/commons/menu/menu-item.js +1 -1
- package/dist/basic-sdk/extension/constants/element-type.js +3 -1
- package/dist/basic-sdk/extension/constants/index.js +2 -2
- package/dist/basic-sdk/extension/constants/menus-config.js +2 -2
- package/dist/basic-sdk/extension/index.js +11 -1
- package/dist/basic-sdk/extension/plugins/image/helpers.js +6 -3
- package/dist/basic-sdk/extension/plugins/image/menu/index.js +25 -4
- package/dist/basic-sdk/extension/plugins/image/render-elem.js +1 -0
- package/dist/basic-sdk/extension/plugins/index.js +3 -1
- package/dist/basic-sdk/extension/plugins/link/menu/index.js +22 -3
- package/dist/basic-sdk/extension/plugins/markdown/plugin.js +17 -6
- package/dist/basic-sdk/extension/plugins/mention/helper.js +142 -0
- package/dist/basic-sdk/extension/plugins/mention/index.js +10 -0
- package/dist/basic-sdk/extension/plugins/mention/plugin.js +258 -0
- package/dist/basic-sdk/{comment/components/comment-input → extension/plugins/mention/render-elem}/comment-participant-item.js +1 -1
- package/dist/basic-sdk/{comment/components/comment-input → extension/plugins/mention/render-elem}/index.css +22 -1
- package/dist/basic-sdk/extension/plugins/mention/render-elem/index.js +51 -0
- package/dist/basic-sdk/extension/plugins/mention/render-elem/participant-popover.js +219 -0
- package/dist/basic-sdk/extension/plugins/paragraph/helper.js +10 -0
- package/dist/basic-sdk/extension/plugins/paragraph/render-elem.js +9 -3
- package/dist/basic-sdk/extension/plugins/text-style/menu/comemnt-editor-menu.js +68 -0
- package/dist/basic-sdk/extension/plugins/text-style/menu/index.js +19 -8
- package/dist/basic-sdk/extension/render/custom-element.js +12 -2
- package/dist/basic-sdk/extension/toolbar/comment-editor-toolbar/index.js +45 -0
- package/dist/basic-sdk/utils/event-handler.js +21 -0
- package/dist/slate-convert/md-to-slate/transform.js +17 -0
- package/dist/slate-convert/slate-to-md/transform.js +28 -2
- package/package.json +1 -1
- package/dist/basic-sdk/comment/components/comment-input/helpers.js +0 -15
- package/dist/basic-sdk/comment/components/comment-input/index.js +0 -306
|
@@ -7,3 +7,18 @@
|
|
|
7
7
|
.sdoc-context-menu .dropdown-item:hover {
|
|
8
8
|
color: #fff;
|
|
9
9
|
}
|
|
10
|
+
|
|
11
|
+
/* Used in mention editor, to modify `mention` node */
|
|
12
|
+
a[title^='__sdoc_mention__username'] {
|
|
13
|
+
display: inline-block;
|
|
14
|
+
padding: 0 2px;
|
|
15
|
+
border: none;
|
|
16
|
+
background-color: transparent;
|
|
17
|
+
color: #1677ff !important;
|
|
18
|
+
border-radius: 5px;
|
|
19
|
+
cursor: pointer;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
a[title^='__sdoc_mention__username']:hover {
|
|
23
|
+
background-color: rgb(221, 236, 253);
|
|
24
|
+
}
|
|
@@ -114,3 +114,18 @@
|
|
|
114
114
|
font-size: 12px;
|
|
115
115
|
transform: scale(.75);
|
|
116
116
|
}
|
|
117
|
+
|
|
118
|
+
.sdoc-comment-editor-toolbar {
|
|
119
|
+
display: flex;
|
|
120
|
+
flex: 1;
|
|
121
|
+
position: relative;
|
|
122
|
+
height: 44px;
|
|
123
|
+
align-items: center;
|
|
124
|
+
user-select: none;
|
|
125
|
+
position: relative;
|
|
126
|
+
z-index: 102;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.sdoc-comment-editor-menu-group {
|
|
130
|
+
border-right: none;
|
|
131
|
+
}
|
|
@@ -2,12 +2,18 @@ import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import { Button } from 'reactstrap';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
|
+
import { Editor, Transforms } from '@seafile/slate';
|
|
5
6
|
import { useScrollContext } from '../../hooks/use-scroll-context';
|
|
6
7
|
import context from '../../../context';
|
|
7
|
-
import EventBus from '../../utils/event-bus';
|
|
8
|
-
import { INTERNAL_EVENT } from '../../constants';
|
|
9
8
|
import { useParticipantsContext } from '../hooks/use-participants';
|
|
10
|
-
import
|
|
9
|
+
import SdocCommentEditor from '../../editor/sdoc-comment-editor';
|
|
10
|
+
import { createCommentEditor } from '../../extension';
|
|
11
|
+
import withNodeId from '../../node-id';
|
|
12
|
+
import { generateEmptyElement } from '../../extension/core';
|
|
13
|
+
import { PARAGRAPH } from '../../extension/constants';
|
|
14
|
+
import slateToMdString from '../../../slate-convert/slate-to-md';
|
|
15
|
+
import mdStringToSlate from '../../../slate-convert/md-to-slate';
|
|
16
|
+
import { COMMENT_EDITOR, COMMENT_EDITOR_EDIT_AREA_WIDTH } from '../../constants';
|
|
11
17
|
const getSubmitTip = (type, content) => {
|
|
12
18
|
if (content) return 'Save';
|
|
13
19
|
return type === 'comment' ? 'Comment' : 'Reply';
|
|
@@ -23,7 +29,6 @@ const CommentEditor = _ref => {
|
|
|
23
29
|
setIsEditing,
|
|
24
30
|
hiddenComment
|
|
25
31
|
} = _ref;
|
|
26
|
-
const commentInputRef = useRef();
|
|
27
32
|
const commentWrapperRef = useRef();
|
|
28
33
|
const {
|
|
29
34
|
t
|
|
@@ -32,6 +37,30 @@ const CommentEditor = _ref => {
|
|
|
32
37
|
const {
|
|
33
38
|
addParticipants
|
|
34
39
|
} = useParticipantsContext();
|
|
40
|
+
const submitTip = useMemo(() => getSubmitTip(type, content), [content, type]);
|
|
41
|
+
const userInfo = context.getUserInfo();
|
|
42
|
+
const document = useMemo(() => {
|
|
43
|
+
const cursor = {};
|
|
44
|
+
let children = null;
|
|
45
|
+
children = [generateEmptyElement(PARAGRAPH, {
|
|
46
|
+
placeholder
|
|
47
|
+
})];
|
|
48
|
+
return {
|
|
49
|
+
children,
|
|
50
|
+
cursor
|
|
51
|
+
};
|
|
52
|
+
}, [placeholder]);
|
|
53
|
+
const editor = useMemo(() => {
|
|
54
|
+
const defaultEditor = createCommentEditor();
|
|
55
|
+
const newEditor = withNodeId(defaultEditor);
|
|
56
|
+
const {
|
|
57
|
+
cursors
|
|
58
|
+
} = document;
|
|
59
|
+
newEditor.cursors = cursors || {};
|
|
60
|
+
newEditor.width = COMMENT_EDITOR_EDIT_AREA_WIDTH; // default width
|
|
61
|
+
newEditor.editorType = COMMENT_EDITOR;
|
|
62
|
+
return newEditor;
|
|
63
|
+
}, [document]);
|
|
35
64
|
|
|
36
65
|
// onMount: set scrollLeft
|
|
37
66
|
useEffect(() => {
|
|
@@ -45,42 +74,33 @@ const CommentEditor = _ref => {
|
|
|
45
74
|
scrollRef.current.scrollLeft = scrollRef.current.scrollLeft + width;
|
|
46
75
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
47
76
|
}, []);
|
|
48
|
-
|
|
49
|
-
// onMount: hidden comment
|
|
50
|
-
useEffect(() => {
|
|
51
|
-
const eventBus = EventBus.getInstance();
|
|
52
|
-
const unsubscribe = eventBus.subscribe(INTERNAL_EVENT.ARTICLE_CLICK, hiddenComment);
|
|
53
|
-
return () => {
|
|
54
|
-
unsubscribe();
|
|
55
|
-
};
|
|
56
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
57
|
-
}, []);
|
|
58
77
|
const updateValue = useCallback(value => {
|
|
59
78
|
if (!value || value.trim() === '') return;
|
|
60
|
-
if (!content)
|
|
61
|
-
insertContent(value);
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
79
|
+
if (!content) return insertContent(value);
|
|
64
80
|
updateContent(value);
|
|
65
81
|
}, [content, insertContent, updateContent]);
|
|
66
82
|
const onSubmit = useCallback(event => {
|
|
67
83
|
event && event.stopPropagation();
|
|
68
|
-
const
|
|
69
|
-
updateValue(
|
|
70
|
-
const userInfo = context.getUserInfo();
|
|
84
|
+
const mdString = slateToMdString(editor.children);
|
|
85
|
+
updateValue(mdString);
|
|
71
86
|
addParticipants(userInfo.username);
|
|
72
|
-
|
|
73
|
-
|
|
87
|
+
editor.children = [generateEmptyElement(PARAGRAPH, {
|
|
88
|
+
placeholder
|
|
89
|
+
})];
|
|
90
|
+
Transforms.select(editor, Editor.start(editor, []));
|
|
91
|
+
}, [editor, updateValue, addParticipants, userInfo.username, placeholder]);
|
|
74
92
|
const onCancel = useCallback(event => {
|
|
75
93
|
event.stopPropagation();
|
|
76
|
-
commentInputRef.current.setValue('');
|
|
77
94
|
setIsEditing && setIsEditing(false);
|
|
78
95
|
hiddenComment && hiddenComment(false);
|
|
79
96
|
|
|
80
97
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
81
98
|
}, [setIsEditing]);
|
|
82
|
-
|
|
83
|
-
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
const children = mdStringToSlate(content);
|
|
101
|
+
editor.children = children;
|
|
102
|
+
Transforms.select(editor, Editor.end(editor, []));
|
|
103
|
+
}, [editor, content]);
|
|
84
104
|
return /*#__PURE__*/React.createElement("div", {
|
|
85
105
|
className: classNames('comment-editor-wrapper', className),
|
|
86
106
|
ref: commentWrapperRef
|
|
@@ -95,13 +115,9 @@ const CommentEditor = _ref => {
|
|
|
95
115
|
width: "100%"
|
|
96
116
|
})), /*#__PURE__*/React.createElement("div", {
|
|
97
117
|
className: "comment-editor-user-name"
|
|
98
|
-
}, userInfo.name)), /*#__PURE__*/React.createElement(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
placeholder: placeholder,
|
|
102
|
-
content: content,
|
|
103
|
-
onCancel: onCancel,
|
|
104
|
-
onSubmit: onSubmit
|
|
118
|
+
}, userInfo.name)), /*#__PURE__*/React.createElement(SdocCommentEditor, {
|
|
119
|
+
editor: editor,
|
|
120
|
+
document: document
|
|
105
121
|
}), /*#__PURE__*/React.createElement("div", {
|
|
106
122
|
className: "comment-operations"
|
|
107
123
|
}, /*#__PURE__*/React.createElement(Button, {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
|
-
import React, { useCallback, useMemo, useState } from 'react';
|
|
2
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
3
3
|
import { withTranslation } from 'react-i18next';
|
|
4
4
|
import { Dropdown, DropdownItem, DropdownMenu, DropdownToggle } from 'reactstrap';
|
|
5
5
|
import dayjs from 'dayjs';
|
|
6
6
|
import CommentEditor from './comment-editor';
|
|
7
7
|
import Tooltip from '../../../components/tooltip';
|
|
8
|
-
import { textToHtml } from '../utils';
|
|
9
8
|
import { useNotificationContext } from '../hooks/notification-hooks';
|
|
9
|
+
import processor from '../../../slate-convert/md-to-html';
|
|
10
10
|
const CommentItem = _ref => {
|
|
11
11
|
let {
|
|
12
12
|
isActive,
|
|
@@ -23,11 +23,19 @@ const CommentItem = _ref => {
|
|
|
23
23
|
const {
|
|
24
24
|
notificationsInfo
|
|
25
25
|
} = useNotificationContext();
|
|
26
|
+
const [editorContent, setEditorContent] = useState('');
|
|
26
27
|
const onEditToggle = useCallback(event => {
|
|
27
28
|
event.stopPropagation();
|
|
28
29
|
setIsEditing(true);
|
|
29
30
|
}, []);
|
|
30
31
|
const isUnseen = notificationsInfo.notifications_map["sdoc_notification_".concat(comment.id)] ? true : false;
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
transferHtml(comment.comment);
|
|
34
|
+
}, [comment.comment]);
|
|
35
|
+
const transferHtml = async mdString => {
|
|
36
|
+
const htmlString = await processor.process(mdString);
|
|
37
|
+
setEditorContent(String(htmlString));
|
|
38
|
+
};
|
|
31
39
|
const onDeleteToggle = useCallback(event => {
|
|
32
40
|
event.stopPropagation();
|
|
33
41
|
onDeleteComment(true);
|
|
@@ -126,7 +134,7 @@ const CommentItem = _ref => {
|
|
|
126
134
|
className: "comment-content"
|
|
127
135
|
}, !isEditing && /*#__PURE__*/React.createElement("div", {
|
|
128
136
|
dangerouslySetInnerHTML: {
|
|
129
|
-
__html:
|
|
137
|
+
__html: editorContent
|
|
130
138
|
}
|
|
131
139
|
})), isEditing && /*#__PURE__*/React.createElement(CommentEditor, {
|
|
132
140
|
className: "pb-3",
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import React, { useCallback, useState, useRef } from 'react';
|
|
1
|
+
import React, { useCallback, useState, useRef, useEffect } from 'react';
|
|
2
2
|
import { withTranslation } from 'react-i18next';
|
|
3
3
|
import { Dropdown, DropdownItem, DropdownMenu, DropdownToggle } from 'reactstrap';
|
|
4
4
|
import dayjs from 'dayjs';
|
|
5
5
|
import context from '../../../context';
|
|
6
6
|
import CommentEditor from './comment-editor';
|
|
7
|
-
import { textToHtml } from '../utils';
|
|
8
7
|
import { useNotificationContext } from '../hooks/notification-hooks';
|
|
9
8
|
import CommentDeletePopover from './comment-delete-popover';
|
|
9
|
+
import processor from '../../../slate-convert/md-to-html';
|
|
10
10
|
const CommentItemReply = _ref => {
|
|
11
11
|
let {
|
|
12
12
|
isActive,
|
|
@@ -23,6 +23,7 @@ const CommentItemReply = _ref => {
|
|
|
23
23
|
const liRef = useRef(null);
|
|
24
24
|
const isUnseen = notificationsInfo.notifications_map["sdoc_notification_".concat(reply.comment_id, "_").concat(reply.id)] ? true : false;
|
|
25
25
|
const [isEditing, setIsEditing] = useState(false);
|
|
26
|
+
const [editorContent, setEditorContent] = useState('');
|
|
26
27
|
const replyOpToolsId = "replyOpTools_".concat(reply.id);
|
|
27
28
|
const onEditToggle = useCallback(event => {
|
|
28
29
|
event.stopPropagation();
|
|
@@ -33,6 +34,13 @@ const CommentItemReply = _ref => {
|
|
|
33
34
|
event.stopPropagation();
|
|
34
35
|
setIsShowDeleteDialog(true);
|
|
35
36
|
}, []);
|
|
37
|
+
const transferHtml = async mdString => {
|
|
38
|
+
const htmlString = await processor.process(mdString);
|
|
39
|
+
setEditorContent(String(htmlString));
|
|
40
|
+
};
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
transferHtml(reply.reply);
|
|
43
|
+
}, [reply.reply]);
|
|
36
44
|
const _deleteReply = useCallback(() => {
|
|
37
45
|
deleteReply(reply.id);
|
|
38
46
|
setIsShowDeleteDialog(false);
|
|
@@ -95,12 +103,12 @@ const CommentItemReply = _ref => {
|
|
|
95
103
|
className: "comment-content"
|
|
96
104
|
}, !isEditing && /*#__PURE__*/React.createElement("div", {
|
|
97
105
|
dangerouslySetInnerHTML: {
|
|
98
|
-
__html:
|
|
106
|
+
__html: editorContent
|
|
99
107
|
}
|
|
100
108
|
})), isEditing && /*#__PURE__*/React.createElement(CommentEditor, {
|
|
101
|
-
className:
|
|
109
|
+
className: "pb-3",
|
|
102
110
|
type: "reply",
|
|
103
|
-
content:
|
|
111
|
+
content: editorContent,
|
|
104
112
|
updateContent: updateContent,
|
|
105
113
|
setIsEditing: setIsEditing
|
|
106
114
|
}), isShowDeleteDialog && isActive && /*#__PURE__*/React.createElement(CommentDeletePopover, {
|
|
@@ -278,7 +278,7 @@ const CommentItemWrapper = _ref => {
|
|
|
278
278
|
reply: reply
|
|
279
279
|
});
|
|
280
280
|
})), isActive && /*#__PURE__*/React.createElement(CommentEditor, {
|
|
281
|
-
className: "
|
|
281
|
+
className: "p-3",
|
|
282
282
|
type: "reply",
|
|
283
283
|
placeholder: tip,
|
|
284
284
|
insertContent: insertContent,
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
.sdoc-comment-list-container .comment-ui-container {
|
|
6
|
+
min-width: 330px;
|
|
7
|
+
max-width: 400px;
|
|
6
8
|
background-color: #edf2fa;
|
|
7
9
|
border-radius: 8px;
|
|
8
10
|
box-shadow: 0 0 2px rgba(0, 0, 0, .04);
|
|
@@ -42,7 +44,6 @@
|
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
.sdoc-comment-list-container .comment-item-list {
|
|
45
|
-
max-height: 350px;
|
|
46
47
|
min-width: 280px;
|
|
47
48
|
overflow-x: hidden;
|
|
48
49
|
overflow-y: auto;
|
|
@@ -51,7 +52,7 @@
|
|
|
51
52
|
|
|
52
53
|
.sdoc-comment-list-container .comment-item {
|
|
53
54
|
position: relative;
|
|
54
|
-
padding: 16px
|
|
55
|
+
padding: 16px 10px 0;
|
|
55
56
|
cursor: pointer;
|
|
56
57
|
}
|
|
57
58
|
|
|
@@ -79,9 +80,9 @@
|
|
|
79
80
|
.sdoc-comment-list-container .comment-item .comment-content {
|
|
80
81
|
padding-bottom: 10px;
|
|
81
82
|
margin-top: 10px;
|
|
82
|
-
margin-left:
|
|
83
|
-
|
|
84
|
-
word-
|
|
83
|
+
margin-left: 41px;
|
|
84
|
+
word-break: keep-all;
|
|
85
|
+
word-wrap: break-word;
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
.sdoc-comment-list-container .comment-header .comment-author__avatar {
|
|
@@ -200,27 +201,34 @@
|
|
|
200
201
|
color: #fff;
|
|
201
202
|
}
|
|
202
203
|
|
|
204
|
+
.sdoc-comment-editor-wrapper {
|
|
205
|
+
border: 1px solid #ececec;
|
|
206
|
+
border-top-left-radius: 3px;
|
|
207
|
+
border-top-right-radius: 3px;
|
|
208
|
+
margin-bottom: 15px;
|
|
209
|
+
border-radius: 3px;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.comment-editor-wrapper .sdoc-comment-editor-wrapper .article.sdoc-comment-editor {
|
|
213
|
+
width: 365px;
|
|
214
|
+
padding: 0 5px;
|
|
215
|
+
min-height: 75px;
|
|
216
|
+
max-height: 80px;
|
|
217
|
+
box-shadow: none;
|
|
218
|
+
overflow-y: auto;
|
|
219
|
+
overflow-x: hidden;
|
|
220
|
+
border: none;
|
|
221
|
+
background-color: transparent;
|
|
222
|
+
}
|
|
223
|
+
|
|
203
224
|
.sdoc-comment-list-container .comment-editor-wrapper {
|
|
204
225
|
display: flex;
|
|
205
226
|
flex-direction: column;
|
|
206
227
|
justify-content: center;
|
|
207
|
-
padding: 0
|
|
228
|
+
padding: 0 10px;
|
|
208
229
|
cursor: text;
|
|
209
230
|
}
|
|
210
231
|
|
|
211
|
-
.sdoc-comment-list-container .comment-editor-wrapper .comment-editor {
|
|
212
|
-
margin-bottom: 10px;
|
|
213
|
-
min-height: 40px;
|
|
214
|
-
max-height: 120px;
|
|
215
|
-
min-width: 240px;
|
|
216
|
-
overflow: auto;
|
|
217
|
-
background: #fff;
|
|
218
|
-
border: 1px solid rgba(0, 0, 0, .12);
|
|
219
|
-
border-radius: 4px;
|
|
220
|
-
padding: 8px;
|
|
221
|
-
word-break: break-all;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
232
|
.sdoc-comment-list-container .comment-editor-wrapper .comment-editor:empty:before {
|
|
225
233
|
content: attr(placeholder);
|
|
226
234
|
opacity: .6;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
right: 10px;
|
|
4
4
|
top: 50px;
|
|
5
5
|
z-index: 103;
|
|
6
|
-
width:
|
|
6
|
+
width: 432px;
|
|
7
7
|
height: 540px;
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
flex: 1;
|
|
88
88
|
display: flex;
|
|
89
89
|
flex-direction: column;
|
|
90
|
-
padding:
|
|
90
|
+
padding: 10px;
|
|
91
91
|
overflow: auto;
|
|
92
92
|
}
|
|
93
93
|
|
|
@@ -95,10 +95,6 @@
|
|
|
95
95
|
position: relative;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
.global-comments-popover .comments-panel-body__content .comment-item-list {
|
|
99
|
-
max-width: 308px;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
98
|
.global-comments-popover .comments-panel-body__content .comment-ui-container.active {
|
|
103
99
|
left: 0;
|
|
104
100
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
2
2
|
import { Editor } from '@seafile/slate';
|
|
3
3
|
import { getEventTransfer } from '../../../utils';
|
|
4
|
-
import { COMMENT_URL_CLASSNAME } from '../constants';
|
|
5
4
|
import { KeyCodes } from '../../../constants';
|
|
6
5
|
import { createNotify, generatorNotificationKey } from './notification-utils';
|
|
7
6
|
import { focusEditor, findPath } from '../../extension/core';
|
|
@@ -33,10 +32,11 @@ export const searchCollaborators = (collaborators, searchValue) => {
|
|
|
33
32
|
|
|
34
33
|
// Mailto, file, tel, callto, sms, cid, xmpp, etc. are not support
|
|
35
34
|
const ALLOWED_URL_REG = /((http|https):\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|])/g;
|
|
36
|
-
export const textToHtml = text => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
};
|
|
35
|
+
// export const textToHtml = (text) => {
|
|
36
|
+
// if (!text) return '';
|
|
37
|
+
// return text.replace(ALLOWED_URL_REG, '<a href="$1" target="_blank" class=' + COMMENT_URL_CLASSNAME + '>$1</a>');
|
|
38
|
+
// };
|
|
39
|
+
|
|
40
40
|
export const convertComment = value => {
|
|
41
41
|
return value.replaceAll('<', '<').replaceAll('>', '>');
|
|
42
42
|
};
|
|
@@ -17,12 +17,15 @@ export const INTERNAL_EVENT = {
|
|
|
17
17
|
CLOSE_CALLOUT_COLOR_PICKER: 'close_callout_color_picker',
|
|
18
18
|
OPEN_SEARCH_REPLACE_MODAL: 'open_search_replace_modal',
|
|
19
19
|
UPDATE_SEARCH_REPLACE_HIGHLIGHT: 'update_search_replace_highlight',
|
|
20
|
-
TABLE_CELL_MOUSE_ENTER: 'table_cell_mouse_enter'
|
|
20
|
+
TABLE_CELL_MOUSE_ENTER: 'table_cell_mouse_enter',
|
|
21
|
+
HANDLE_MENTION_TEMP_CHOSEN: 'handle_mention_temp_chosen',
|
|
22
|
+
UPDATE_MENTION_TEMP_CONTENT: 'update_mention_temp_content'
|
|
21
23
|
};
|
|
22
24
|
export const REVISION_DIFF_KEY = 'diff';
|
|
23
25
|
export const REVISION_DIFF_VALUE = '1';
|
|
24
26
|
export const PAGE_EDIT_AREA_WIDTH = 672; // 672 = 794 - 2[borderLeft + borderRight] - 120[paddingLeft + paddingRight]
|
|
25
|
-
|
|
27
|
+
export const COMMENT_EDITOR_EDIT_AREA_WIDTH = 364;
|
|
28
|
+
export const COMMENT_EDITOR = 'comment_editor';
|
|
26
29
|
export const MODIFY_TYPE = {
|
|
27
30
|
ADD: 'add',
|
|
28
31
|
DELETE: 'delete',
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import React, { useCallback, useMemo } from 'react';
|
|
2
|
+
import { Editable, ReactEditor, Slate } from '@seafile/slate-react';
|
|
3
|
+
import { Editor, Node, Range } from '@seafile/slate';
|
|
4
|
+
import { renderLeaf, renderElement } from '../extension';
|
|
5
|
+
import { getAboveBlockNode, getNextNode, getPrevNode, isSelectionAtBlockEnd, isSelectionAtBlockStart } from '../extension/core';
|
|
6
|
+
import EventProxy from '../utils/event-handler';
|
|
7
|
+
import { useCursors } from '../cursor/use-cursors';
|
|
8
|
+
import { INTERNAL_EVENT } from '../constants';
|
|
9
|
+
import { usePipDecorate } from '../decorates';
|
|
10
|
+
import { getCursorPosition, getDomHeight, getDomMarginTop } from '../utils/dom-utils';
|
|
11
|
+
import EventBus from '../utils/event-bus';
|
|
12
|
+
import { useScrollContext } from '../hooks/use-scroll-context';
|
|
13
|
+
import { IMAGE } from '../extension/constants';
|
|
14
|
+
const CommentArticle = _ref => {
|
|
15
|
+
let {
|
|
16
|
+
editor,
|
|
17
|
+
slateValue,
|
|
18
|
+
updateSlateValue
|
|
19
|
+
} = _ref;
|
|
20
|
+
const {
|
|
21
|
+
cursors
|
|
22
|
+
} = useCursors(editor);
|
|
23
|
+
const decorate = usePipDecorate(editor);
|
|
24
|
+
// init eventHandler
|
|
25
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
26
|
+
const eventProxy = useMemo(() => new EventProxy(editor), []);
|
|
27
|
+
const onMouseDown = useCallback(event => {
|
|
28
|
+
if (event.button === 0) {
|
|
29
|
+
// Compatible with the editor which unload table plugin
|
|
30
|
+
editor.reSetTableSelectedRange && editor.reSetTableSelectedRange();
|
|
31
|
+
const eventBus = EventBus.getInstance();
|
|
32
|
+
eventBus.dispatch(INTERNAL_EVENT.CANCEL_TABLE_SELECT_RANGE);
|
|
33
|
+
}
|
|
34
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
35
|
+
}, []);
|
|
36
|
+
const scrollRef = useScrollContext();
|
|
37
|
+
const onKeyDown = useCallback(event => {
|
|
38
|
+
const {
|
|
39
|
+
scrollTop,
|
|
40
|
+
clientHeight
|
|
41
|
+
} = scrollRef.current;
|
|
42
|
+
eventProxy.onKeyDown(event);
|
|
43
|
+
if (event.key === 'ArrowLeft') {
|
|
44
|
+
if (!isSelectionAtBlockStart(editor)) return;
|
|
45
|
+
}
|
|
46
|
+
if (event.key === 'ArrowUp' || event.key === 'ArrowLeft') {
|
|
47
|
+
if (scrollTop === 0) return;
|
|
48
|
+
let prevNode = getPrevNode(editor);
|
|
49
|
+
if (!prevNode) return;
|
|
50
|
+
const domNode = ReactEditor.toDOMNode(editor, prevNode[0]);
|
|
51
|
+
const domHeight = getDomHeight(domNode);
|
|
52
|
+
const isScrollUp = true;
|
|
53
|
+
const {
|
|
54
|
+
y
|
|
55
|
+
} = getCursorPosition(isScrollUp);
|
|
56
|
+
if (y >= domHeight) return;
|
|
57
|
+
scrollRef.current.scroll(0, Math.max(0, scrollTop - domHeight));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (event.key === 'ArrowRight') {
|
|
61
|
+
if (!isSelectionAtBlockEnd(editor)) return;
|
|
62
|
+
}
|
|
63
|
+
if (event.key === 'ArrowDown' || event.key === 'ArrowRight') {
|
|
64
|
+
let nextNode = getNextNode(editor);
|
|
65
|
+
if (!nextNode) return;
|
|
66
|
+
const domNode = ReactEditor.toDOMNode(editor, nextNode[0]);
|
|
67
|
+
const domHeight = getDomHeight(domNode);
|
|
68
|
+
const isScrollUp = false;
|
|
69
|
+
const {
|
|
70
|
+
y
|
|
71
|
+
} = getCursorPosition(isScrollUp);
|
|
72
|
+
if (clientHeight - y >= domHeight) return;
|
|
73
|
+
scrollRef.current.scroll(0, Math.max(0, scrollTop + domHeight));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (event.key === 'Backspace') {
|
|
77
|
+
const {
|
|
78
|
+
y
|
|
79
|
+
} = getCursorPosition();
|
|
80
|
+
|
|
81
|
+
// above viewport
|
|
82
|
+
if (y < 0) {
|
|
83
|
+
const newY = Math.abs(y);
|
|
84
|
+
if (isSelectionAtBlockStart(editor)) {
|
|
85
|
+
const prevNode = getPrevNode(editor);
|
|
86
|
+
if (!prevNode) return;
|
|
87
|
+
const domNode = ReactEditor.toDOMNode(editor, prevNode[0]);
|
|
88
|
+
const domHeight = getDomHeight(domNode);
|
|
89
|
+
const node = getAboveBlockNode(editor);
|
|
90
|
+
if (!node) return;
|
|
91
|
+
const currentDomNode = ReactEditor.toDOMNode(editor, node[0]);
|
|
92
|
+
const marginTop = getDomMarginTop(currentDomNode);
|
|
93
|
+
scrollRef.current.scroll(0, Math.max(0, scrollTop - (newY + domHeight + marginTop)));
|
|
94
|
+
} else {
|
|
95
|
+
scrollRef.current.scroll(0, Math.max(0, scrollTop - newY));
|
|
96
|
+
}
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// insider viewport
|
|
101
|
+
if (y >= 0 && y <= clientHeight) {
|
|
102
|
+
if (isSelectionAtBlockStart(editor)) {
|
|
103
|
+
const prevNode = getPrevNode(editor);
|
|
104
|
+
if (!prevNode) return;
|
|
105
|
+
const domNode = ReactEditor.toDOMNode(editor, prevNode[0]);
|
|
106
|
+
const domHeight = getDomHeight(domNode);
|
|
107
|
+
if (y >= domHeight) return;
|
|
108
|
+
// Scroll up the height of the previous block
|
|
109
|
+
scrollRef.current.scroll(0, Math.max(0, scrollTop - domHeight));
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// below viewport
|
|
115
|
+
if (y > clientHeight) {
|
|
116
|
+
if (isSelectionAtBlockStart(editor)) {
|
|
117
|
+
// y: text top border
|
|
118
|
+
scrollRef.current.scroll(0, Math.max(0, scrollTop + (y - clientHeight)));
|
|
119
|
+
} else {
|
|
120
|
+
const marginBottom = 11.2;
|
|
121
|
+
const {
|
|
122
|
+
y: newY
|
|
123
|
+
} = getCursorPosition(false);
|
|
124
|
+
const rectBottom = newY + marginBottom; // text bottom border
|
|
125
|
+
scrollRef.current.scroll(0, Math.max(0, scrollTop + (rectBottom - clientHeight)));
|
|
126
|
+
}
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
132
|
+
}, [scrollRef]);
|
|
133
|
+
const handleScrollIntoView = useCallback((editor, domRange) => {
|
|
134
|
+
try {
|
|
135
|
+
const {
|
|
136
|
+
selection
|
|
137
|
+
} = editor;
|
|
138
|
+
if (Range.isCollapsed(selection)) {
|
|
139
|
+
// Do not scroll into view, when focus on image
|
|
140
|
+
const [imageNodeEntry] = Editor.nodes(editor, {
|
|
141
|
+
match: n => n.type === IMAGE,
|
|
142
|
+
at: selection
|
|
143
|
+
});
|
|
144
|
+
if (imageNodeEntry) return;
|
|
145
|
+
}
|
|
146
|
+
const focusedNode = Node.get(editor, selection.focus.path);
|
|
147
|
+
const domNode = ReactEditor.toDOMNode(editor, focusedNode);
|
|
148
|
+
if (!domNode) return;
|
|
149
|
+
domNode.scrollIntoView({
|
|
150
|
+
block: 'nearest'
|
|
151
|
+
});
|
|
152
|
+
} catch (error) {
|
|
153
|
+
//
|
|
154
|
+
}
|
|
155
|
+
}, []);
|
|
156
|
+
return /*#__PURE__*/React.createElement(Slate, {
|
|
157
|
+
editor: editor,
|
|
158
|
+
value: slateValue,
|
|
159
|
+
onChange: updateSlateValue
|
|
160
|
+
}, /*#__PURE__*/React.createElement(Editable, {
|
|
161
|
+
scrollSelectionIntoView: handleScrollIntoView,
|
|
162
|
+
cursors: cursors,
|
|
163
|
+
renderElement: renderElement,
|
|
164
|
+
renderLeaf: renderLeaf,
|
|
165
|
+
onKeyDown: onKeyDown,
|
|
166
|
+
onMouseDown: onMouseDown,
|
|
167
|
+
decorate: decorate,
|
|
168
|
+
onCut: eventProxy.onCut,
|
|
169
|
+
onCopy: eventProxy.onCopy,
|
|
170
|
+
onCompositionStart: eventProxy.onCompositionStart,
|
|
171
|
+
onCompositionUpdate: eventProxy.onCompositionUpdate,
|
|
172
|
+
onCompositionEnd: eventProxy.onCompositionEnd
|
|
173
|
+
}));
|
|
174
|
+
};
|
|
175
|
+
export default CommentArticle;
|
|
@@ -31,7 +31,8 @@ const EditableArticle = _ref => {
|
|
|
31
31
|
const eventProxy = useMemo(() => new EventProxy(editor), []);
|
|
32
32
|
const onMouseDown = useCallback(event => {
|
|
33
33
|
if (event.button === 0) {
|
|
34
|
-
editor
|
|
34
|
+
// Compatible with the editor which unload table plugin
|
|
35
|
+
editor.reSetTableSelectedRange && editor.reSetTableSelectedRange();
|
|
35
36
|
const eventBus = EventBus.getInstance();
|
|
36
37
|
eventBus.dispatch(INTERNAL_EVENT.CANCEL_TABLE_SELECT_RANGE);
|
|
37
38
|
}
|