@seafile/sdoc-editor 2.0.69 → 2.0.70
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/comment/comment-decorate.js +17 -17
- package/dist/basic-sdk/comment/components/comment-context-menu/index.css +16 -0
- package/dist/basic-sdk/comment/components/comment-context-menu/index.js +38 -0
- package/dist/basic-sdk/comment/components/comment-context-menu/menu-item.js +57 -0
- package/dist/basic-sdk/comment/components/comment-editor.js +5 -2
- package/dist/basic-sdk/comment/components/comment-item-collapse-wrapper.js +17 -1
- package/dist/basic-sdk/comment/components/comment-item-wrapper.js +85 -30
- package/dist/basic-sdk/comment/components/comment-list.css +34 -0
- package/dist/basic-sdk/comment/components/comment-list.js +96 -20
- package/dist/basic-sdk/comment/components/editor-comment.js +117 -57
- package/dist/basic-sdk/comment/components/elements-comment-count/index.js +15 -3
- package/dist/basic-sdk/comment/components/global-comment/index.css +25 -0
- package/dist/basic-sdk/comment/helper.js +111 -2
- package/dist/basic-sdk/comment/reducer/comment-reducer.js +2 -3
- package/dist/basic-sdk/constants/index.js +2 -1
- package/dist/basic-sdk/editor/sdoc-editor.js +4 -4
- package/dist/basic-sdk/extension/plugins/ai/ai-icon/index.js +2 -2
- package/dist/basic-sdk/extension/plugins/ai/ai-module/helpers.js +4 -0
- package/dist/basic-sdk/extension/plugins/text-style/menu/index.js +2 -1
- package/dist/basic-sdk/extension/plugins/text-style/render-elem.js +28 -4
- package/dist/basic-sdk/hooks/use-selection-position.js +51 -30
- package/dist/basic-sdk/node-id/helpers.js +26 -2
- package/dist/basic-sdk/node-id/index.js +37 -2
- package/package.json +1 -1
- package/public/locales/en/sdoc-editor.json +2 -1
- package/public/locales/zh_CN/sdoc-editor.json +2 -1
|
@@ -8,10 +8,12 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
8
8
|
exports.default = void 0;
|
|
9
9
|
var _react = _interopRequireWildcard(require("react"));
|
|
10
10
|
var _slate = require("@seafile/slate");
|
|
11
|
+
var _classnames = _interopRequireDefault(require("classnames"));
|
|
11
12
|
var _constants = require("../../constants");
|
|
12
|
-
var
|
|
13
|
+
var _helpers = require("../../extension/plugins/ai/ai-module/helpers");
|
|
13
14
|
var _useSelectionElement = require("../../hooks/use-selection-element");
|
|
14
15
|
var _useSelectionUpdate = _interopRequireDefault(require("../../hooks/use-selection-update"));
|
|
16
|
+
var _eventBus = _interopRequireDefault(require("../../utils/event-bus"));
|
|
15
17
|
var _helper = require("../helper");
|
|
16
18
|
var _useCommentContext = require("../hooks/comment-hooks/use-comment-context");
|
|
17
19
|
var _index = require("../utils/index");
|
|
@@ -28,39 +30,84 @@ const EditorComment = _ref => {
|
|
|
28
30
|
const currentSelectionElement = (0, _useSelectionElement.useSelectionElement)({
|
|
29
31
|
editor
|
|
30
32
|
}); // The slate node of the current cursor line
|
|
31
|
-
const [
|
|
33
|
+
const [activeElementIds, setActiveElementIds] = (0, _react.useState)([]); // The elements currently activated by clicking
|
|
32
34
|
const [isShowComments, setIsShowComments] = (0, _react.useState)(false);
|
|
33
35
|
const [commentDetail, setCommentDetail] = (0, _react.useState)({});
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (currentSelectionElement.type === _constants2.ELEMENT_TYPE.IMAGE_BLOCK) {
|
|
39
|
-
activeElement = currentSelectionElement.children.find(item => (item === null || item === void 0 ? void 0 : item.type) === _constants2.ELEMENT_TYPE.IMAGE);
|
|
40
|
-
}
|
|
41
|
-
setActiveElement(activeElement);
|
|
42
|
-
setIsShowComments(true);
|
|
36
|
+
const [isContextComment, setIsContextComment] = (0, _react.useState)(false);
|
|
37
|
+
const [isClickedContextComment, setIsClickedContextComment] = (0, _react.useState)(false);
|
|
38
|
+
const commentedDomRef = (0, _react.useRef)(null);
|
|
39
|
+
const hiddenComment = (0, _react.useCallback)(() => {
|
|
43
40
|
setCommentDetail({});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
setIsShowComments(false);
|
|
42
|
+
setIsContextComment(false);
|
|
43
|
+
(0, _helpers.removeMarks)(editor);
|
|
44
|
+
setIsClickedContextComment(false);
|
|
45
|
+
}, [editor]);
|
|
46
|
+
const onSelectElement = (0, _react.useCallback)(function (elementId) {
|
|
47
|
+
let isClickInContext = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
48
|
+
if (!isClickInContext) {
|
|
49
|
+
hiddenComment();
|
|
50
|
+
const activeElementIds = [elementId];
|
|
51
|
+
setActiveElementIds(activeElementIds);
|
|
52
|
+
const unresolvedComments = element_comments_map[elementId].filter(item => !item.resolved);
|
|
53
|
+
setCommentDetail({
|
|
54
|
+
...unresolvedComments
|
|
55
|
+
});
|
|
56
|
+
setIsClickedContextComment(false);
|
|
57
|
+
}
|
|
50
58
|
setIsShowComments(true);
|
|
51
|
-
|
|
59
|
+
if (isClickInContext) {
|
|
60
|
+
const clickedComments = [];
|
|
61
|
+
for (const comments of Object.values(editor.element_comments_map)) {
|
|
62
|
+
for (const comment of comments) {
|
|
63
|
+
if (elementId.includes(comment.detail.text_comment_id)) {
|
|
64
|
+
clickedComments.push(comment);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
setCommentDetail({
|
|
69
|
+
...clickedComments
|
|
70
|
+
});
|
|
71
|
+
setIsClickedContextComment(true);
|
|
72
|
+
}
|
|
73
|
+
}, [editor, element_comments_map, hiddenComment]);
|
|
74
|
+
(0, _react.useEffect)(() => {
|
|
75
|
+
const handleHoverContextComment = event => {
|
|
76
|
+
var _parentDom$className;
|
|
77
|
+
const parentDom = event.target.parentElement;
|
|
78
|
+
if (parentDom !== null && parentDom !== void 0 && (_parentDom$className = parentDom.className) !== null && _parentDom$className !== void 0 && _parentDom$className.includes('sdoc_comment_')) {
|
|
79
|
+
const isHover = event.type === 'mouseover';
|
|
80
|
+
const matchedAttributes = parentDom.className.split(' ').filter(cls => cls.startsWith('sdoc_comment_'));
|
|
81
|
+
matchedAttributes.forEach(className => {
|
|
82
|
+
const el = document.querySelectorAll(`.${className}`);
|
|
83
|
+
el.forEach(el => {
|
|
84
|
+
el.style.textDecoration = isHover ? 'underline #eb8205' : '';
|
|
85
|
+
el.style.textDecorationThickness = isHover ? '2px' : '';
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
document.addEventListener('mouseover', handleHoverContextComment);
|
|
91
|
+
document.addEventListener('mouseout', handleHoverContextComment);
|
|
92
|
+
return () => {
|
|
93
|
+
document.removeEventListener('mouseover', handleHoverContextComment);
|
|
94
|
+
document.removeEventListener('mouseout', handleHoverContextComment);
|
|
95
|
+
};
|
|
96
|
+
}, []);
|
|
52
97
|
const onSetCommentDetail = (0, _react.useCallback)(comment => {
|
|
53
98
|
setCommentDetail(comment);
|
|
54
99
|
}, []);
|
|
55
|
-
const hiddenComment = (0, _react.useCallback)(() => {
|
|
56
|
-
setCommentDetail({});
|
|
57
|
-
setIsShowComments(false);
|
|
58
|
-
}, []);
|
|
59
100
|
|
|
60
101
|
// Comments are updated to modify the current comment
|
|
61
102
|
(0, _react.useEffect)(() => {
|
|
62
|
-
if (
|
|
63
|
-
const unresolvedComments = element_comments_map[
|
|
103
|
+
if (isContextComment && activeElementIds) {
|
|
104
|
+
const unresolvedComments = element_comments_map[activeElementIds[0].element.id].filter(item => !item.resolved);
|
|
105
|
+
if (unresolvedComments.length === 0) {
|
|
106
|
+
setIsShowComments(false);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (activeElementIds && !Array.isArray(activeElementIds)) {
|
|
110
|
+
const unresolvedComments = element_comments_map[activeElementIds.id].filter(item => !item.resolved);
|
|
64
111
|
if (unresolvedComments.length === 0) {
|
|
65
112
|
setIsShowComments(false);
|
|
66
113
|
}
|
|
@@ -72,53 +119,66 @@ const EditorComment = _ref => {
|
|
|
72
119
|
if (isShowComments) {
|
|
73
120
|
hiddenComment();
|
|
74
121
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const cursor = (0, _helper.useCursorPosition)();
|
|
78
|
-
const style = (0, _react.useMemo)(() => {
|
|
79
|
-
var _Node$string;
|
|
80
|
-
if (currentSelectionElement && ((_Node$string = _slate.Node.string(currentSelectionElement)) === null || _Node$string === void 0 ? void 0 : _Node$string.length) === 0 && !currentSelectionElement.children.find(n => n.type === _constants2.ELEMENT_TYPE.IMAGE)) {
|
|
81
|
-
return {
|
|
82
|
-
top: '-99999px'
|
|
83
|
-
};
|
|
122
|
+
if (isContextComment) {
|
|
123
|
+
(0, _helpers.removeMarks)(editor);
|
|
84
124
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
125
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
126
|
+
}, [currentSelectionElement, editor.selection]);
|
|
127
|
+
(0, _react.useEffect)(() => {
|
|
128
|
+
const handleAddContextComment = () => {
|
|
129
|
+
// Add temporary marks for selection
|
|
130
|
+
_slate.Editor.addMark(editor, 'comment', true);
|
|
131
|
+
setTimeout(() => {
|
|
132
|
+
const activeElementIds = (0, _helper.getSelectedElemIds)(editor);
|
|
133
|
+
const lastSelectedDom = (0, _helper.getDomById)(activeElementIds[activeElementIds.length - 1]);
|
|
134
|
+
commentedDomRef.current = lastSelectedDom;
|
|
135
|
+
setActiveElementIds(activeElementIds);
|
|
136
|
+
setIsShowComments(true);
|
|
137
|
+
setCommentDetail({});
|
|
138
|
+
setIsContextComment(true);
|
|
139
|
+
}, 0);
|
|
90
140
|
};
|
|
91
|
-
|
|
92
|
-
|
|
141
|
+
const handleClickCommentedText = event => {
|
|
142
|
+
const parentDom = event.target.parentElement;
|
|
143
|
+
if (parentDom.className.split(/\s+/).some(cls => cls.startsWith('sdoc_comment'))) {
|
|
144
|
+
commentedDomRef.current = parentDom;
|
|
145
|
+
const matchedAttributes = parentDom.className.split(' ').filter(cls => cls.startsWith('sdoc_comment_'));
|
|
146
|
+
const clickedCommmentIdArray = matchedAttributes.map(item => item.replace('sdoc_comment_', ''));
|
|
147
|
+
onSelectElement(clickedCommmentIdArray, true);
|
|
148
|
+
}
|
|
93
149
|
};
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
150
|
+
const eventBus = _eventBus.default.getInstance();
|
|
151
|
+
const unsubscribeAddContextComment = eventBus.subscribe(_constants.INTERNAL_EVENT.ADD_CONTEXT_COMMENT, handleAddContextComment);
|
|
152
|
+
document.addEventListener('click', handleClickCommentedText);
|
|
153
|
+
return () => {
|
|
154
|
+
unsubscribeAddContextComment();
|
|
155
|
+
document.removeEventListener('click', handleClickCommentedText);
|
|
97
156
|
};
|
|
98
|
-
}, [
|
|
157
|
+
}, [editor, onSelectElement]);
|
|
99
158
|
return /*#__PURE__*/_react.default.createElement("div", {
|
|
100
159
|
className: "sdoc-comment-container"
|
|
101
160
|
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
102
161
|
className: "comment-container-main"
|
|
103
162
|
}), /*#__PURE__*/_react.default.createElement("div", {
|
|
104
|
-
className:
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}, /*#__PURE__*/_react.default.createElement("span", {
|
|
109
|
-
className: "add-comment-icon",
|
|
110
|
-
onClick: onAddCommentToggle
|
|
111
|
-
}, /*#__PURE__*/_react.default.createElement("i", {
|
|
112
|
-
className: "sdocfont sdoc-add-comment mr-1"
|
|
113
|
-
}))), /*#__PURE__*/_react.default.createElement(_elementsCommentCount.default, {
|
|
163
|
+
className: (0, _classnames.default)('comment-container-right', {
|
|
164
|
+
'isContextComment': isContextComment
|
|
165
|
+
})
|
|
166
|
+
}, /*#__PURE__*/_react.default.createElement(_elementsCommentCount.default, {
|
|
114
167
|
elementCommentsMap: element_comments_map,
|
|
115
|
-
|
|
168
|
+
activeElementIds: activeElementIds,
|
|
116
169
|
editor: editor,
|
|
117
170
|
onSelectElement: onSelectElement
|
|
118
171
|
}), isShowComments && /*#__PURE__*/_react.default.createElement(_commentList.default, {
|
|
119
|
-
|
|
172
|
+
activeElementIds: activeElementIds,
|
|
120
173
|
commentDetail: commentDetail,
|
|
121
|
-
onSetCommentDetail: onSetCommentDetail
|
|
174
|
+
onSetCommentDetail: onSetCommentDetail,
|
|
175
|
+
isContextComment: isContextComment,
|
|
176
|
+
isClickedContextComment: isClickedContextComment,
|
|
177
|
+
setIsClickedContextComment: setIsClickedContextComment,
|
|
178
|
+
onSelectElement: onSelectElement,
|
|
179
|
+
commentedDom: commentedDomRef.current,
|
|
180
|
+
closeComment: hiddenComment,
|
|
181
|
+
editor: editor
|
|
122
182
|
})));
|
|
123
183
|
};
|
|
124
184
|
var _default = exports.default = EditorComment;
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.default = void 0;
|
|
8
8
|
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
var _utils = require("../../utils");
|
|
9
10
|
var _elementCommentCount = _interopRequireDefault(require("./element-comment-count"));
|
|
10
11
|
require("./index.css");
|
|
11
12
|
const ElementsCommentCount = _ref => {
|
|
@@ -18,14 +19,25 @@ const ElementsCommentCount = _ref => {
|
|
|
18
19
|
if (!elementCommentsMap) return null;
|
|
19
20
|
return /*#__PURE__*/_react.default.createElement("div", {
|
|
20
21
|
className: "elements-comments-count"
|
|
21
|
-
}, Object.keys(elementCommentsMap).map(
|
|
22
|
-
|
|
22
|
+
}, Object.keys(elementCommentsMap).map(originElementId => {
|
|
23
|
+
var _comments$0$detail$el, _comments$0$detail;
|
|
24
|
+
const comments = elementCommentsMap[originElementId];
|
|
23
25
|
if (!Array.isArray(comments) || comments.length === 0) return null;
|
|
26
|
+
let elementId = originElementId;
|
|
27
|
+
const elementIdList = (_comments$0$detail$el = (_comments$0$detail = comments[0].detail) === null || _comments$0$detail === void 0 ? void 0 : _comments$0$detail.element_id_list) !== null && _comments$0$detail$el !== void 0 ? _comments$0$detail$el : [];
|
|
28
|
+
if (elementIdList.length > 1) {
|
|
29
|
+
const existedId = elementIdList.find(id => (0, _utils.getCommentElementById)(id, editor));
|
|
30
|
+
if (existedId) {
|
|
31
|
+
elementId = existedId;
|
|
32
|
+
} else {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
24
36
|
const unresolvedComment = comments.filter(item => !item.resolved);
|
|
25
37
|
const unresolvedCommentCount = unresolvedComment.length;
|
|
26
38
|
if (unresolvedCommentCount === 0) return null;
|
|
27
39
|
return /*#__PURE__*/_react.default.createElement(_elementCommentCount.default, {
|
|
28
|
-
key: elementId
|
|
40
|
+
key: `${originElementId}-${elementId}`,
|
|
29
41
|
elementId: elementId,
|
|
30
42
|
isElementSelected: selectionElement && selectionElement.id === elementId,
|
|
31
43
|
commentsCount: unresolvedCommentCount,
|
|
@@ -278,6 +278,31 @@
|
|
|
278
278
|
overflow: hidden;
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
+
.sdoc-comment-drawer .sdoc-comment-list-container .detail-context-comment {
|
|
282
|
+
align-items: start !important;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.sdoc-comment-drawer .sdoc-comment-list-container .detail-context-comment .sdoc-comment-quote {
|
|
286
|
+
padding-top: 1px;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.sdoc-comment-drawer .sdoc-comment-list-container .context-comment-item-selected-text-container {
|
|
290
|
+
padding: 16px 16px 0 16px;
|
|
291
|
+
color: #666;
|
|
292
|
+
display: flex;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.sdoc-comment-drawer .sdoc-comment-list-container .context-comment-item-selected-text-container .sdoc-comment-quote {
|
|
296
|
+
font-size: 12px;
|
|
297
|
+
padding-top: 1px;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.sdoc-comment-drawer .sdoc-comment-list-container .context-comment-item-selected-text-container .context-comment-items {
|
|
301
|
+
display: flex;
|
|
302
|
+
flex-direction: column;
|
|
303
|
+
font-size: 14px;
|
|
304
|
+
}
|
|
305
|
+
|
|
281
306
|
.comments-panel-body__header .sdoc-comment-filter-dropdown.sdoc-dropdown-menu {
|
|
282
307
|
border: 1px solid #dee3eb;
|
|
283
308
|
}
|
|
@@ -4,9 +4,11 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
-
exports.useCursorPosition = exports.getSelectionRange = exports.getElementCommentCountTop = exports.getCursorPosition = exports.getAvatarUrl = void 0;
|
|
7
|
+
exports.useCursorPosition = exports.updateElementsAttrs = exports.updateCommentedElementsAttrs = exports.getSelectionRange = exports.getSelectedElemIds = exports.getPrimaryElementId = exports.getElementCommentCountTop = exports.getDomById = exports.getCursorPosition = exports.getCommentedTextsByElementId = exports.getAvatarUrl = void 0;
|
|
8
|
+
var _slate = require("@seafile/slate");
|
|
8
9
|
var _slateReact = require("@seafile/slate-react");
|
|
9
10
|
var _context = _interopRequireDefault(require("../../context"));
|
|
11
|
+
var _core = require("../extension/core");
|
|
10
12
|
var _useScrollContext = require("../hooks/use-scroll-context");
|
|
11
13
|
const getSelectionRange = () => {
|
|
12
14
|
if (window.getSelection) {
|
|
@@ -72,4 +74,111 @@ const getElementCommentCountTop = (editor, element, scrollTop) => {
|
|
|
72
74
|
});
|
|
73
75
|
return minY - 93 + scrollTop; // 100: header height(56) + toolbar height(37)
|
|
74
76
|
};
|
|
75
|
-
exports.getElementCommentCountTop = getElementCommentCountTop;
|
|
77
|
+
exports.getElementCommentCountTop = getElementCommentCountTop;
|
|
78
|
+
const getSelectedElemIds = editor => {
|
|
79
|
+
const {
|
|
80
|
+
selection
|
|
81
|
+
} = editor;
|
|
82
|
+
if (!selection) return;
|
|
83
|
+
const selectedElemId = [];
|
|
84
|
+
const nodeEntries = Array.from(_slate.Editor.nodes(editor, {
|
|
85
|
+
match: n => _slate.Element.isElement(n) && _slate.Editor.isBlock(editor, n),
|
|
86
|
+
mode: 'lowest'
|
|
87
|
+
}));
|
|
88
|
+
for (const [node] of nodeEntries) {
|
|
89
|
+
selectedElemId.push(node.id);
|
|
90
|
+
}
|
|
91
|
+
return selectedElemId;
|
|
92
|
+
};
|
|
93
|
+
exports.getSelectedElemIds = getSelectedElemIds;
|
|
94
|
+
const getCommentedTextsByElementId = (elementId, textCommentId) => {
|
|
95
|
+
const container = document.querySelector(`[data-id='${elementId}']`);
|
|
96
|
+
if (!container) return [];
|
|
97
|
+
let targetDoms = container.querySelectorAll(`.sdoc_comment_${textCommentId}`);
|
|
98
|
+
if (targetDoms.length === 0) {
|
|
99
|
+
targetDoms = container.querySelectorAll(`.removed_sdoc_comment_${textCommentId}`);
|
|
100
|
+
}
|
|
101
|
+
const texts = [];
|
|
102
|
+
targetDoms.forEach(dom => {
|
|
103
|
+
var _dom$textContent;
|
|
104
|
+
texts.push(((_dom$textContent = dom.textContent) === null || _dom$textContent === void 0 ? void 0 : _dom$textContent.trim()) || '');
|
|
105
|
+
});
|
|
106
|
+
return texts;
|
|
107
|
+
};
|
|
108
|
+
exports.getCommentedTextsByElementId = getCommentedTextsByElementId;
|
|
109
|
+
const getDomById = elementId => {
|
|
110
|
+
const container = document.querySelector(`[data-id='${elementId}']`);
|
|
111
|
+
if (!container) return [];
|
|
112
|
+
const lastCommentedDomWithMarks = container.querySelector('.comment');
|
|
113
|
+
return lastCommentedDomWithMarks;
|
|
114
|
+
};
|
|
115
|
+
exports.getDomById = getDomById;
|
|
116
|
+
const updateElementsAttrs = (activeElementIds, editor, text_comment_id) => {
|
|
117
|
+
if (Array.isArray(activeElementIds)) {
|
|
118
|
+
for (const elemId of activeElementIds) {
|
|
119
|
+
const dom = document.querySelectorAll(`[data-id="${elemId}"]`)[0];
|
|
120
|
+
if (!dom) continue;
|
|
121
|
+
const domNode = _slateReact.ReactEditor.toSlateNode(editor, dom);
|
|
122
|
+
const nodePath = (0, _core.findPath)(editor, domNode);
|
|
123
|
+
domNode.children.forEach((textNode, index) => {
|
|
124
|
+
if (textNode.comment) {
|
|
125
|
+
const textNodePath = [...nodePath, index];
|
|
126
|
+
_slate.Transforms.setNodes(editor, {
|
|
127
|
+
[`sdoc_comment_${text_comment_id}`]: true
|
|
128
|
+
}, {
|
|
129
|
+
at: textNodePath,
|
|
130
|
+
match: _slate.Text.isText,
|
|
131
|
+
split: true
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
exports.updateElementsAttrs = updateElementsAttrs;
|
|
139
|
+
const updateCommentedElementsAttrs = function (activeElementIds, editor, text_comment_id) {
|
|
140
|
+
let resolved = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
141
|
+
let isDeleteComment = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
|
|
142
|
+
if (Array.isArray(activeElementIds)) {
|
|
143
|
+
_slate.Editor.withoutNormalizing(editor, () => {
|
|
144
|
+
for (const elemId of activeElementIds) {
|
|
145
|
+
// const { element } = elem;
|
|
146
|
+
const dom = document.querySelector(`[data-id="${elemId}"]`);
|
|
147
|
+
if (!dom) continue;
|
|
148
|
+
const domNode = _slateReact.ReactEditor.toSlateNode(editor, dom);
|
|
149
|
+
const domNodePath = (0, _core.findPath)(editor, domNode);
|
|
150
|
+
domNode.children.forEach((child, index) => {
|
|
151
|
+
const childPath = [...domNodePath, index];
|
|
152
|
+
if (_slate.Text.isText(child) && `sdoc_comment_${text_comment_id}` in child) {
|
|
153
|
+
_slate.Transforms.unsetNodes(editor, [`sdoc_comment_${text_comment_id}`], {
|
|
154
|
+
at: childPath,
|
|
155
|
+
match: _slate.Text.isText
|
|
156
|
+
});
|
|
157
|
+
!isDeleteComment && _slate.Transforms.setNodes(editor, {
|
|
158
|
+
[`sdoc_comment_${text_comment_id}`]: resolved
|
|
159
|
+
}, {
|
|
160
|
+
at: childPath,
|
|
161
|
+
match: _slate.Text.isText
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
exports.updateCommentedElementsAttrs = updateCommentedElementsAttrs;
|
|
170
|
+
const getPrimaryElementId = detail => {
|
|
171
|
+
if (!detail) return null;
|
|
172
|
+
let elementId;
|
|
173
|
+
const {
|
|
174
|
+
element_id,
|
|
175
|
+
element_id_list
|
|
176
|
+
} = detail;
|
|
177
|
+
if (element_id_list.length > 0) {
|
|
178
|
+
elementId = element_id_list[0];
|
|
179
|
+
} else {
|
|
180
|
+
elementId = element_id;
|
|
181
|
+
}
|
|
182
|
+
return elementId;
|
|
183
|
+
};
|
|
184
|
+
exports.getPrimaryElementId = getPrimaryElementId;
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.sortCommentList = exports.initElementCommentsMap = exports.initCommentsInfo = exports.initCommentList = exports.formatCommentsData = exports.commentReducer = void 0;
|
|
8
8
|
var _deepCopy = _interopRequireDefault(require("deep-copy"));
|
|
9
|
+
var _helper = require("../helper");
|
|
9
10
|
const formatCommentsData = comments => {
|
|
10
11
|
const formatComments = [];
|
|
11
12
|
const dupComments = (0, _deepCopy.default)(comments);
|
|
@@ -29,9 +30,7 @@ const initElementCommentsMap = comments => {
|
|
|
29
30
|
const formatComments = formatCommentsData(comments);
|
|
30
31
|
for (let i = 0; i < formatComments.length; i++) {
|
|
31
32
|
const item = formatComments[i];
|
|
32
|
-
const
|
|
33
|
-
element_id
|
|
34
|
-
} = item.detail;
|
|
33
|
+
const element_id = (0, _helper.getPrimaryElementId)(item.detail);
|
|
35
34
|
if (!elementCommentsMap[element_id]) {
|
|
36
35
|
elementCommentsMap[element_id] = [];
|
|
37
36
|
}
|
|
@@ -49,7 +49,8 @@ const INTERNAL_EVENT = exports.INTERNAL_EVENT = {
|
|
|
49
49
|
RESIZE_ARTICLE: 'resize_article',
|
|
50
50
|
ON_VIDEO_FILES_UPLOADED: 'on_video_files_uploaded',
|
|
51
51
|
RELOAD_COMMENT: 'reload_comment',
|
|
52
|
-
ASK_AI: 'ask_ai'
|
|
52
|
+
ASK_AI: 'ask_ai',
|
|
53
|
+
ADD_CONTEXT_COMMENT: 'add_context_comment'
|
|
53
54
|
};
|
|
54
55
|
const REVISION_DIFF_KEY = exports.REVISION_DIFF_KEY = 'diff';
|
|
55
56
|
const REVISION_DIFF_VALUE = exports.REVISION_DIFF_VALUE = '1';
|
|
@@ -122,12 +122,12 @@ const SdocEditor = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
|
|
|
122
122
|
const eventBus = _basicSdk.EventBus.getInstance();
|
|
123
123
|
eventBus.subscribe(_constants.EXTERNAL_EVENT.REFRESH_DOCUMENT, onRefreshDocument);
|
|
124
124
|
|
|
125
|
-
// Remove
|
|
126
|
-
const
|
|
125
|
+
// Remove Marks on special conditions like unexpected exit or refresh page using AI or context comment
|
|
126
|
+
const hasSpecialMark = !_slate.Editor.nodes(validEditor, {
|
|
127
127
|
at: [],
|
|
128
|
-
match: n => _slate.Text.isText(n) && n.sdoc_ai === true
|
|
128
|
+
match: n => _slate.Text.isText(n) && (n.sdoc_ai === true || n.comment === true)
|
|
129
129
|
}).next().done;
|
|
130
|
-
if (
|
|
130
|
+
if (hasSpecialMark) {
|
|
131
131
|
(0, _helpers.removeMarks)(validEditor);
|
|
132
132
|
}
|
|
133
133
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -17,9 +17,9 @@ function AIIcon(_ref) {
|
|
|
17
17
|
const {
|
|
18
18
|
t
|
|
19
19
|
} = (0, _reactI18next.useTranslation)('sdoc-editor');
|
|
20
|
-
const
|
|
20
|
+
const classnames = (0, _classnames.default)('sdoc-ask-ai-icon', className);
|
|
21
21
|
return /*#__PURE__*/_react.default.createElement("img", {
|
|
22
|
-
className:
|
|
22
|
+
className: classnames,
|
|
23
23
|
src: _sdocAskAi.default,
|
|
24
24
|
alt: t('Ask_AI')
|
|
25
25
|
});
|
|
@@ -13,6 +13,10 @@ const removeMarks = editor => {
|
|
|
13
13
|
at: [],
|
|
14
14
|
match: n => _slate.Text.isText(n) && n.sdoc_ai === true
|
|
15
15
|
});
|
|
16
|
+
_slate.Transforms.unsetNodes(editor, 'comment', {
|
|
17
|
+
at: [],
|
|
18
|
+
match: n => _slate.Text.isText(n) && n.comment === true
|
|
19
|
+
});
|
|
16
20
|
if (selection) {
|
|
17
21
|
_slate.Transforms.select(editor, selection);
|
|
18
22
|
} else {
|
|
@@ -11,6 +11,7 @@ var _reactI18next = require("react-i18next");
|
|
|
11
11
|
var _slate = require("@seafile/slate");
|
|
12
12
|
var _constants = require("../../../../../basic-sdk/constants");
|
|
13
13
|
var _context = _interopRequireDefault(require("../../../../../context"));
|
|
14
|
+
var _commentContextMenu = _interopRequireDefault(require("../../../../comment/components/comment-context-menu"));
|
|
14
15
|
var _useColorContext = require("../../../../hooks/use-color-context");
|
|
15
16
|
var _eventBus = _interopRequireDefault(require("../../../../utils/event-bus"));
|
|
16
17
|
var _mouseEvent = require("../../../../utils/mouse-event");
|
|
@@ -155,7 +156,7 @@ const TextStyleMenuList = _ref => {
|
|
|
155
156
|
tipMessage: t('Reduce_font_size')
|
|
156
157
|
}, /*#__PURE__*/_react.default.createElement("i", {
|
|
157
158
|
className: "sdocfont sdoc-reduce-font-size"
|
|
158
|
-
}))), idPrefix && enableSeafileAI && /*#__PURE__*/_react.default.createElement(_aiMenu.AIContextMenu, {
|
|
159
|
+
}))), idPrefix && /*#__PURE__*/_react.default.createElement(_commentContextMenu.default, null), idPrefix && enableSeafileAI && /*#__PURE__*/_react.default.createElement(_aiMenu.AIContextMenu, {
|
|
159
160
|
isRichEditor: isRichEditor
|
|
160
161
|
}));
|
|
161
162
|
};
|
|
@@ -15,7 +15,7 @@ const renderText = props => {
|
|
|
15
15
|
children,
|
|
16
16
|
leaf
|
|
17
17
|
} = props;
|
|
18
|
-
|
|
18
|
+
let {
|
|
19
19
|
text,
|
|
20
20
|
...rest
|
|
21
21
|
} = leaf;
|
|
@@ -35,10 +35,34 @@ const renderText = props => {
|
|
|
35
35
|
style['minWidth'] = '2px';
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
// Add temporary marks for selection in AI
|
|
39
|
-
if (leaf.sdoc_ai && leaf.text.trim()) {
|
|
38
|
+
// Add temporary marks for selection in AI or context comment
|
|
39
|
+
if ((leaf.sdoc_ai || leaf.comment) && leaf.text.trim()) {
|
|
40
40
|
style['padding'] = '3.23px 0';
|
|
41
|
-
style['
|
|
41
|
+
style['backgroundColor'] = '#a9c9ed';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Background color overlap for multi comments
|
|
45
|
+
if (Object.keys(leaf).some(key => key.startsWith('sdoc_comment_'))) {
|
|
46
|
+
const commentEntries = Object.entries(leaf).filter(_ref => {
|
|
47
|
+
let [key] = _ref;
|
|
48
|
+
return key.startsWith('sdoc_comment_');
|
|
49
|
+
});
|
|
50
|
+
for (const [key, value] of commentEntries) {
|
|
51
|
+
if (value === false && key.startsWith('sdoc_comment_')) {
|
|
52
|
+
const newKey = `removed_${key}`;
|
|
53
|
+
rest[newKey] = true;
|
|
54
|
+
delete rest[key];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const commentRest = Object.keys(rest).filter(item => item.startsWith('sdoc_comment_'));
|
|
58
|
+
|
|
59
|
+
// Multi comment or only one comment
|
|
60
|
+
if (commentRest.length > 1) {
|
|
61
|
+
style['backgroundColor'] = 'rgba(129, 237, 247)';
|
|
62
|
+
}
|
|
63
|
+
if (commentRest.length === 1) {
|
|
64
|
+
style['backgroundColor'] = 'rgba(129, 237, 247, 0.5)';
|
|
65
|
+
}
|
|
42
66
|
}
|
|
43
67
|
if (leaf.computed_background_color) {
|
|
44
68
|
style['backgroundColor'] = leaf.computed_background_color;
|
|
@@ -3,45 +3,66 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
7
|
-
var _slateReact = require("@seafile/slate-react");
|
|
6
|
+
exports.useCommentListPosition = void 0;
|
|
8
7
|
var _useScrollContext = require("./use-scroll-context");
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
if (!editor.selection) return {
|
|
12
|
-
x: 0,
|
|
13
|
-
y: 0
|
|
14
|
-
};
|
|
15
|
-
if (!node) return {
|
|
16
|
-
x: 0,
|
|
17
|
-
y: 0
|
|
18
|
-
};
|
|
19
|
-
try {
|
|
20
|
-
const domNode = _slateReact.ReactEditor.toDOMNode(editor, node);
|
|
21
|
-
const rect = domNode.getBoundingClientRect();
|
|
22
|
-
return rect;
|
|
23
|
-
} catch (error) {
|
|
24
|
-
// A new node has not yet been indexed, it cannot be retrieved, and the new node has no comment information, just do not display it
|
|
25
|
-
return {
|
|
26
|
-
x: 0,
|
|
27
|
-
y: 0
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
exports.useSelectionPosition = useSelectionPosition;
|
|
32
|
-
const useCommentListPosition = selectionElement => {
|
|
33
|
-
const selectionPosition = useSelectionPosition(selectionElement);
|
|
8
|
+
const useCommentListPosition = (selectedElementIds, isContextComment, isClickedContextComment, commentedDom, commentDetail, closeComment) => {
|
|
9
|
+
var _document$querySelect;
|
|
34
10
|
const headerHeight = 100;
|
|
35
11
|
const scrollRef = (0, _useScrollContext.useScrollContext)();
|
|
36
12
|
const {
|
|
37
13
|
scrollTop = 0
|
|
38
14
|
} = scrollRef.current || {};
|
|
39
|
-
if (
|
|
15
|
+
if (isContextComment || isClickedContextComment) {
|
|
16
|
+
let rect;
|
|
17
|
+
if (isContextComment) {
|
|
18
|
+
rect = commentedDom.getBoundingClientRect();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// rect is the last commented context dom
|
|
22
|
+
if (isClickedContextComment) {
|
|
23
|
+
const lastComment = Object.values(commentDetail).map(item => {
|
|
24
|
+
var _item$detail;
|
|
25
|
+
return (_item$detail = item.detail) === null || _item$detail === void 0 ? void 0 : _item$detail.text_comment_id;
|
|
26
|
+
}).flatMap(id => {
|
|
27
|
+
const elements = Array.from(document.querySelectorAll(`.sdoc_comment_${id}`));
|
|
28
|
+
return elements.map(el => ({
|
|
29
|
+
id,
|
|
30
|
+
el
|
|
31
|
+
}));
|
|
32
|
+
}).reduce((last, current) => {
|
|
33
|
+
if (!last) return current;
|
|
34
|
+
const position = last.el.compareDocumentPosition(current.el);
|
|
35
|
+
return position & Node.DOCUMENT_POSITION_FOLLOWING ? current : last;
|
|
36
|
+
}, null);
|
|
37
|
+
if (lastComment) {
|
|
38
|
+
const result = `.sdoc_comment_${lastComment.id}`;
|
|
39
|
+
const elements = Array.from(document.querySelectorAll(result));
|
|
40
|
+
if (elements.length === 0) return;
|
|
41
|
+
const lastTextElement = elements[elements.length - 1];
|
|
42
|
+
const parentElement = lastTextElement.closest('[data-slate-node="element"]');
|
|
43
|
+
const firstInSameParent = elements.find(el => parentElement.contains(el));
|
|
44
|
+
rect = firstInSameParent === null || firstInSameParent === void 0 ? void 0 : firstInSameParent.getBoundingClientRect();
|
|
45
|
+
} else {
|
|
46
|
+
closeComment();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const editorArticleRight = document.getElementById('sdoc-editor-print-wrapper').getBoundingClientRect().right;
|
|
50
|
+
const topPara = rect.bottom - headerHeight + 10 + scrollTop;
|
|
51
|
+
const rightPara = editorArticleRight - rect.left - 300; // 300 is comment container's width
|
|
52
|
+
return {
|
|
53
|
+
right: rightPara,
|
|
54
|
+
y: topPara
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const selectionPosition = (_document$querySelect = document.querySelectorAll(`[data-id="${selectedElementIds[0]}"]`)[0]) === null || _document$querySelect === void 0 ? void 0 : _document$querySelect.getBoundingClientRect();
|
|
58
|
+
// Boundary check
|
|
59
|
+
if (!selectionPosition) closeComment();
|
|
60
|
+
if (selectionPosition && selectionPosition.y !== 0) {
|
|
40
61
|
selectionPosition.y = selectionPosition.y - headerHeight + scrollTop;
|
|
41
62
|
}
|
|
42
63
|
return {
|
|
43
|
-
x: selectionPosition.x,
|
|
44
|
-
y: selectionPosition.y
|
|
64
|
+
x: selectionPosition === null || selectionPosition === void 0 ? void 0 : selectionPosition.x,
|
|
65
|
+
y: selectionPosition === null || selectionPosition === void 0 ? void 0 : selectionPosition.y
|
|
45
66
|
};
|
|
46
67
|
};
|
|
47
68
|
exports.useCommentListPosition = useCommentListPosition;
|