@seafile/sdoc-editor 0.4.33 → 0.4.35
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/extension/commons/history-files/index.css +5 -0
- package/dist/basic-sdk/extension/commons/history-files/index.js +72 -29
- package/dist/basic-sdk/extension/commons/select-file-dialog/local-files/index.css +2 -0
- package/dist/basic-sdk/extension/plugins/callout/render-elem/index.css +3 -0
- package/dist/basic-sdk/extension/plugins/code-block/helpers.js +2 -1
- package/dist/basic-sdk/extension/plugins/table/helpers.js +21 -0
- package/dist/basic-sdk/extension/plugins/table/render/index.js +5 -3
- package/dist/basic-sdk/extension/toolbar/side-toolbar/transform-menus.js +11 -4
- package/dist/constants/index.js +2 -1
- package/dist/context.js +4 -0
- package/dist/layout/layout.js +27 -0
- package/dist/utils/index.js +7 -0
- 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) {
|
|
@@ -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,13 @@ 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';
|
|
7
11
|
import { insertSdocFileLink } from '../../plugins/sdoc-link/helpers';
|
|
8
|
-
import { LocalStorage } from '../../../../utils';
|
|
12
|
+
import { LocalStorage, isEnglish } from '../../../../utils';
|
|
9
13
|
import { INTERNAL_EVENT } from '../../../constants';
|
|
10
14
|
import { EXTERNAL_EVENT } from '../../../../constants';
|
|
11
15
|
import { SDOC_LINK } from '../../constants';
|
|
@@ -54,6 +58,13 @@ const HistoryFiles = _ref => {
|
|
|
54
58
|
const files = LocalStorage.getItem('sdoc-recent-files') || [];
|
|
55
59
|
setFiles(files);
|
|
56
60
|
}, []);
|
|
61
|
+
const onInsertLink = useCallback(params => {
|
|
62
|
+
const {
|
|
63
|
+
insertSdocFileLinkCallback
|
|
64
|
+
} = insertLinkCallback;
|
|
65
|
+
insertSdocFileLinkCallback(editor, params.data.obj_name, params.data.doc_uuid);
|
|
66
|
+
closeDialog();
|
|
67
|
+
}, [closeDialog, editor, insertLinkCallback]);
|
|
57
68
|
useEffect(() => {
|
|
58
69
|
getPosition();
|
|
59
70
|
getHistoryFiles();
|
|
@@ -62,41 +73,73 @@ const HistoryFiles = _ref => {
|
|
|
62
73
|
}, 0);
|
|
63
74
|
const sdocScrollContainer = document.getElementById('sdoc-scroll-container');
|
|
64
75
|
sdocScrollContainer.addEventListener('scroll', onScroll);
|
|
76
|
+
const eventBus = EventBus.getInstance();
|
|
77
|
+
const unsubscribeInsertLink = eventBus.subscribe(EXTERNAL_EVENT.INSERT_LINK, onInsertLink);
|
|
65
78
|
document.addEventListener('click', onClick);
|
|
66
79
|
return () => {
|
|
67
80
|
sdocScrollContainer.removeEventListener('scroll', onScroll);
|
|
81
|
+
unsubscribeInsertLink();
|
|
68
82
|
document.removeEventListener('click', onClick);
|
|
69
83
|
};
|
|
70
84
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
71
85
|
}, []);
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
const onCompositionStart = e => {
|
|
87
|
+
e.stopPropagation();
|
|
88
|
+
historyFilesInputRef.current.typing = true;
|
|
89
|
+
};
|
|
90
|
+
const onCompositionEnd = e => {
|
|
91
|
+
e.stopPropagation();
|
|
92
|
+
historyFilesInputRef.current.typing = false;
|
|
93
|
+
onSearch(e);
|
|
94
|
+
};
|
|
95
|
+
const onSearch = useCallback(async e => {
|
|
96
|
+
// Ignore when entering Chinese
|
|
97
|
+
if (historyFilesInputRef.current.typing) return;
|
|
98
|
+
|
|
99
|
+
// Show history files when search is empty
|
|
100
|
+
if (e.target.value.trim().length === 0) {
|
|
101
|
+
setHeader(t('Recent_previews'));
|
|
102
|
+
setNewFileName('');
|
|
103
|
+
getHistoryFiles();
|
|
84
104
|
return;
|
|
85
105
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
106
|
+
|
|
107
|
+
// Cannot be found if the search is less than three characters.
|
|
108
|
+
if (isEnglish(e.target.value.trim()) && e.target.value.length < 3) {
|
|
109
|
+
setFiles([]);
|
|
110
|
+
setHeader(t('The_document_does_not_exist'));
|
|
111
|
+
setNewFileName(e.target.value);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
var _res$data;
|
|
116
|
+
const res = await context.searchSdocFiles(e.target.value, 1, 10);
|
|
117
|
+
if (res === null || res === void 0 ? void 0 : (_res$data = res.data) === null || _res$data === void 0 ? void 0 : _res$data.results) {
|
|
118
|
+
let newFiles = res.data.results;
|
|
119
|
+
if (newFiles.length === 0) {
|
|
120
|
+
setHeader(t('The_document_does_not_exist'));
|
|
121
|
+
setNewFileName(e.target.value);
|
|
122
|
+
} else {
|
|
123
|
+
setHeader('');
|
|
124
|
+
setNewFileName('');
|
|
125
|
+
}
|
|
126
|
+
setFiles(newFiles);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
} catch (error) {
|
|
130
|
+
toaster.danger(error.message);
|
|
131
|
+
}
|
|
89
132
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
90
133
|
}, []);
|
|
91
134
|
const onSelect = useCallback(fileInfo => {
|
|
92
135
|
const {
|
|
93
|
-
|
|
94
|
-
|
|
136
|
+
doc_uuid,
|
|
137
|
+
name
|
|
95
138
|
} = fileInfo;
|
|
96
139
|
const {
|
|
97
140
|
insertSdocFileLinkCallback
|
|
98
141
|
} = insertLinkCallback;
|
|
99
|
-
insertSdocFileLinkCallback(editor,
|
|
142
|
+
insertSdocFileLinkCallback(editor, name, doc_uuid);
|
|
100
143
|
closeDialog();
|
|
101
144
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
102
145
|
}, []);
|
|
@@ -112,8 +155,7 @@ const HistoryFiles = _ref => {
|
|
|
112
155
|
eventBus.dispatch(EXTERNAL_EVENT.CREATE_SDOC_FILE, {
|
|
113
156
|
newFileName: newFileName.trim()
|
|
114
157
|
});
|
|
115
|
-
|
|
116
|
-
}, [closeDialog, newFileName]);
|
|
158
|
+
}, [newFileName]);
|
|
117
159
|
return /*#__PURE__*/React.createElement("div", {
|
|
118
160
|
ref: historyFilesRef,
|
|
119
161
|
className: "sdoc-history-files-wrapper popover",
|
|
@@ -123,26 +165,27 @@ const HistoryFiles = _ref => {
|
|
|
123
165
|
className: "sdoc-history-files-search-input",
|
|
124
166
|
ref: historyFilesInputRef,
|
|
125
167
|
autoComplete: "off",
|
|
126
|
-
onChange: onSearch,
|
|
127
|
-
onCompositionStart:
|
|
128
|
-
|
|
129
|
-
}
|
|
168
|
+
onChange: debounce(onSearch, 200),
|
|
169
|
+
onCompositionStart: onCompositionStart,
|
|
170
|
+
onCompositionEnd: onCompositionEnd
|
|
130
171
|
}), /*#__PURE__*/React.createElement("div", {
|
|
131
172
|
className: "sdoc-history-files-content"
|
|
132
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
173
|
+
}, header.length !== 0 && /*#__PURE__*/React.createElement("div", {
|
|
133
174
|
className: "sdoc-history-files-header"
|
|
134
175
|
}, header), /*#__PURE__*/React.createElement("div", {
|
|
135
|
-
className:
|
|
176
|
+
className: classNames('sdoc-history-files', {
|
|
177
|
+
'no-header': header.length === 0
|
|
178
|
+
})
|
|
136
179
|
}, files.map(item => {
|
|
137
180
|
return /*#__PURE__*/React.createElement("div", {
|
|
138
|
-
key: item.
|
|
181
|
+
key: item.doc_uuid,
|
|
139
182
|
className: "sdoc-history-files-item",
|
|
140
183
|
onClick: () => {
|
|
141
184
|
onSelect(item);
|
|
142
185
|
}
|
|
143
186
|
}, /*#__PURE__*/React.createElement("i", {
|
|
144
187
|
className: "sdocfont sdoc-document"
|
|
145
|
-
}), /*#__PURE__*/React.createElement("span", null, item.
|
|
188
|
+
}), /*#__PURE__*/React.createElement("span", null, item.name));
|
|
146
189
|
}), /*#__PURE__*/React.createElement("div", {
|
|
147
190
|
className: "sdoc-history-files-item",
|
|
148
191
|
onClick: onShowMore
|
|
@@ -125,7 +125,8 @@ export const changeToPlainText = editor => {
|
|
|
125
125
|
};
|
|
126
126
|
export const setClipboardCodeBlockData = value => {
|
|
127
127
|
// Insert text into the clipboard for use on other pages
|
|
128
|
-
|
|
128
|
+
// Empty string cannot apply in `copy`
|
|
129
|
+
const text = value.children.map(line => Node.string(line)).join('\n') || ' ';
|
|
129
130
|
copy(text, {
|
|
130
131
|
format: 'text/plain',
|
|
131
132
|
onCopy: data => {
|
|
@@ -1512,4 +1512,25 @@ export const getHighlightClass = (editor, cellPath) => {
|
|
|
1512
1512
|
const rowIndex = cellPath[cellPath.length - 2];
|
|
1513
1513
|
const className = getCellHighlightClassName(alternate_highlight_color, rowIndex);
|
|
1514
1514
|
return className;
|
|
1515
|
+
};
|
|
1516
|
+
|
|
1517
|
+
// Correct the selected range when combined cell are selected
|
|
1518
|
+
export const adjustCombinedCellRange = (table, range) => {
|
|
1519
|
+
const {
|
|
1520
|
+
minRowIndex,
|
|
1521
|
+
maxRowIndex,
|
|
1522
|
+
minColIndex,
|
|
1523
|
+
maxColIndex
|
|
1524
|
+
} = range;
|
|
1525
|
+
const firstCell = table.children[minRowIndex].children[minColIndex];
|
|
1526
|
+
const {
|
|
1527
|
+
colspan = 0,
|
|
1528
|
+
rowspan = 0
|
|
1529
|
+
} = firstCell;
|
|
1530
|
+
if (rowspan > 1 || colspan > 1) {
|
|
1531
|
+
const isRowCombined = minRowIndex + rowspan === maxRowIndex + 1;
|
|
1532
|
+
const isColCombined = minColIndex + colspan === maxColIndex + 1;
|
|
1533
|
+
if (isRowCombined && isColCombined) return EMPTY_SELECTED_RANGE;
|
|
1534
|
+
}
|
|
1535
|
+
return range;
|
|
1515
1536
|
};
|
|
@@ -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, () => {
|
|
@@ -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;
|
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
|
@@ -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 };
|