@seafile/sdoc-editor 0.4.34 → 0.4.36
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/api/seafile-api.js +4 -0
- package/dist/basic-sdk/comment/components/global-comment/index.js +1 -2
- package/dist/basic-sdk/comment/helper.js +2 -2
- package/dist/basic-sdk/comment/utils/index.js +3 -1
- package/dist/basic-sdk/editor/editable-article.js +1 -1
- package/dist/basic-sdk/editor/sdoc-editor.js +1 -2
- package/dist/basic-sdk/extension/commons/history-files/index.css +5 -0
- package/dist/basic-sdk/extension/commons/history-files/index.js +84 -29
- package/dist/basic-sdk/extension/commons/select-file-dialog/local-files/index.css +2 -0
- package/dist/basic-sdk/extension/constants/font.js +1 -0
- package/dist/basic-sdk/extension/constants/index.js +1 -0
- package/dist/basic-sdk/extension/plugins/callout/render-elem/index.js +2 -0
- package/dist/basic-sdk/extension/plugins/code-block/helpers.js +6 -3
- package/dist/basic-sdk/extension/plugins/code-block/render-elem.js +2 -0
- package/dist/basic-sdk/extension/plugins/file-link/helpers.js +1 -0
- package/dist/basic-sdk/extension/plugins/html/helper.js +1 -0
- package/dist/basic-sdk/extension/plugins/image/hover-menu/index.js +3 -3
- package/dist/basic-sdk/extension/plugins/link/helpers.js +1 -0
- package/dist/basic-sdk/extension/plugins/sdoc-link/helpers.js +1 -1
- package/dist/basic-sdk/extension/plugins/table/helpers.js +22 -0
- package/dist/basic-sdk/extension/plugins/table/render/index.js +5 -3
- package/dist/basic-sdk/extension/plugins/table/render/render-cell.js +6 -7
- package/dist/basic-sdk/extension/plugins/table/render/resize-handlers/column-resize-handler.js +1 -1
- package/dist/basic-sdk/extension/plugins/table/render/resize-handlers/row-resize-handler.js +2 -3
- package/dist/basic-sdk/extension/plugins/table/render/table-header/rows-header/row-header.js +1 -1
- package/dist/basic-sdk/extension/toolbar/side-toolbar/helpers.js +1 -0
- package/dist/basic-sdk/extension/toolbar/side-toolbar/transform-menus.js +11 -4
- package/dist/basic-sdk/utils/dom-utils.js +2 -2
- package/dist/constants/index.js +2 -1
- package/dist/context.js +4 -0
- package/dist/layout/layout.js +27 -0
- package/dist/utils/get-event-transfer.js +3 -1
- package/dist/utils/index.js +13 -6
- package/package.json +1 -1
package/dist/api/seafile-api.js
CHANGED
|
@@ -117,6 +117,10 @@ class SeafileAPI {
|
|
|
117
117
|
const url = 'api/v2.1/seadoc/query-copy-move-progress/' + docUuid + '/?&doc_uuid=' + docUuid + '&task_id=' + taskId;
|
|
118
118
|
return this.req.get(url);
|
|
119
119
|
}
|
|
120
|
+
searchSdocFiles(docUuid, query, page, per_page) {
|
|
121
|
+
const url = 'api/v2.1/seadoc/search-filename/' + docUuid + '/?query=' + query + '&page=' + page + '&per_page=' + per_page;
|
|
122
|
+
return this.req.get(url);
|
|
123
|
+
}
|
|
120
124
|
|
|
121
125
|
// participants
|
|
122
126
|
listParticipants(docUuid) {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
2
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
3
|
import dayjs from 'dayjs';
|
|
4
|
-
import { useSlateStatic } from '@seafile/slate-react';
|
|
5
|
-
import { ReactEditor } from '@seafile/slate-react';
|
|
4
|
+
import { useSlateStatic, ReactEditor } from '@seafile/slate-react';
|
|
6
5
|
import { ElementPopover } from '../../../extension/commons';
|
|
7
6
|
import EventBus from '../../../utils/event-bus';
|
|
8
7
|
import useCommentList from '../../hooks/comment-hooks/use-comment-list';
|
|
@@ -13,8 +13,8 @@ export const getSelectionRange = () => {
|
|
|
13
13
|
return null;
|
|
14
14
|
};
|
|
15
15
|
export const getCursorPosition = () => {
|
|
16
|
-
let x = 0
|
|
17
|
-
|
|
16
|
+
let x = 0;
|
|
17
|
+
let y = 0;
|
|
18
18
|
let range = getSelectionRange();
|
|
19
19
|
if (range) {
|
|
20
20
|
const rect = range.getBoundingClientRect();
|
|
@@ -100,7 +100,9 @@ class CommentUtilities {
|
|
|
100
100
|
content,
|
|
101
101
|
nodeType
|
|
102
102
|
} = _ref2;
|
|
103
|
-
let spanNode1
|
|
103
|
+
let spanNode1;
|
|
104
|
+
let spanNode2;
|
|
105
|
+
let imageContainer;
|
|
104
106
|
if (nodeType === 'image') {
|
|
105
107
|
spanNode1 = document.createElement('div');
|
|
106
108
|
spanNode1.className = 'image-container';
|
|
@@ -5,7 +5,7 @@ import deepCopy from 'deep-copy';
|
|
|
5
5
|
import context from '../../context';
|
|
6
6
|
import CommonLoading from '../../components/common-loading';
|
|
7
7
|
import { INTERNAL_EVENT, PAGE_EDIT_AREA_WIDTH } from '../constants';
|
|
8
|
-
import { createDefaultEditor } from '../extension';
|
|
8
|
+
import { createDefaultEditor, HeaderToolbar } from '../extension';
|
|
9
9
|
import withNodeId from '../node-id';
|
|
10
10
|
import { withSocketIO } from '../socket';
|
|
11
11
|
import { focusEditor } from '../extension/core';
|
|
@@ -13,7 +13,6 @@ import InsertElementDialog from '../extension/commons/insert-element-dialog';
|
|
|
13
13
|
import { EditorContainer, EditorContent } from '../layout';
|
|
14
14
|
import EditableArticle from './editable-article';
|
|
15
15
|
import { ColorProvider } from '../hooks/use-color-context';
|
|
16
|
-
import { HeaderToolbar } from '../extension';
|
|
17
16
|
import ReadOnlyArticle from '../views/readonly-article';
|
|
18
17
|
import { isMobile } from '../../utils';
|
|
19
18
|
import { CollaboratorsProvider } from '../../hooks';
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
padding: 0px;
|
|
15
15
|
color: #212529;
|
|
16
16
|
font-size: 14px;
|
|
17
|
+
text-decoration: underline;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
.sdoc-history-files-wrapper .sdoc-history-files-content .sdoc-history-files-header {
|
|
@@ -31,6 +32,10 @@
|
|
|
31
32
|
overflow-y: scroll;
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
.sdoc-history-files-wrapper .sdoc-history-files-content .no-header {
|
|
36
|
+
margin-top: 8px;
|
|
37
|
+
}
|
|
38
|
+
|
|
34
39
|
.sdoc-history-files-wrapper .sdoc-history-files-content .sdoc-history-files .sdoc-history-files-item {
|
|
35
40
|
font-size: 14px;
|
|
36
41
|
line-height: 32px;
|
|
@@ -3,9 +3,14 @@ import React, { useCallback, useEffect, useState, useRef } from 'react';
|
|
|
3
3
|
import { Editor } from '@seafile/slate';
|
|
4
4
|
import { ReactEditor } from '@seafile/slate-react';
|
|
5
5
|
import { withTranslation } from 'react-i18next';
|
|
6
|
+
import classNames from 'classnames';
|
|
7
|
+
import debounce from 'lodash.debounce';
|
|
8
|
+
import toaster from '../../../../components/toast';
|
|
6
9
|
import EventBus from '../../../utils/event-bus';
|
|
10
|
+
import context from '../../../../context';
|
|
11
|
+
import { focusEditor } from '../../core';
|
|
7
12
|
import { insertSdocFileLink } from '../../plugins/sdoc-link/helpers';
|
|
8
|
-
import { LocalStorage } from '../../../../utils';
|
|
13
|
+
import { LocalStorage, isEnglish } from '../../../../utils';
|
|
9
14
|
import { INTERNAL_EVENT } from '../../../constants';
|
|
10
15
|
import { EXTERNAL_EVENT } from '../../../../constants';
|
|
11
16
|
import { SDOC_LINK } from '../../constants';
|
|
@@ -54,6 +59,13 @@ const HistoryFiles = _ref => {
|
|
|
54
59
|
const files = LocalStorage.getItem('sdoc-recent-files') || [];
|
|
55
60
|
setFiles(files);
|
|
56
61
|
}, []);
|
|
62
|
+
const onInsertLink = useCallback(params => {
|
|
63
|
+
const {
|
|
64
|
+
insertSdocFileLinkCallback
|
|
65
|
+
} = insertLinkCallback;
|
|
66
|
+
insertSdocFileLinkCallback(editor, params.data.obj_name, params.data.doc_uuid);
|
|
67
|
+
closeDialog();
|
|
68
|
+
}, [closeDialog, editor, insertLinkCallback]);
|
|
57
69
|
useEffect(() => {
|
|
58
70
|
getPosition();
|
|
59
71
|
getHistoryFiles();
|
|
@@ -62,41 +74,83 @@ const HistoryFiles = _ref => {
|
|
|
62
74
|
}, 0);
|
|
63
75
|
const sdocScrollContainer = document.getElementById('sdoc-scroll-container');
|
|
64
76
|
sdocScrollContainer.addEventListener('scroll', onScroll);
|
|
77
|
+
const eventBus = EventBus.getInstance();
|
|
78
|
+
const unsubscribeInsertLink = eventBus.subscribe(EXTERNAL_EVENT.INSERT_LINK, onInsertLink);
|
|
65
79
|
document.addEventListener('click', onClick);
|
|
66
80
|
return () => {
|
|
67
81
|
sdocScrollContainer.removeEventListener('scroll', onScroll);
|
|
82
|
+
unsubscribeInsertLink();
|
|
68
83
|
document.removeEventListener('click', onClick);
|
|
69
84
|
};
|
|
70
85
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
71
86
|
}, []);
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
87
|
+
const onKeydown = useCallback(e => {
|
|
88
|
+
const {
|
|
89
|
+
key,
|
|
90
|
+
target
|
|
91
|
+
} = e;
|
|
92
|
+
if (key === 'Backspace' && !target.selectionStart && !target.selectionEnd && !target.value) {
|
|
93
|
+
focusEditor(editor);
|
|
94
|
+
closeDialog();
|
|
95
|
+
}
|
|
96
|
+
}, [closeDialog, editor]);
|
|
97
|
+
const onCompositionStart = e => {
|
|
98
|
+
e.stopPropagation();
|
|
99
|
+
historyFilesInputRef.current.typing = true;
|
|
100
|
+
};
|
|
101
|
+
const onCompositionEnd = e => {
|
|
102
|
+
e.stopPropagation();
|
|
103
|
+
historyFilesInputRef.current.typing = false;
|
|
104
|
+
onSearch(e);
|
|
105
|
+
};
|
|
106
|
+
const onSearch = useCallback(async e => {
|
|
107
|
+
// Ignore when entering Chinese
|
|
108
|
+
if (historyFilesInputRef.current.typing) return;
|
|
109
|
+
|
|
110
|
+
// Show history files when search is empty
|
|
111
|
+
if (e.target.value.trim().length === 0) {
|
|
112
|
+
setHeader(t('Recent_previews'));
|
|
113
|
+
setNewFileName('');
|
|
114
|
+
getHistoryFiles();
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Cannot be found if the search is less than three characters.
|
|
119
|
+
if (isEnglish(e.target.value.trim()) && e.target.value.length < 3) {
|
|
120
|
+
setFiles([]);
|
|
121
|
+
setHeader(t('The_document_does_not_exist'));
|
|
122
|
+
setNewFileName(e.target.value);
|
|
84
123
|
return;
|
|
85
124
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
125
|
+
try {
|
|
126
|
+
var _res$data;
|
|
127
|
+
const res = await context.searchSdocFiles(e.target.value, 1, 10);
|
|
128
|
+
if (res === null || res === void 0 ? void 0 : (_res$data = res.data) === null || _res$data === void 0 ? void 0 : _res$data.results) {
|
|
129
|
+
let newFiles = res.data.results;
|
|
130
|
+
if (newFiles.length === 0) {
|
|
131
|
+
setHeader(t('The_document_does_not_exist'));
|
|
132
|
+
setNewFileName(e.target.value);
|
|
133
|
+
} else {
|
|
134
|
+
setHeader('');
|
|
135
|
+
setNewFileName('');
|
|
136
|
+
}
|
|
137
|
+
setFiles(newFiles);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
} catch (error) {
|
|
141
|
+
toaster.danger(error.message);
|
|
142
|
+
}
|
|
89
143
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
90
144
|
}, []);
|
|
91
145
|
const onSelect = useCallback(fileInfo => {
|
|
92
146
|
const {
|
|
93
|
-
|
|
94
|
-
|
|
147
|
+
doc_uuid,
|
|
148
|
+
name
|
|
95
149
|
} = fileInfo;
|
|
96
150
|
const {
|
|
97
151
|
insertSdocFileLinkCallback
|
|
98
152
|
} = insertLinkCallback;
|
|
99
|
-
insertSdocFileLinkCallback(editor,
|
|
153
|
+
insertSdocFileLinkCallback(editor, name, doc_uuid);
|
|
100
154
|
closeDialog();
|
|
101
155
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
102
156
|
}, []);
|
|
@@ -112,8 +166,7 @@ const HistoryFiles = _ref => {
|
|
|
112
166
|
eventBus.dispatch(EXTERNAL_EVENT.CREATE_SDOC_FILE, {
|
|
113
167
|
newFileName: newFileName.trim()
|
|
114
168
|
});
|
|
115
|
-
|
|
116
|
-
}, [closeDialog, newFileName]);
|
|
169
|
+
}, [newFileName]);
|
|
117
170
|
return /*#__PURE__*/React.createElement("div", {
|
|
118
171
|
ref: historyFilesRef,
|
|
119
172
|
className: "sdoc-history-files-wrapper popover",
|
|
@@ -123,26 +176,28 @@ const HistoryFiles = _ref => {
|
|
|
123
176
|
className: "sdoc-history-files-search-input",
|
|
124
177
|
ref: historyFilesInputRef,
|
|
125
178
|
autoComplete: "off",
|
|
126
|
-
onChange: onSearch,
|
|
127
|
-
onCompositionStart:
|
|
128
|
-
|
|
129
|
-
|
|
179
|
+
onChange: debounce(onSearch, 200),
|
|
180
|
+
onCompositionStart: onCompositionStart,
|
|
181
|
+
onCompositionEnd: onCompositionEnd,
|
|
182
|
+
onKeyDown: onKeydown
|
|
130
183
|
}), /*#__PURE__*/React.createElement("div", {
|
|
131
184
|
className: "sdoc-history-files-content"
|
|
132
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
185
|
+
}, header.length !== 0 && /*#__PURE__*/React.createElement("div", {
|
|
133
186
|
className: "sdoc-history-files-header"
|
|
134
187
|
}, header), /*#__PURE__*/React.createElement("div", {
|
|
135
|
-
className:
|
|
188
|
+
className: classNames('sdoc-history-files', {
|
|
189
|
+
'no-header': header.length === 0
|
|
190
|
+
})
|
|
136
191
|
}, files.map(item => {
|
|
137
192
|
return /*#__PURE__*/React.createElement("div", {
|
|
138
|
-
key: item.
|
|
193
|
+
key: item.doc_uuid,
|
|
139
194
|
className: "sdoc-history-files-item",
|
|
140
195
|
onClick: () => {
|
|
141
196
|
onSelect(item);
|
|
142
197
|
}
|
|
143
198
|
}, /*#__PURE__*/React.createElement("i", {
|
|
144
199
|
className: "sdocfont sdoc-document"
|
|
145
|
-
}), /*#__PURE__*/React.createElement("span", null, item.
|
|
200
|
+
}), /*#__PURE__*/React.createElement("span", null, item.name));
|
|
146
201
|
}), /*#__PURE__*/React.createElement("div", {
|
|
147
202
|
className: "sdoc-history-files-item",
|
|
148
203
|
onClick: onShowMore
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// extension plugin
|
|
2
2
|
import * as ELEMENT_TYPE from './element-type';
|
|
3
|
+
// eslint-disable-next-line no-duplicate-imports
|
|
3
4
|
import { BLOCKQUOTE, TITLE, SUBTITLE, HEADER, HEADER1, HEADER2, HEADER3, HEADER4, HEADER5, HEADER6, PARAGRAPH, ORDERED_LIST, UNORDERED_LIST, LIST_ITEM, CHECK_LIST_ITEM, CODE_BLOCK, CODE_LINE, TABLE, TABLE_CELL, TABLE_ROW, LINK, SDOC_LINK, FILE_LINK, IMAGE, IMAGE_BLOCK, TOP_LEVEL_TYPES, INLINE_LEVEL_TYPES, CALL_OUT } from './element-type';
|
|
4
5
|
export { DEFAULT_COLORS, STANDARD_COLORS, DEFAULT_RECENT_USED_LIST, DEFAULT_FONT_COLOR, RECENT_USED_HIGHLIGHT_COLORS_KEY, RECENT_USED_FONT_COLORS_KEY, RECENT_USED_TABLE_CELL_BACKGROUND_COLORS_KEY, DEFAULT_LAST_USED_FONT_COLOR, DEFAULT_LAST_USED_HIGHLIGHT_COLOR, DEFAULT_LAST_USED_TABLE_CELL_BACKGROUND_COLOR } from './color';
|
|
5
6
|
export { FONT_SIZE, DEFAULT_FONT, FONT, GOOGLE_FONT_CLASS, RECENT_USED_FONTS_KEY, SDOC_FONT_SIZE } from './font';
|
|
@@ -72,6 +72,7 @@ const renderCallout = (_ref, editor) => {
|
|
|
72
72
|
top: menuTop,
|
|
73
73
|
left: left // left = code-block left distance
|
|
74
74
|
};
|
|
75
|
+
|
|
75
76
|
setPopoverPosition(newMenuPosition);
|
|
76
77
|
}
|
|
77
78
|
}, [isShowColorSelector, readOnly]);
|
|
@@ -107,6 +108,7 @@ const renderCallout = (_ref, editor) => {
|
|
|
107
108
|
top: menuTop,
|
|
108
109
|
left: left // left = callout left distance
|
|
109
110
|
};
|
|
111
|
+
|
|
110
112
|
setPopoverPosition(newMenuPosition);
|
|
111
113
|
setIsShowColorSelector(true);
|
|
112
114
|
}, [readOnly]);
|
|
@@ -23,6 +23,7 @@ export const isMenuDisabled = (editor, readonly) => {
|
|
|
23
23
|
if (isMatch) return false; // enable
|
|
24
24
|
return true; // disable
|
|
25
25
|
};
|
|
26
|
+
|
|
26
27
|
export const getSelectCodeElem = editor => {
|
|
27
28
|
const codeNode = getSelectedNodeByType(editor, CODE_BLOCK);
|
|
28
29
|
if (codeNode == null) return null;
|
|
@@ -32,8 +33,8 @@ export const changeToCodeBlock = function (editor) {
|
|
|
32
33
|
let language = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
|
|
33
34
|
let position = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : INSERT_POSITION.CURRENT;
|
|
34
35
|
// Summarizes the strings for the selected highest-level node
|
|
35
|
-
let strArr = []
|
|
36
|
-
|
|
36
|
+
let strArr = [];
|
|
37
|
+
let path = Editor.path(editor, editor.selection);
|
|
37
38
|
if (position === INSERT_POSITION.AFTER) {
|
|
38
39
|
strArr = [''];
|
|
39
40
|
} else {
|
|
@@ -62,6 +63,7 @@ export const changeToCodeBlock = function (editor) {
|
|
|
62
63
|
style: {
|
|
63
64
|
white_space: 'nowrap' // default nowrap
|
|
64
65
|
},
|
|
66
|
+
|
|
65
67
|
children: [{
|
|
66
68
|
id: slugid.nice(),
|
|
67
69
|
type: CODE_LINE,
|
|
@@ -125,7 +127,8 @@ export const changeToPlainText = editor => {
|
|
|
125
127
|
};
|
|
126
128
|
export const setClipboardCodeBlockData = value => {
|
|
127
129
|
// Insert text into the clipboard for use on other pages
|
|
128
|
-
|
|
130
|
+
// Empty string cannot apply in `copy`
|
|
131
|
+
const text = value.children.map(line => Node.string(line)).join('\n') || ' ';
|
|
129
132
|
copy(text, {
|
|
130
133
|
format: 'text/plain',
|
|
131
134
|
onCopy: data => {
|
|
@@ -81,6 +81,7 @@ const CodeBlock = _ref => {
|
|
|
81
81
|
top: menuTop,
|
|
82
82
|
left: left // left = code-block left distance
|
|
83
83
|
};
|
|
84
|
+
|
|
84
85
|
setMenuPosition(newMenuPosition);
|
|
85
86
|
}
|
|
86
87
|
setShowHoverMenu(true);
|
|
@@ -104,6 +105,7 @@ const CodeBlock = _ref => {
|
|
|
104
105
|
top: menuTop,
|
|
105
106
|
left: left // left = code-block left distance
|
|
106
107
|
};
|
|
108
|
+
|
|
107
109
|
setMenuPosition(newMenuPosition);
|
|
108
110
|
}
|
|
109
111
|
}, [readOnly, showHoverMenu]);
|
|
@@ -71,9 +71,9 @@ const ImageHoverMenu = _ref => {
|
|
|
71
71
|
const beforeLeaf = newNodeEntry[0].children.slice(0, index);
|
|
72
72
|
const imageLeaf = newNodeEntry[0].children.slice(index, index + 1);
|
|
73
73
|
const afterLeaf = newNodeEntry[0].children.slice(index + 1);
|
|
74
|
-
let beforeNode = null
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
let beforeNode = null;
|
|
75
|
+
let centerNode = null;
|
|
76
|
+
let afterNode = null;
|
|
77
77
|
let p = path[0];
|
|
78
78
|
if (!beforeLeaf.every(item => {
|
|
79
79
|
var _item$text;
|
|
@@ -5,7 +5,6 @@ import slugid from 'slugid';
|
|
|
5
5
|
import copy from 'copy-to-clipboard';
|
|
6
6
|
import context from '../../../../context';
|
|
7
7
|
import { focusEditor, getNodeType, getSelectedElems } from '../../core';
|
|
8
|
-
import { LocalStorage } from '../../../../utils';
|
|
9
8
|
import { SDOC_LINK, LINK, INSERT_FILE_DISPLAY_TYPE, CODE_BLOCK, CODE_LINE, PARAGRAPH } from '../../constants';
|
|
10
9
|
export const isMenuDisabled = (editor, readonly) => {
|
|
11
10
|
if (readonly) return true;
|
|
@@ -22,6 +21,7 @@ export const isMenuDisabled = (editor, readonly) => {
|
|
|
22
21
|
if (notMatch) return true; // disabled
|
|
23
22
|
return false; // enable
|
|
24
23
|
};
|
|
24
|
+
|
|
25
25
|
export const generateSdocFileNode = (uuid, text) => {
|
|
26
26
|
const sdocFileNode = {
|
|
27
27
|
id: slugid.nice(),
|
|
@@ -175,6 +175,7 @@ export const isAllInTable = editor => {
|
|
|
175
175
|
if (firstSelectedNode.type !== ELEMENT_TYPE.TABLE) return false;
|
|
176
176
|
return selectedNodes.slice(1).every(node => [ELEMENT_TYPE.TABLE_ROW, ELEMENT_TYPE.TABLE_CELL].includes(node.type)); // same table element
|
|
177
177
|
};
|
|
178
|
+
|
|
178
179
|
export const setCellStyle = (editor, style) => {
|
|
179
180
|
// Select single cell
|
|
180
181
|
if (ObjectUtils.isSameObject(editor.tableSelectedRange, EMPTY_SELECTED_RANGE)) {
|
|
@@ -1512,4 +1513,25 @@ export const getHighlightClass = (editor, cellPath) => {
|
|
|
1512
1513
|
const rowIndex = cellPath[cellPath.length - 2];
|
|
1513
1514
|
const className = getCellHighlightClassName(alternate_highlight_color, rowIndex);
|
|
1514
1515
|
return className;
|
|
1516
|
+
};
|
|
1517
|
+
|
|
1518
|
+
// Correct the selected range when combined cell are selected
|
|
1519
|
+
export const adjustCombinedCellRange = (table, range) => {
|
|
1520
|
+
const {
|
|
1521
|
+
minRowIndex,
|
|
1522
|
+
maxRowIndex,
|
|
1523
|
+
minColIndex,
|
|
1524
|
+
maxColIndex
|
|
1525
|
+
} = range;
|
|
1526
|
+
const firstCell = table.children[minRowIndex].children[minColIndex];
|
|
1527
|
+
const {
|
|
1528
|
+
colspan = 0,
|
|
1529
|
+
rowspan = 0
|
|
1530
|
+
} = firstCell;
|
|
1531
|
+
if (rowspan > 1 || colspan > 1) {
|
|
1532
|
+
const isRowCombined = minRowIndex + rowspan === maxRowIndex + 1;
|
|
1533
|
+
const isColCombined = minColIndex + colspan === maxColIndex + 1;
|
|
1534
|
+
if (isRowCombined && isColCombined) return EMPTY_SELECTED_RANGE;
|
|
1535
|
+
}
|
|
1536
|
+
return range;
|
|
1515
1537
|
};
|
|
@@ -2,13 +2,13 @@ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
|
2
2
|
import React, { useRef, useState, useEffect, useCallback } from 'react';
|
|
3
3
|
import classnames from 'classnames';
|
|
4
4
|
import throttle from 'lodash.throttle';
|
|
5
|
-
import { useSelected, useSlateStatic, useReadOnly } from '@seafile/slate-react';
|
|
5
|
+
import { useSelected, useSlateStatic, useReadOnly, ReactEditor } from '@seafile/slate-react';
|
|
6
6
|
import { Transforms, Editor } from '@seafile/slate';
|
|
7
7
|
import { EMPTY_SELECTED_RANGE } from '../constants';
|
|
8
8
|
import { ResizeHandlersContext, TableSelectedRangeContext, SettingSelectRangeContext } from './hooks';
|
|
9
9
|
import EventBus from '../../../../utils/event-bus';
|
|
10
10
|
import { INTERNAL_EVENT } from '../../../../constants';
|
|
11
|
-
import { getTableColumns, setTableSelectedRange, getFirstTableCell, getRowHeight } from '../helpers';
|
|
11
|
+
import { getTableColumns, setTableSelectedRange, getFirstTableCell, getRowHeight, adjustCombinedCellRange } from '../helpers';
|
|
12
12
|
import ObjectUtils from '../../../../utils/object-utils';
|
|
13
13
|
import ResizeHandlers from './resize-handlers';
|
|
14
14
|
import { registerResizeEvents, unregisterResizeEvents } from '../../../../utils/mouse-event';
|
|
@@ -102,12 +102,14 @@ const Table = _ref => {
|
|
|
102
102
|
const cellData = tableCell.style.gridArea.split(' / ');
|
|
103
103
|
const endRowSpan = Number(cellData[2].split(' ')[1]);
|
|
104
104
|
const endColSpan = Number(cellData[3].split(' ')[1]);
|
|
105
|
-
const
|
|
105
|
+
const tableSlateNode = ReactEditor.toSlateNode(editor, table.current);
|
|
106
|
+
let newSelectedRange = {
|
|
106
107
|
minRowIndex: Math.min(startRowIndex, endRowIndex),
|
|
107
108
|
maxRowIndex: startRowIndex < endRowIndex ? endRowIndex + endRowSpan - 1 : startRowIndex + startRowSpan - 1,
|
|
108
109
|
minColIndex: Math.min(startColIndex, endColIndex),
|
|
109
110
|
maxColIndex: startColIndex < endColIndex ? endColIndex + endColSpan - 1 : startColIndex + startColSpan - 1
|
|
110
111
|
};
|
|
112
|
+
newSelectedRange = adjustCombinedCellRange(tableSlateNode, newSelectedRange);
|
|
111
113
|
if (!ObjectUtils.isSameObject(selectedRange, EMPTY_SELECTED_RANGE)) {
|
|
112
114
|
event.preventDefault();
|
|
113
115
|
Editor.withoutNormalizing(editor, () => {
|
|
@@ -5,9 +5,9 @@ import { useSlateStatic, useReadOnly } from '@seafile/slate-react';
|
|
|
5
5
|
import { Editor, Transforms } from '@seafile/slate';
|
|
6
6
|
import ObjectUtils from '../../../../utils/object-utils';
|
|
7
7
|
import { findPath, focusEditor } from '../../../core';
|
|
8
|
-
import {
|
|
8
|
+
import { useTableSelectedRangeContext } from './hooks';
|
|
9
9
|
import { EMPTY_SELECTED_RANGE, SELECTED_TABLE_CELL_BACKGROUND_COLOR, TABLE_CELL_STYLE } from '../constants';
|
|
10
|
-
import {
|
|
10
|
+
import { colorBlend, getHighlightClass } from '../helpers';
|
|
11
11
|
import EventBus from '../../../../utils/event-bus';
|
|
12
12
|
import { INTERNAL_EVENT } from '../../../../constants';
|
|
13
13
|
const TableCell = _ref => {
|
|
@@ -19,7 +19,6 @@ const TableCell = _ref => {
|
|
|
19
19
|
const editor = useSlateStatic();
|
|
20
20
|
const selectedRange = useTableSelectedRangeContext() || EMPTY_SELECTED_RANGE;
|
|
21
21
|
const cellPath = findPath(editor, element, [0, 0]);
|
|
22
|
-
const columns = useResizeHandlersContext() || getTableColumns(editor, element);
|
|
23
22
|
const pathLength = cellPath.length;
|
|
24
23
|
const rowIndex = cellPath[pathLength - 2];
|
|
25
24
|
const cellIndex = cellPath[pathLength - 1];
|
|
@@ -60,10 +59,10 @@ const TableCell = _ref => {
|
|
|
60
59
|
if (element.is_combined) {
|
|
61
60
|
style.display = 'none';
|
|
62
61
|
}
|
|
63
|
-
if (rowIndex
|
|
62
|
+
if (rowIndex === 0) {
|
|
64
63
|
style.borderTop = '1px solid #ddd';
|
|
65
64
|
}
|
|
66
|
-
if (cellIndex
|
|
65
|
+
if (cellIndex === 0) {
|
|
67
66
|
style.borderLeft = '1px solid #ddd';
|
|
68
67
|
}
|
|
69
68
|
const {
|
|
@@ -134,10 +133,10 @@ function renderTableCell(props) {
|
|
|
134
133
|
if (element.is_combined) {
|
|
135
134
|
style.display = 'none';
|
|
136
135
|
}
|
|
137
|
-
if (rowIndex
|
|
136
|
+
if (rowIndex === 0) {
|
|
138
137
|
style.borderTop = '1px solid #ddd';
|
|
139
138
|
}
|
|
140
|
-
if (cellIndex
|
|
139
|
+
if (cellIndex === 0) {
|
|
141
140
|
style.borderLeft = '1px solid #ddd';
|
|
142
141
|
}
|
|
143
142
|
const {
|
package/dist/basic-sdk/extension/plugins/table/render/resize-handlers/column-resize-handler.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
|
-
import React, { useRef, useState, useEffect,
|
|
2
|
+
import React, { useRef, useState, useEffect, useLayoutEffect } from 'react';
|
|
3
3
|
import { useSlateStatic } from '@seafile/slate-react';
|
|
4
4
|
import { useTableRootContext } from '../hooks';
|
|
5
5
|
import { TABLE_CELL_MIN_WIDTH } from '../../constants';
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useState, useRef, useLayoutEffect } from 'react';
|
|
2
|
-
import { useSlateStatic } from '@seafile/slate-react';
|
|
3
|
-
import { ReactEditor } from '@seafile/slate-react';
|
|
2
|
+
import { useSlateStatic, ReactEditor } from '@seafile/slate-react';
|
|
4
3
|
import { TABLE_ROW_MIN_HEIGHT } from '../../constants';
|
|
5
4
|
import { focusClosestCellWhenJustifyCellSize, getRowHeight, updateTableRowHeight } from '../../helpers';
|
|
6
5
|
import { eventStopPropagation, getMouseDownInfo, getMouseMoveInfo, registerResizeEvents, unregisterResizeEvents } from '../../../../../utils/mouse-event';
|
|
@@ -65,7 +64,7 @@ const RowResizeHandler = _ref => {
|
|
|
65
64
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
66
65
|
}, [isDraggingResizeHandler, mouseDownInfo, rowBottom, table, height]);
|
|
67
66
|
useEffect(() => {
|
|
68
|
-
const cell = row.children.filter(cell => !cell.is_combined && (!cell.rowspan || cell.rowspan
|
|
67
|
+
const cell = row.children.filter(cell => !cell.is_combined && (!cell.rowspan || cell.rowspan === 1))[0];
|
|
69
68
|
if (!cell) return;
|
|
70
69
|
const rowDom = ReactEditor.toDOMNode(editor, cell);
|
|
71
70
|
if (!rowDom) return;
|
package/dist/basic-sdk/extension/plugins/table/render/table-header/rows-header/row-header.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useRef, useCallback, useState, useEffect
|
|
1
|
+
import React, { useRef, useCallback, useState, useEffect } from 'react';
|
|
2
2
|
import { useSlateStatic } from '@seafile/slate-react';
|
|
3
3
|
import classnames from 'classnames';
|
|
4
4
|
import ObjectUtils from '../../../../../../utils/object-utils';
|
|
@@ -92,6 +92,7 @@ export const getDomTopHeight = (dom, slateNode) => {
|
|
|
92
92
|
if (ADD_POSITION_OFFSET_TYPE.includes(slateNode.type)) {
|
|
93
93
|
offsetY = lightHight / 2 + paddingTop - 12; // side toolbar icon is 12 px
|
|
94
94
|
}
|
|
95
|
+
|
|
95
96
|
const HEADER_HEIGHT = 56 + 44;
|
|
96
97
|
return rect.y - HEADER_HEIGHT + offsetY;
|
|
97
98
|
};
|
|
@@ -3,7 +3,7 @@ import { UncontrolledPopover } from 'reactstrap';
|
|
|
3
3
|
import { withTranslation } from 'react-i18next';
|
|
4
4
|
import { ReactEditor, useSlateStatic } from '@seafile/slate-react';
|
|
5
5
|
import { onSetNodeType } from './helpers';
|
|
6
|
-
import { SIDE_TRANSFORM_MENUS_CONFIG, LIST_ITEM_SUPPORTED_TRANSFORMATION, LIST_ITEM_CORRELATION_TYPE, BLOCKQUOTE, CALL_OUT } from '../../constants';
|
|
6
|
+
import { SIDE_TRANSFORM_MENUS_CONFIG, LIST_ITEM_SUPPORTED_TRANSFORMATION, LIST_ITEM_CORRELATION_TYPE, BLOCKQUOTE, CALL_OUT, HEADERS } from '../../constants';
|
|
7
7
|
import DropdownMenuItem from '../../commons/dropdown-menu-item';
|
|
8
8
|
const TransformMenus = _ref => {
|
|
9
9
|
let {
|
|
@@ -24,11 +24,18 @@ const TransformMenus = _ref => {
|
|
|
24
24
|
newSideMenusConfig = SIDE_TRANSFORM_MENUS_CONFIG.filter(item => LIST_ITEM_SUPPORTED_TRANSFORMATION.includes(item.type));
|
|
25
25
|
}
|
|
26
26
|
const path = ReactEditor.findPath(editor, slateNode);
|
|
27
|
-
if (path
|
|
27
|
+
if (path) {
|
|
28
28
|
const nodeIndex = path[0];
|
|
29
29
|
const highestNode = editor.children[nodeIndex];
|
|
30
|
-
if (
|
|
31
|
-
|
|
30
|
+
if (path.length > 1) {
|
|
31
|
+
if (highestNode.type === BLOCKQUOTE) {
|
|
32
|
+
newSideMenusConfig = SIDE_TRANSFORM_MENUS_CONFIG.filter(item => item.type !== CALL_OUT);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// headers can't be nested by quote block
|
|
37
|
+
if (HEADERS.includes(highestNode.type)) {
|
|
38
|
+
newSideMenusConfig = SIDE_TRANSFORM_MENUS_CONFIG.filter(item => item.type !== BLOCKQUOTE);
|
|
32
39
|
}
|
|
33
40
|
}
|
|
34
41
|
return newSideMenusConfig;
|
|
@@ -27,8 +27,8 @@ export const getSelectionRange = () => {
|
|
|
27
27
|
};
|
|
28
28
|
export const getCursorPosition = function () {
|
|
29
29
|
let isScrollUp = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
30
|
-
let x = 0
|
|
31
|
-
|
|
30
|
+
let x = 0;
|
|
31
|
+
let y = 0;
|
|
32
32
|
let range = getSelectionRange();
|
|
33
33
|
if (range) {
|
|
34
34
|
const rect = range.getBoundingClientRect();
|
package/dist/constants/index.js
CHANGED
|
@@ -17,7 +17,8 @@ export const EXTERNAL_EVENT = {
|
|
|
17
17
|
NEW_NOTIFICATION: 'new_notification',
|
|
18
18
|
PARTICIPANT_ADDED: 'participant-added',
|
|
19
19
|
PARTICIPANT_REMOVED: 'participant-removed',
|
|
20
|
-
CREATE_SDOC_FILE: 'create_sdoc_file'
|
|
20
|
+
CREATE_SDOC_FILE: 'create_sdoc_file',
|
|
21
|
+
INSERT_LINK: 'insert_link'
|
|
21
22
|
};
|
|
22
23
|
export const TIP_TYPE = {
|
|
23
24
|
DELETE_NO_CHANGES_REVISION: 'delete_no_changes_revision',
|
package/dist/context.js
CHANGED
|
@@ -204,6 +204,10 @@ class Context {
|
|
|
204
204
|
const docUuid = this.getSetting('docUuid');
|
|
205
205
|
return this.api.getCopyMoveProgressView(docUuid, taskId);
|
|
206
206
|
}
|
|
207
|
+
searchSdocFiles(query, page, per_page) {
|
|
208
|
+
const docUuid = this.getSetting('docUuid');
|
|
209
|
+
return this.api.searchSdocFiles(docUuid, query, page, per_page);
|
|
210
|
+
}
|
|
207
211
|
|
|
208
212
|
// participants
|
|
209
213
|
listParticipants() {
|
package/dist/layout/layout.js
CHANGED
|
@@ -2,12 +2,38 @@ import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutPr
|
|
|
2
2
|
const _excluded = ["children", "className"];
|
|
3
3
|
import React, { useEffect } from 'react';
|
|
4
4
|
import classnames from 'classnames';
|
|
5
|
+
import context from '../context';
|
|
6
|
+
import { LocalStorage } from '../utils';
|
|
5
7
|
const Layout = _ref => {
|
|
6
8
|
let {
|
|
7
9
|
children,
|
|
8
10
|
className
|
|
9
11
|
} = _ref,
|
|
10
12
|
restProps = _objectWithoutProperties(_ref, _excluded);
|
|
13
|
+
const cacheHistoryfiles = () => {
|
|
14
|
+
const docUuid = context.getSetting('docUuid');
|
|
15
|
+
const docName = context.getSetting('docName');
|
|
16
|
+
const rencentFiles = LocalStorage.getItem('sdoc-recent-files', []);
|
|
17
|
+
let arr = [];
|
|
18
|
+
const newFile = {
|
|
19
|
+
doc_uuid: docUuid,
|
|
20
|
+
name: docName
|
|
21
|
+
};
|
|
22
|
+
if (rencentFiles.length > 0) {
|
|
23
|
+
const isExist = rencentFiles.find(item => item.doc_uuid === docUuid);
|
|
24
|
+
if (isExist) return;
|
|
25
|
+
if (!isExist) {
|
|
26
|
+
let newRencentFiles = rencentFiles.slice(0);
|
|
27
|
+
if (rencentFiles.length === 10) {
|
|
28
|
+
newRencentFiles.shift();
|
|
29
|
+
}
|
|
30
|
+
arr = [newFile, ...newRencentFiles];
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
arr.push(newFile);
|
|
34
|
+
}
|
|
35
|
+
LocalStorage.setItem('sdoc-recent-files', arr);
|
|
36
|
+
};
|
|
11
37
|
useEffect(() => {
|
|
12
38
|
setTimeout(() => {
|
|
13
39
|
const url = window.location.href;
|
|
@@ -17,6 +43,7 @@ const Layout = _ref => {
|
|
|
17
43
|
element && element.scrollIntoView(true);
|
|
18
44
|
}
|
|
19
45
|
}, 500);
|
|
46
|
+
cacheHistoryfiles();
|
|
20
47
|
}, []);
|
|
21
48
|
return /*#__PURE__*/React.createElement("div", Object.assign({
|
|
22
49
|
className: classnames('sdoc-editor-page-wrapper', className)
|
package/dist/utils/index.js
CHANGED
|
@@ -56,12 +56,12 @@ export const resetWebTitle = t => {
|
|
|
56
56
|
};
|
|
57
57
|
export const getSelectionCoords = () => {
|
|
58
58
|
let doc = window.document;
|
|
59
|
-
let sel = doc.selection
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
let x = 0
|
|
64
|
-
|
|
59
|
+
let sel = doc.selection;
|
|
60
|
+
let range;
|
|
61
|
+
let rects;
|
|
62
|
+
let rect;
|
|
63
|
+
let x = 0;
|
|
64
|
+
let y = 0;
|
|
65
65
|
if (sel) {
|
|
66
66
|
if (sel.type !== 'Control') {
|
|
67
67
|
range = sel.createRange();
|
|
@@ -109,4 +109,11 @@ export const getSelectionCoords = () => {
|
|
|
109
109
|
y: y
|
|
110
110
|
};
|
|
111
111
|
};
|
|
112
|
+
export const isEnglish = str => {
|
|
113
|
+
const pattern = new RegExp('[A-Za-z]+');
|
|
114
|
+
if (pattern.test(str)) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
};
|
|
112
119
|
export { DateUtils, LocalStorage, getEventTransfer, Hotkey };
|