@seafile/sdoc-editor 0.5.41 → 0.5.43
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/constants/index.js +2 -1
- package/dist/basic-sdk/editor/comment-article.js +9 -10
- package/dist/basic-sdk/editor/editable-article.js +8 -9
- package/dist/basic-sdk/extension/commons/{history-files → file-insert-dialog}/index.js +115 -95
- package/dist/basic-sdk/extension/commons/file-insert-dialog/style.css +76 -0
- package/dist/basic-sdk/extension/commons/insert-element-dialog/index.js +9 -8
- package/dist/basic-sdk/extension/commons/menu-shortcut-indicator/style.css +5 -7
- package/dist/basic-sdk/extension/constants/element-type.js +1 -0
- package/dist/basic-sdk/extension/constants/index.js +2 -2
- package/dist/basic-sdk/extension/plugins/code-block/hover-menu/index.css +9 -0
- package/dist/basic-sdk/extension/plugins/code-block/hover-menu/index.js +41 -24
- package/dist/basic-sdk/extension/plugins/image/helpers.js +26 -2
- package/dist/basic-sdk/extension/plugins/image/render-elem.js +10 -4
- package/dist/basic-sdk/extension/plugins/sdoc-link/helpers.js +62 -13
- package/dist/basic-sdk/extension/plugins/sdoc-link/index.js +3 -2
- package/dist/basic-sdk/extension/plugins/sdoc-link/plugin.js +33 -23
- package/dist/basic-sdk/extension/plugins/sdoc-link/{render-elem.css → render/render-elem.css} +5 -1
- package/dist/basic-sdk/extension/plugins/sdoc-link/{render-elem.js → render/render-elem.js} +6 -6
- package/dist/basic-sdk/extension/plugins/sdoc-link/render/render-file-link-temp-input.js +26 -0
- package/dist/basic-sdk/extension/render/custom-element.js +6 -1
- package/dist/basic-sdk/extension/toolbar/context-toolbar/index.js +9 -1
- package/dist/basic-sdk/utils/diff.js +24 -0
- package/dist/components/doc-operations/more-operations.js +13 -10
- package/dist/components/doc-operations/revision-operations/changes-count/index.js +16 -15
- package/dist/components/doc-operations/revision-operations/index.js +1 -1
- package/dist/components/doc-operations/style.css +15 -0
- package/dist/pages/published-revision-viewer.js +1 -1
- package/dist/pages/simple-editor.js +1 -1
- package/package.json +1 -1
- package/public/locales/en/sdoc-editor.json +3 -1
- package/public/locales/zh_CN/sdoc-editor.json +3 -1
- package/dist/basic-sdk/extension/commons/history-files/index.css +0 -70
|
@@ -1,12 +1,43 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useState } from 'react';
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
2
|
import { Input } from 'reactstrap';
|
|
3
|
-
import { withTranslation } from 'react-i18next';
|
|
3
|
+
import { useTranslation, withTranslation } from 'react-i18next';
|
|
4
4
|
import Tooltip from '../../../../../components/tooltip';
|
|
5
5
|
import { ElementPopover } from '../../../commons/';
|
|
6
6
|
import { genCodeLangs } from '../prismjs';
|
|
7
7
|
import { getSelectedLangOption } from '../helpers';
|
|
8
8
|
import './index.css';
|
|
9
|
-
const
|
|
9
|
+
const LangList = _ref => {
|
|
10
|
+
let {
|
|
11
|
+
langsData,
|
|
12
|
+
onSelectLang,
|
|
13
|
+
selectedLanguageText
|
|
14
|
+
} = _ref;
|
|
15
|
+
const {
|
|
16
|
+
t
|
|
17
|
+
} = useTranslation();
|
|
18
|
+
if (!langsData.length) {
|
|
19
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
20
|
+
className: "langs-list-empty"
|
|
21
|
+
}, /*#__PURE__*/React.createElement("span", null, t('Search_not_found')));
|
|
22
|
+
}
|
|
23
|
+
return /*#__PURE__*/React.createElement("ul", {
|
|
24
|
+
className: "langs-list-ul"
|
|
25
|
+
}, langsData.map(item => {
|
|
26
|
+
return /*#__PURE__*/React.createElement("li", {
|
|
27
|
+
className: "langs-list-li ".concat(selectedLanguageText === item.text ? 'active' : ''),
|
|
28
|
+
id: item.value,
|
|
29
|
+
key: item.value,
|
|
30
|
+
onClick: () => {
|
|
31
|
+
onSelectLang(item);
|
|
32
|
+
}
|
|
33
|
+
}, item.text, /*#__PURE__*/React.createElement("span", {
|
|
34
|
+
className: "li-check-mark ".concat(selectedLanguageText === item.text ? 'li-checked' : '')
|
|
35
|
+
}, /*#__PURE__*/React.createElement("i", {
|
|
36
|
+
className: "sdocfont sdoc-check-mark icon-font"
|
|
37
|
+
})));
|
|
38
|
+
}));
|
|
39
|
+
};
|
|
40
|
+
const CodeBlockHoverMenu = _ref2 => {
|
|
10
41
|
let {
|
|
11
42
|
style,
|
|
12
43
|
language,
|
|
@@ -16,7 +47,7 @@ const CodeBlockHoverMenu = _ref => {
|
|
|
16
47
|
onCopyCodeBlock,
|
|
17
48
|
onDeleteCodeBlock,
|
|
18
49
|
t
|
|
19
|
-
} =
|
|
50
|
+
} = _ref2;
|
|
20
51
|
const {
|
|
21
52
|
white_space = 'nowrap'
|
|
22
53
|
} = style;
|
|
@@ -74,15 +105,12 @@ const CodeBlockHoverMenu = _ref => {
|
|
|
74
105
|
}, [language]);
|
|
75
106
|
const onChange = useCallback(e => {
|
|
76
107
|
const filterData = [];
|
|
77
|
-
const restData = [];
|
|
78
108
|
genCodeLangs().forEach(item => {
|
|
79
109
|
if (item.value.startsWith(e.currentTarget.value.toLowerCase())) {
|
|
80
110
|
filterData.push(item);
|
|
81
|
-
} else {
|
|
82
|
-
restData.push(item);
|
|
83
111
|
}
|
|
84
112
|
});
|
|
85
|
-
setLangsData(
|
|
113
|
+
setLangsData(filterData);
|
|
86
114
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
87
115
|
}, []);
|
|
88
116
|
return /*#__PURE__*/React.createElement(ElementPopover, null, /*#__PURE__*/React.createElement("div", {
|
|
@@ -150,21 +178,10 @@ const CodeBlockHoverMenu = _ref => {
|
|
|
150
178
|
}, /*#__PURE__*/React.createElement(Input, {
|
|
151
179
|
placeholder: t('Search_language'),
|
|
152
180
|
onChange: onChange
|
|
153
|
-
})), /*#__PURE__*/React.createElement(
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
id: item.value,
|
|
159
|
-
key: item.value,
|
|
160
|
-
onClick: () => {
|
|
161
|
-
onSelectLang(item);
|
|
162
|
-
}
|
|
163
|
-
}, item.text, /*#__PURE__*/React.createElement("span", {
|
|
164
|
-
className: "li-check-mark ".concat(selectedLanguageText === item.text ? 'li-checked' : '')
|
|
165
|
-
}, /*#__PURE__*/React.createElement("i", {
|
|
166
|
-
className: "sdocfont sdoc-check-mark icon-font"
|
|
167
|
-
})));
|
|
168
|
-
}))))));
|
|
181
|
+
})), /*#__PURE__*/React.createElement(LangList, {
|
|
182
|
+
langsData: langsData,
|
|
183
|
+
onSelectLang: onSelectLang,
|
|
184
|
+
selectedLanguageText: selectedLanguageText
|
|
185
|
+
})))));
|
|
169
186
|
};
|
|
170
187
|
export default withTranslation('sdoc-editor')(CodeBlockHoverMenu);
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
2
|
import urlJoin from 'url-join';
|
|
3
3
|
import { Editor, Range, Transforms, Path, Node } from '@seafile/slate';
|
|
4
|
+
import { ReactEditor } from '@seafile/slate-react';
|
|
4
5
|
import context from '../../../../context';
|
|
5
6
|
import EventBus from '../../../utils/event-bus';
|
|
6
|
-
import { generateEmptyElement, getNodeType, isTextNode, getParentNode, focusEditor } from '../../core';
|
|
7
|
+
import { generateEmptyElement, getNodeType, isTextNode, getParentNode, focusEditor, getSelectedElems } from '../../core';
|
|
7
8
|
import { isList } from '../../toolbar/side-toolbar/helpers';
|
|
8
9
|
import { COMMENT_EDITOR, INTERNAL_EVENT } from '../../../constants';
|
|
9
|
-
import { CODE_BLOCK, ELEMENT_TYPE, IMAGE, INSERT_POSITION } from '../../constants';
|
|
10
|
+
import { CODE_BLOCK, ELEMENT_TYPE, IMAGE, IMAGE_BLOCK, INSERT_POSITION } from '../../constants';
|
|
10
11
|
export const isInsertImageMenuDisabled = (editor, readonly) => {
|
|
11
12
|
if (readonly) return true;
|
|
12
13
|
const {
|
|
@@ -154,4 +155,27 @@ export const insertImageFiles = (files, editor, targetPath) => {
|
|
|
154
155
|
context.uploadLocalImage(files).then(fileUrl => {
|
|
155
156
|
insertImage(editor, fileUrl, targetPath, INSERT_POSITION.AFTER);
|
|
156
157
|
});
|
|
158
|
+
};
|
|
159
|
+
export const selectImageWhenSelectPartial = (event, editor, imageNode, isImageSelected) => {
|
|
160
|
+
if (isImageSelected) return;
|
|
161
|
+
const isMouseLeftDown = event.buttons === 1;
|
|
162
|
+
if (!isMouseLeftDown) return;
|
|
163
|
+
const {
|
|
164
|
+
selection
|
|
165
|
+
} = editor;
|
|
166
|
+
if (Range.isCollapsed(selection)) return;
|
|
167
|
+
let imagePath = ReactEditor.findPath(editor, imageNode);
|
|
168
|
+
if (imageNode.type === IMAGE_BLOCK) {
|
|
169
|
+
const imageIndex = imageNode.children.findIndex(item => item.type === IMAGE);
|
|
170
|
+
imagePath = imagePath.concat([imageIndex]);
|
|
171
|
+
}
|
|
172
|
+
const isIncludedSelection = Range.includes(selection, imagePath);
|
|
173
|
+
if (isIncludedSelection) return;
|
|
174
|
+
const focusRange = _objectSpread(_objectSpread({}, selection), {}, {
|
|
175
|
+
focus: {
|
|
176
|
+
offset: 0,
|
|
177
|
+
path: imagePath
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
focusEditor(editor, focusRange);
|
|
157
181
|
};
|
|
@@ -4,7 +4,7 @@ import { ReactEditor, useSelected, useReadOnly } from '@seafile/slate-react';
|
|
|
4
4
|
import { Transforms, Editor } from '@seafile/slate';
|
|
5
5
|
import classNames from 'classnames';
|
|
6
6
|
import { withTranslation } from 'react-i18next';
|
|
7
|
-
import { getImageURL, updateImage } from './helpers';
|
|
7
|
+
import { getImageURL, selectImageWhenSelectPartial, updateImage } from './helpers';
|
|
8
8
|
import EventBus from '../../../utils/event-bus';
|
|
9
9
|
import { INTERNAL_EVENT } from '../../../constants';
|
|
10
10
|
import ImageHoverMenu from './hover-menu';
|
|
@@ -195,7 +195,8 @@ const Image = _ref => {
|
|
|
195
195
|
return /*#__PURE__*/React.createElement(React.Fragment, null, isShowImagePlaceholder && /*#__PURE__*/React.createElement("span", Object.assign({
|
|
196
196
|
className: classNames('sdoc-image-wrapper', className)
|
|
197
197
|
}, attributes, {
|
|
198
|
-
style: _objectSpread({}, style)
|
|
198
|
+
style: _objectSpread({}, style),
|
|
199
|
+
onMouseOver: e => selectImageWhenSelectPartial(e, editor, element, isSelected)
|
|
199
200
|
}), /*#__PURE__*/React.createElement("img", {
|
|
200
201
|
ref: imageRef,
|
|
201
202
|
src: imagePlaceholder,
|
|
@@ -206,7 +207,8 @@ const Image = _ref => {
|
|
|
206
207
|
"data-id": element.id,
|
|
207
208
|
className: classNames('sdoc-image-wrapper', className)
|
|
208
209
|
}, attributes, {
|
|
209
|
-
style: _objectSpread({}, style)
|
|
210
|
+
style: _objectSpread({}, style),
|
|
211
|
+
onMouseOver: e => selectImageWhenSelectPartial(e, editor, element, isSelected)
|
|
210
212
|
}), /*#__PURE__*/React.createElement("span", {
|
|
211
213
|
className: "sdoc-image-inner"
|
|
212
214
|
}, /*#__PURE__*/React.createElement("span", {
|
|
@@ -294,6 +296,8 @@ export function renderImageBlock(props, editor) {
|
|
|
294
296
|
const {
|
|
295
297
|
align
|
|
296
298
|
} = element;
|
|
299
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
300
|
+
const isSelected = useSelected();
|
|
297
301
|
let justifyContent = '';
|
|
298
302
|
if (align) {
|
|
299
303
|
justifyContent = align === 'left' ? 'start' : align === 'right' ? 'end' : align;
|
|
@@ -305,5 +309,7 @@ export function renderImageBlock(props, editor) {
|
|
|
305
309
|
padding: '5px 0px',
|
|
306
310
|
justifyContent: "".concat(justifyContent)
|
|
307
311
|
}
|
|
308
|
-
}, attributes
|
|
312
|
+
}, attributes, {
|
|
313
|
+
onMouseOver: e => selectImageWhenSelectPartial(e, editor, element, isSelected)
|
|
314
|
+
}), children);
|
|
309
315
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
2
|
import { ReactEditor } from '@seafile/slate-react';
|
|
3
|
-
import { Editor, Transforms, Range, Text } from '@seafile/slate';
|
|
3
|
+
import { Editor, Transforms, Range, Text, Path, Node } from '@seafile/slate';
|
|
4
4
|
import slugid from 'slugid';
|
|
5
5
|
import copy from 'copy-to-clipboard';
|
|
6
6
|
import context from '../../../../context';
|
|
7
|
-
import { focusEditor, getNodeType, getSelectedElems } from '../../core';
|
|
8
|
-
import { SDOC_LINK, LINK, INSERT_FILE_DISPLAY_TYPE, CODE_BLOCK, CODE_LINE, PARAGRAPH } from '../../constants';
|
|
7
|
+
import { focusEditor, generateEmptyElement, getNodeType, getSelectedElems } from '../../core';
|
|
8
|
+
import { SDOC_LINK, LINK, INSERT_FILE_DISPLAY_TYPE, CODE_BLOCK, CODE_LINE, PARAGRAPH, FILE_LINK_INSET_INPUT_TEMP } from '../../constants';
|
|
9
9
|
export const isMenuDisabled = (editor, readonly) => {
|
|
10
10
|
if (readonly) return true;
|
|
11
11
|
if (editor.selection == null) return true;
|
|
@@ -149,17 +149,13 @@ export const getBeforeText = editor => {
|
|
|
149
149
|
range
|
|
150
150
|
};
|
|
151
151
|
};
|
|
152
|
-
export const
|
|
153
|
-
const {
|
|
154
|
-
selection
|
|
155
|
-
} = editor;
|
|
156
|
-
const {
|
|
157
|
-
anchor
|
|
158
|
-
} = selection;
|
|
152
|
+
export const isTriggeredByShortcut = editor => {
|
|
159
153
|
const {
|
|
160
154
|
beforeText
|
|
161
155
|
} = getBeforeText(editor);
|
|
162
|
-
|
|
156
|
+
const fileSearchInput = getFileSearchInputEntry(editor);
|
|
157
|
+
if (fileSearchInput) return false;
|
|
158
|
+
return beforeText.endsWith('[');
|
|
163
159
|
};
|
|
164
160
|
|
|
165
161
|
// If insert operation is triggered by shortcut, remove the '[[' symbol
|
|
@@ -172,8 +168,8 @@ export const removeShortCutSymbol = editor => {
|
|
|
172
168
|
beforeText,
|
|
173
169
|
range: beforeRange
|
|
174
170
|
} = getBeforeText(editor);
|
|
175
|
-
const
|
|
176
|
-
|
|
171
|
+
const isTriggeredByShortCut = beforeText.slice(-2) === '[[';
|
|
172
|
+
isTriggeredByShortCut && Transforms.delete(editor, {
|
|
177
173
|
at: {
|
|
178
174
|
anchor: {
|
|
179
175
|
path: beforeRange.focus.path,
|
|
@@ -184,4 +180,57 @@ export const removeShortCutSymbol = editor => {
|
|
|
184
180
|
voids: true
|
|
185
181
|
});
|
|
186
182
|
focusEditor(editor);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// Generate temp input for collecting file name
|
|
186
|
+
const generateFileLinkInput = () => {
|
|
187
|
+
const input = generateEmptyElement(FILE_LINK_INSET_INPUT_TEMP);
|
|
188
|
+
return input;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
// Insert temp input collecting file name
|
|
192
|
+
export const insertTempInput = editor => {
|
|
193
|
+
const {
|
|
194
|
+
selection
|
|
195
|
+
} = editor;
|
|
196
|
+
if (!Range.isCollapsed(selection)) return;
|
|
197
|
+
const tempInput = generateFileLinkInput();
|
|
198
|
+
const insertPoint = Editor.start(editor, selection);
|
|
199
|
+
Transforms.insertNodes(editor, tempInput, {
|
|
200
|
+
at: insertPoint
|
|
201
|
+
});
|
|
202
|
+
const path = Editor.path(editor, insertPoint);
|
|
203
|
+
const insertPath = Path.next(path);
|
|
204
|
+
const focusPoint = insertPath.concat(0);
|
|
205
|
+
focusEditor(editor, focusPoint);
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// Remove temp input collecting file name
|
|
209
|
+
export const removeTempInput = (editor, element) => {
|
|
210
|
+
const path = ReactEditor.findPath(editor, element);
|
|
211
|
+
Transforms.delete(editor, {
|
|
212
|
+
at: path
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
export const getFileSearchInputEntry = editor => {
|
|
216
|
+
const [searchInputNodeEntry] = Editor.nodes(editor, {
|
|
217
|
+
match: n => n.type === FILE_LINK_INSET_INPUT_TEMP
|
|
218
|
+
});
|
|
219
|
+
return searchInputNodeEntry;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Insert text when remove file name collector, such as inserting 'filename' into prevNode when close collector entered '[[filename'
|
|
223
|
+
export const insertTextWhenRemoveFileNameCollector = (editor, searchInputNode) => {
|
|
224
|
+
const inputNodePath = ReactEditor.findPath(editor, searchInputNode);
|
|
225
|
+
if (!inputNodePath) return;
|
|
226
|
+
const prevNodeEntry = Editor.previous(editor, {
|
|
227
|
+
at: inputNodePath
|
|
228
|
+
});
|
|
229
|
+
if (!prevNodeEntry) return;
|
|
230
|
+
const searchContent = Node.string(searchInputNode);
|
|
231
|
+
const insertPoint = Editor.end(editor, prevNodeEntry[1]);
|
|
232
|
+
Transforms.insertText(editor, searchContent, {
|
|
233
|
+
at: insertPoint
|
|
234
|
+
});
|
|
235
|
+
removeTempInput(editor, searchInputNode);
|
|
187
236
|
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { SDOC_LINK } from '../../constants';
|
|
2
2
|
import SdocLinkMenu from './menu';
|
|
3
3
|
import withSdocLink from './plugin';
|
|
4
|
-
import renderSdocLink from './render-elem';
|
|
4
|
+
import renderSdocLink from './render/render-elem';
|
|
5
|
+
import renderFileLinkTempInput from './render/render-file-link-temp-input';
|
|
5
6
|
const SdocLinkPlugin = {
|
|
6
7
|
type: SDOC_LINK,
|
|
7
8
|
editorMenus: [SdocLinkMenu],
|
|
8
9
|
editorPlugin: withSdocLink,
|
|
9
|
-
renderElements: [renderSdocLink]
|
|
10
|
+
renderElements: [renderSdocLink, renderFileLinkTempInput]
|
|
10
11
|
};
|
|
11
12
|
export default SdocLinkPlugin;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { Transforms, Node, Editor } from '@seafile/slate';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { ReactEditor } from '@seafile/slate-react';
|
|
3
|
+
import { FILE_LINK_INSET_INPUT_TEMP, SDOC_LINK } from '../../constants';
|
|
4
|
+
import { getFileSearchInputEntry, insertTempInput, isTriggeredByShortcut } from './helpers';
|
|
5
|
+
import { getSelectedElems } from '../../core';
|
|
6
6
|
const withSdocLink = editor => {
|
|
7
7
|
const {
|
|
8
8
|
isInline,
|
|
9
9
|
deleteBackward,
|
|
10
|
-
|
|
10
|
+
insertText,
|
|
11
|
+
onCompositionStart
|
|
11
12
|
} = editor;
|
|
12
13
|
const newEditor = editor;
|
|
13
14
|
|
|
@@ -16,9 +17,8 @@ const withSdocLink = editor => {
|
|
|
16
17
|
const {
|
|
17
18
|
type
|
|
18
19
|
} = elem;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
20
|
+
const isInlineElem = [SDOC_LINK, FILE_LINK_INSET_INPUT_TEMP].includes(type);
|
|
21
|
+
if (isInlineElem) return true;
|
|
22
22
|
return isInline(elem);
|
|
23
23
|
};
|
|
24
24
|
newEditor.deleteBackward = unit => {
|
|
@@ -29,13 +29,21 @@ const withSdocLink = editor => {
|
|
|
29
29
|
return deleteBackward(unit);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
// Delete file link node
|
|
32
|
+
// Delete file link node when the input is empty
|
|
33
|
+
const selectedElems = getSelectedElems(newEditor);
|
|
34
|
+
const fileLinkSearchInputNode = selectedElems.find(elem => elem.type === FILE_LINK_INSET_INPUT_TEMP);
|
|
35
|
+
if (fileLinkSearchInputNode) {
|
|
36
|
+
const path = ReactEditor.findPath(editor, fileLinkSearchInputNode);
|
|
37
|
+
if (Node.string(fileLinkSearchInputNode).length === 0) return Transforms.delete(newEditor, {
|
|
38
|
+
at: path
|
|
39
|
+
});
|
|
40
|
+
}
|
|
33
41
|
const nodeEntry = Editor.node(newEditor, newEditor.selection);
|
|
34
42
|
if (nodeEntry && Node.string(nodeEntry[0]).length === 0) {
|
|
35
43
|
const beforePath = nodeEntry[1];
|
|
36
44
|
beforePath.splice(-1, 1, Math.max(nodeEntry[1].at(-1) - 1, 0));
|
|
37
45
|
const beforeNodeEntry = Editor.node(newEditor, beforePath);
|
|
38
|
-
if (beforeNodeEntry && beforeNodeEntry[0].type
|
|
46
|
+
if (beforeNodeEntry && [SDOC_LINK, FILE_LINK_INSET_INPUT_TEMP].includes(beforeNodeEntry[0].type)) {
|
|
39
47
|
Transforms.delete(newEditor, {
|
|
40
48
|
at: beforeNodeEntry[1]
|
|
41
49
|
});
|
|
@@ -45,21 +53,23 @@ const withSdocLink = editor => {
|
|
|
45
53
|
}
|
|
46
54
|
return deleteBackward(unit);
|
|
47
55
|
};
|
|
48
|
-
newEditor.
|
|
49
|
-
|
|
50
|
-
key
|
|
51
|
-
} = event;
|
|
52
|
-
if (key !== '[') return onHotKeyDown && onHotKeyDown(event);
|
|
56
|
+
newEditor.insertText = text => {
|
|
57
|
+
if (text !== '[') return insertText(text);
|
|
53
58
|
// If user press '[[', open file modal
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
if (isTriggeredByShortcut(newEditor)) {
|
|
60
|
+
insertText(text);
|
|
61
|
+
insertTempInput(newEditor);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
return insertText(text);
|
|
65
|
+
};
|
|
66
|
+
newEditor.onCompositionStart = event => {
|
|
67
|
+
const fileSearchInputNodeEntry = getFileSearchInputEntry(newEditor);
|
|
68
|
+
if (fileSearchInputNodeEntry) {
|
|
69
|
+
event.preventDefault();
|
|
70
|
+
return true;
|
|
61
71
|
}
|
|
62
|
-
return
|
|
72
|
+
return onCompositionStart && onCompositionStart(event);
|
|
63
73
|
};
|
|
64
74
|
return newEditor;
|
|
65
75
|
};
|
package/dist/basic-sdk/extension/plugins/sdoc-link/{render-elem.css → render/render-elem.css}
RENAMED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
.sdoc-file-card-link .sdoc-file-link-icon :first-child {
|
|
23
|
-
|
|
23
|
+
font-size: 24px;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
.sdoc-file-card-link .sdoc-file-link-icon {
|
|
@@ -39,3 +39,7 @@
|
|
|
39
39
|
text-decoration: none;
|
|
40
40
|
color: #333;
|
|
41
41
|
}
|
|
42
|
+
|
|
43
|
+
.sdoc-file-name-insert-collector {
|
|
44
|
+
padding: 0 .25em;
|
|
45
|
+
}
|
|
@@ -2,12 +2,12 @@ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
|
2
2
|
import React, { useCallback, useEffect, useState, useRef } from 'react';
|
|
3
3
|
import { Editor, Range } from '@seafile/slate';
|
|
4
4
|
import { ReactEditor, useReadOnly } from '@seafile/slate-react';
|
|
5
|
-
import { useScrollContext } from '
|
|
6
|
-
import { unwrapLinkNode, getUrl } from '
|
|
7
|
-
import HoverMenu from '
|
|
8
|
-
import { DELETED_STYLE, ADDED_STYLE } from '
|
|
9
|
-
import { SDOC_LINK_TYPE } from '
|
|
10
|
-
import { focusEditor } from '
|
|
5
|
+
import { useScrollContext } from '../../../../hooks/use-scroll-context';
|
|
6
|
+
import { unwrapLinkNode, getUrl } from '../helpers';
|
|
7
|
+
import HoverMenu from '../hover-menu';
|
|
8
|
+
import { DELETED_STYLE, ADDED_STYLE } from '../../../constants';
|
|
9
|
+
import { SDOC_LINK_TYPE } from '../constants';
|
|
10
|
+
import { focusEditor } from '../../../core';
|
|
11
11
|
import './render-elem.css';
|
|
12
12
|
const SdocFileLink = _ref => {
|
|
13
13
|
let {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import EventBus from '../../../../utils/event-bus';
|
|
3
|
+
import { INTERNAL_EVENT } from '../../../../constants';
|
|
4
|
+
import { FILE_LINK_INSET_INPUT_TEMP } from '../../../constants';
|
|
5
|
+
import './render-elem.css';
|
|
6
|
+
const RenderFileLinkTempInput = _ref => {
|
|
7
|
+
let {
|
|
8
|
+
element,
|
|
9
|
+
attributes,
|
|
10
|
+
children
|
|
11
|
+
} = _ref;
|
|
12
|
+
const eventBus = EventBus.getInstance();
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
eventBus.dispatch(INTERNAL_EVENT.INSERT_ELEMENT, {
|
|
15
|
+
type: FILE_LINK_INSET_INPUT_TEMP,
|
|
16
|
+
slateNode: element
|
|
17
|
+
});
|
|
18
|
+
return () => {
|
|
19
|
+
eventBus.dispatch(INTERNAL_EVENT.CLOSE_FILE_INSET_DIALOG);
|
|
20
|
+
};
|
|
21
|
+
}, [element, eventBus]);
|
|
22
|
+
return /*#__PURE__*/React.createElement("span", Object.assign({}, attributes, {
|
|
23
|
+
className: "sdoc-file-name-insert-collector"
|
|
24
|
+
}), children);
|
|
25
|
+
};
|
|
26
|
+
export default RenderFileLinkTempInput;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
2
|
import { useReadOnly, useSlateStatic } from '@seafile/slate-react';
|
|
3
|
-
import { BLOCKQUOTE, LINK, CHECK_LIST_ITEM, HEADER1, HEADER2, HEADER3, HEADER4, HEADER5, HEADER6, LIST_ITEM, ORDERED_LIST, PARAGRAPH, UNORDERED_LIST, CODE_BLOCK, CODE_LINE, IMAGE, IMAGE_BLOCK, ELEMENT_TYPE, SDOC_LINK, FILE_LINK, TITLE, SUBTITLE, CALL_OUT, SUPPORTED_SIDE_OPERATION_TYPE, MENTION, MENTION_TEMP } from '../constants';
|
|
3
|
+
import { BLOCKQUOTE, LINK, CHECK_LIST_ITEM, HEADER1, HEADER2, HEADER3, HEADER4, HEADER5, HEADER6, LIST_ITEM, ORDERED_LIST, PARAGRAPH, UNORDERED_LIST, CODE_BLOCK, CODE_LINE, IMAGE, IMAGE_BLOCK, ELEMENT_TYPE, SDOC_LINK, FILE_LINK, TITLE, SUBTITLE, CALL_OUT, SUPPORTED_SIDE_OPERATION_TYPE, MENTION, MENTION_TEMP, FILE_LINK_INSET_INPUT_TEMP } from '../constants';
|
|
4
4
|
import { BlockquotePlugin, LinkPlugin, CheckListPlugin, HeaderPlugin, ListPlugin, CodeBlockPlugin, ImagePlugin, TablePlugin, SdocLinkPlugin, ParagraphPlugin, FileLinkPlugin, CalloutPlugin, MentionPlugin } from '../plugins';
|
|
5
5
|
import { onDragOver, onDragLeave, onDrop } from '../toolbar/side-toolbar/event';
|
|
6
6
|
import { getParentNode } from '../core';
|
|
@@ -134,6 +134,11 @@ const CustomRenderElement = props => {
|
|
|
134
134
|
const [renderFileLink] = FileLinkPlugin.renderElements;
|
|
135
135
|
return renderFileLink(props, editor);
|
|
136
136
|
}
|
|
137
|
+
case FILE_LINK_INSET_INPUT_TEMP:
|
|
138
|
+
{
|
|
139
|
+
const [, renderFileLinkFileSearchInput] = SdocLinkPlugin.renderElements;
|
|
140
|
+
return renderFileLinkFileSearchInput(props, editor);
|
|
141
|
+
}
|
|
137
142
|
case CALL_OUT:
|
|
138
143
|
{
|
|
139
144
|
const [renderCallout] = CalloutPlugin.renderElements;
|
|
@@ -47,10 +47,18 @@ const ContextToolbar = () => {
|
|
|
47
47
|
const onMouseDown = useCallback(event => {
|
|
48
48
|
event.preventDefault(); // prevent toolbar from taking focus away from editor
|
|
49
49
|
}, []);
|
|
50
|
+
const onMouseMove = useCallback(e => {
|
|
51
|
+
const isMouseLeftDown = e.buttons === 1;
|
|
52
|
+
if (isMouseLeftDown) {
|
|
53
|
+
const el = ref.current;
|
|
54
|
+
el.removeAttribute('style');
|
|
55
|
+
}
|
|
56
|
+
}, []);
|
|
50
57
|
return createPortal( /*#__PURE__*/React.createElement("div", {
|
|
51
58
|
ref: ref,
|
|
52
59
|
className: "sdoc-context-toolbar",
|
|
53
|
-
onMouseDown: onMouseDown
|
|
60
|
+
onMouseDown: onMouseDown,
|
|
61
|
+
onMouseOver: onMouseMove
|
|
54
62
|
}, /*#__PURE__*/React.createElement(MenuGroup, null, /*#__PURE__*/React.createElement(TextStyleMenuList, {
|
|
55
63
|
editor: editor,
|
|
56
64
|
idPrefix: 'sdoc_context_toolbar'
|
|
@@ -37,6 +37,30 @@ export const getTopLevelChanges = changes => {
|
|
|
37
37
|
return Array.from(new Set(topLevelChanges));
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
+
// Merge consecutive added areas or deleted areas
|
|
41
|
+
export const getMergedChanges = (topLevelChanges, diffValue) => {
|
|
42
|
+
const topLevelChangesValue = [];
|
|
43
|
+
const changes = [];
|
|
44
|
+
diffValue.forEach(item => {
|
|
45
|
+
if (topLevelChanges.includes(item.id)) {
|
|
46
|
+
const obj = {
|
|
47
|
+
id: item.id,
|
|
48
|
+
value: item
|
|
49
|
+
};
|
|
50
|
+
topLevelChangesValue.push(obj);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
topLevelChangesValue.forEach(item => {
|
|
54
|
+
var _changes;
|
|
55
|
+
const preChange = (_changes = changes[changes.length - 1]) === null || _changes === void 0 ? void 0 : _changes.value;
|
|
56
|
+
const curChange = item.value;
|
|
57
|
+
if ((curChange === null || curChange === void 0 ? void 0 : curChange.add) && (preChange === null || preChange === void 0 ? void 0 : preChange.add)) return;
|
|
58
|
+
if ((curChange === null || curChange === void 0 ? void 0 : curChange.delete) && (preChange === null || preChange === void 0 ? void 0 : preChange.delete)) return;
|
|
59
|
+
changes.push(item);
|
|
60
|
+
});
|
|
61
|
+
return changes.map(item => item.id);
|
|
62
|
+
};
|
|
63
|
+
|
|
40
64
|
// Depth facilitates each child node, adding diffType to each end node
|
|
41
65
|
const generatorDiffElement = function (element, diffType) {
|
|
42
66
|
let style = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
@@ -62,6 +62,7 @@ const MoreOperations = _ref => {
|
|
|
62
62
|
return printTexts;
|
|
63
63
|
}, []);
|
|
64
64
|
return /*#__PURE__*/React.createElement(Dropdown, {
|
|
65
|
+
className: "sdoc-operator-folder",
|
|
65
66
|
isOpen: isDropdownOpen,
|
|
66
67
|
toggle: () => toggleDropdown(isDropdownOpen)
|
|
67
68
|
}, /*#__PURE__*/React.createElement(DropdownToggle, {
|
|
@@ -72,26 +73,28 @@ const MoreOperations = _ref => {
|
|
|
72
73
|
})), /*#__PURE__*/React.createElement(DropdownMenu, {
|
|
73
74
|
className: "sdoc-dropdown-menu",
|
|
74
75
|
right: true
|
|
75
|
-
},
|
|
76
|
-
className: "sdoc-dropdown-menu-item",
|
|
77
|
-
tag: "a",
|
|
78
|
-
href: parentFolderURL
|
|
79
|
-
}, t('Open_parent_folder')), isPro && isFreezed && /*#__PURE__*/React.createElement(DropdownItem, {
|
|
80
|
-
className: "sdoc-dropdown-menu-item",
|
|
81
|
-
onClick: unFreeze
|
|
82
|
-
}, t('Unfreeze')), /*#__PURE__*/React.createElement(DropdownItem, {
|
|
76
|
+
}, /*#__PURE__*/React.createElement(DropdownItem, {
|
|
83
77
|
className: "sdoc-dropdown-menu-item",
|
|
84
78
|
onClick: handlePrint
|
|
85
79
|
}, /*#__PURE__*/React.createElement("div", {
|
|
86
80
|
className: "sdoc-dropdown-print-container"
|
|
87
81
|
}, /*#__PURE__*/React.createElement("div", null, t('Print')), /*#__PURE__*/React.createElement(MenuShortcutPrompt, {
|
|
88
82
|
shortcuts: printShortCutTexts
|
|
89
|
-
}))), isPro &&
|
|
83
|
+
}))), isPro && isFreezed && /*#__PURE__*/React.createElement(DropdownItem, {
|
|
84
|
+
className: "sdoc-dropdown-menu-item",
|
|
85
|
+
onClick: unFreeze
|
|
86
|
+
}, t('Unfreeze')), isPro && !isFreezed && /*#__PURE__*/React.createElement(DropdownItem, {
|
|
90
87
|
className: "sdoc-dropdown-menu-item",
|
|
91
88
|
onClick: onFreezeDocument
|
|
92
89
|
}, t('Freeze_document')), /*#__PURE__*/React.createElement(DropdownItem, {
|
|
93
90
|
className: "sdoc-dropdown-menu-item",
|
|
94
91
|
onClick: handleClickHistory
|
|
95
|
-
}, t('Document_history'))
|
|
92
|
+
}, t('Document_history')), parentFolderURL && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
|
93
|
+
className: "sdoc-operator-folder-divider"
|
|
94
|
+
}), /*#__PURE__*/React.createElement(DropdownItem, {
|
|
95
|
+
className: "sdoc-dropdown-menu-item",
|
|
96
|
+
tag: "a",
|
|
97
|
+
href: parentFolderURL
|
|
98
|
+
}, t('Open_parent_folder')))));
|
|
96
99
|
};
|
|
97
100
|
export default withTranslation('sdoc-editor')(MoreOperations);
|