@seafile/sdoc-editor 0.5.46 → 0.5.48
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/assets/css/sdoc-editor-plugins.css +2 -1
- package/dist/basic-sdk/extension/plugins/code-block/helpers.js +1 -1
- package/dist/basic-sdk/extension/plugins/code-block/plugin.js +21 -2
- package/dist/basic-sdk/extension/plugins/file-link/helpers.js +0 -8
- package/dist/basic-sdk/extension/plugins/html/rules/text.js +4 -1
- package/dist/basic-sdk/extension/plugins/image/helpers.js +24 -1
- package/dist/basic-sdk/extension/plugins/image/render-elem.js +5 -1
- package/dist/basic-sdk/extension/plugins/mention/helper.js +12 -2
- package/dist/basic-sdk/extension/plugins/sdoc-link/helpers.js +0 -7
- package/dist/basic-sdk/outline/style.css +3 -4
- package/dist/context.js +4 -1
- package/dist/utils/base64-to-unit8array.js +15 -0
- package/package.json +2 -2
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
.sdoc-editor-container .article .sdoc-checkbox-container .sdoc-checkbox-input-wrapper .sdoc-checkbox-content-container {
|
|
51
|
-
word-break:normal;
|
|
51
|
+
word-break: normal;
|
|
52
52
|
width: calc(100% - 1em);
|
|
53
53
|
}
|
|
54
54
|
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
position: relative;
|
|
58
58
|
display: inline-block;
|
|
59
59
|
padding: 6px 6px 6px 0;
|
|
60
|
+
margin: 0 0.15em;
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
.sdoc-editor-container .article .sdoc-image-inner {
|
|
@@ -17,7 +17,7 @@ export const isMenuDisabled = (editor, readonly) => {
|
|
|
17
17
|
if (hasVoid) return true;
|
|
18
18
|
const isMatch = selectedElems.some(elem => {
|
|
19
19
|
const type = getNodeType(elem);
|
|
20
|
-
if (type ===
|
|
20
|
+
if (type === PARAGRAPH) return true;
|
|
21
21
|
return false;
|
|
22
22
|
});
|
|
23
23
|
if (isMatch) return false; // enable
|
|
@@ -2,7 +2,8 @@ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
|
2
2
|
import slugid from 'slugid';
|
|
3
3
|
import isHotkey from 'is-hotkey';
|
|
4
4
|
import { Transforms, Node, Range, Editor } from '@seafile/slate';
|
|
5
|
-
import {
|
|
5
|
+
import { ReactEditor } from '@seafile/slate-react';
|
|
6
|
+
import { getNodeType, isLastNode, getSelectedNodeByType, generateEmptyElement, isSelectionAtBlockStart, getSelectedElems } from '../../core';
|
|
6
7
|
import { deleteBackwardByLength } from './helpers';
|
|
7
8
|
import { CODE_BLOCK, PARAGRAPH, CODE_LINE, BLOCKQUOTE } from '../../constants';
|
|
8
9
|
const withCodeBlock = editor => {
|
|
@@ -168,7 +169,25 @@ const withCodeBlock = editor => {
|
|
|
168
169
|
}
|
|
169
170
|
}
|
|
170
171
|
if (isHotkey('tab', event)) {
|
|
171
|
-
|
|
172
|
+
const {
|
|
173
|
+
selection
|
|
174
|
+
} = newEditor;
|
|
175
|
+
event.preventDefault();
|
|
176
|
+
// By default, tab key will insert 4 spaces
|
|
177
|
+
const indent = ' '.repeat(4);
|
|
178
|
+
if (Range.isCollapsed(selection)) {
|
|
179
|
+
newEditor.insertText(indent);
|
|
180
|
+
} else {
|
|
181
|
+
const selectedElements = getSelectedElems(newEditor);
|
|
182
|
+
selectedElements.forEach(elem => {
|
|
183
|
+
if (elem.type !== CODE_LINE) return;
|
|
184
|
+
const text = indent + Node.string(elem);
|
|
185
|
+
const insertPoint = ReactEditor.findPath(newEditor, elem);
|
|
186
|
+
Transforms.insertText(editor, text, {
|
|
187
|
+
at: insertPoint
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
}
|
|
172
191
|
}
|
|
173
192
|
if (isHotkey('shift+tab', event)) {
|
|
174
193
|
const range = {
|
|
@@ -53,16 +53,8 @@ export const insertFileLink = (editor, text, uuid) => {
|
|
|
53
53
|
if (selection == null) return;
|
|
54
54
|
const isCollapsed = Range.isCollapsed(selection);
|
|
55
55
|
if (isCollapsed) {
|
|
56
|
-
// Insert Spaces before and after filelinks for easy operation
|
|
57
|
-
editor.insertText(' ');
|
|
58
56
|
const fileNode = generateFileNode(uuid, text);
|
|
59
57
|
Transforms.insertNodes(editor, fileNode);
|
|
60
|
-
|
|
61
|
-
// Not being able to use insertText directly causes the added Spaces to be added to the linked text, as in the issue above, replaced by insertFragment
|
|
62
|
-
editor.insertFragment([{
|
|
63
|
-
id: slugid.nice(),
|
|
64
|
-
text: ' '
|
|
65
|
-
}]);
|
|
66
58
|
} else {
|
|
67
59
|
const selectedText = Editor.string(editor, selection); // Selected text
|
|
68
60
|
if (selectedText !== text) {
|
|
@@ -2,8 +2,11 @@ import slugid from 'slugid';
|
|
|
2
2
|
const textRule = (element, parseChild) => {
|
|
3
3
|
const {
|
|
4
4
|
nodeName,
|
|
5
|
-
nodeType
|
|
5
|
+
nodeType,
|
|
6
|
+
childNodes
|
|
6
7
|
} = element;
|
|
8
|
+
// If the child node is not a text node, it is processed by the child node
|
|
9
|
+
if (childNodes.length && !((childNodes === null || childNodes === void 0 ? void 0 : childNodes[0]) instanceof Text)) return parseChild(childNodes);
|
|
7
10
|
if (nodeName === 'SPAN') {
|
|
8
11
|
return {
|
|
9
12
|
id: slugid.nice(),
|
|
@@ -2,12 +2,14 @@ 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
4
|
import { ReactEditor } from '@seafile/slate-react';
|
|
5
|
+
import slugId from 'slugid';
|
|
5
6
|
import context from '../../../../context';
|
|
6
7
|
import EventBus from '../../../utils/event-bus';
|
|
7
|
-
import { generateEmptyElement, getNodeType, isTextNode, getParentNode, focusEditor
|
|
8
|
+
import { generateEmptyElement, getNodeType, isTextNode, getParentNode, focusEditor } from '../../core';
|
|
8
9
|
import { isList } from '../../toolbar/side-toolbar/helpers';
|
|
9
10
|
import { COMMENT_EDITOR, INTERNAL_EVENT } from '../../../constants';
|
|
10
11
|
import { CODE_BLOCK, ELEMENT_TYPE, IMAGE, IMAGE_BLOCK, INSERT_POSITION } from '../../constants';
|
|
12
|
+
import base64ToUnit8Array from '../../../../utils/base64-to-unit8array';
|
|
11
13
|
export const isInsertImageMenuDisabled = (editor, readonly) => {
|
|
12
14
|
if (readonly) return true;
|
|
13
15
|
const {
|
|
@@ -178,4 +180,25 @@ export const selectImageWhenSelectPartial = (event, editor, imageNode, isImageSe
|
|
|
178
180
|
}
|
|
179
181
|
});
|
|
180
182
|
focusEditor(editor, focusRange);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// Upload image when the image is pasted from the clipboard in base64
|
|
186
|
+
export const handleBase64Image = (editor, path, imgData) => {
|
|
187
|
+
const unit8Array = base64ToUnit8Array(imgData.src);
|
|
188
|
+
const blob = new Blob([unit8Array.u8arr], {
|
|
189
|
+
type: unit8Array.mime
|
|
190
|
+
});
|
|
191
|
+
const file = new File([blob], "".concat(slugId.nice(), ".jpg"), {
|
|
192
|
+
type: unit8Array.mime
|
|
193
|
+
});
|
|
194
|
+
context.uploadLocalImage([file]).then(res => {
|
|
195
|
+
const _data = _objectSpread(_objectSpread({}, imgData), {}, {
|
|
196
|
+
src: res[0]
|
|
197
|
+
});
|
|
198
|
+
Transforms.setNodes(editor, {
|
|
199
|
+
data: _data
|
|
200
|
+
}, {
|
|
201
|
+
at: path
|
|
202
|
+
});
|
|
203
|
+
});
|
|
181
204
|
};
|
|
@@ -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, selectImageWhenSelectPartial, updateImage } from './helpers';
|
|
7
|
+
import { getImageURL, handleBase64Image, 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';
|
|
@@ -171,6 +171,10 @@ const Image = _ref => {
|
|
|
171
171
|
}
|
|
172
172
|
}, [data.src]);
|
|
173
173
|
const onImageLoadError = useCallback(() => {
|
|
174
|
+
// Check is due to the image is pasted from the clipboard in base64
|
|
175
|
+
if (data.src.startsWith('data:image/jpeg;base64')) {
|
|
176
|
+
return handleBase64Image(editor, path, data);
|
|
177
|
+
}
|
|
174
178
|
setIsShowImagePlaceholder(true);
|
|
175
179
|
// External network images do not reload after failure to load
|
|
176
180
|
if (!data.src.startsWith('http')) {
|
|
@@ -92,14 +92,24 @@ export const insertMention = (editor, collaborator) => {
|
|
|
92
92
|
export const sortCollaborators = function (collaborators) {
|
|
93
93
|
let participants = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
94
94
|
const loginEmail = context.getUserInfo().email;
|
|
95
|
+
const lastModifyUser = context.getSetting('last_modify_user');
|
|
96
|
+
let stickyCollaborator = null;
|
|
95
97
|
const participantsMap = {};
|
|
96
98
|
participants.forEach(item => {
|
|
97
99
|
if (item.email === loginEmail) return;
|
|
98
100
|
participantsMap[item.email] = item;
|
|
99
101
|
});
|
|
100
|
-
const newCollaborators = collaborators.filter(item =>
|
|
102
|
+
const newCollaborators = collaborators.filter(item => {
|
|
103
|
+
const isValidCollaborator = !participantsMap[item.email] && item.email !== loginEmail;
|
|
104
|
+
if (isValidCollaborator && lastModifyUser === item.email) {
|
|
105
|
+
stickyCollaborator = item;
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
return isValidCollaborator;
|
|
109
|
+
});
|
|
101
110
|
const newParticipants = Object.values(participantsMap);
|
|
102
|
-
|
|
111
|
+
const resCollaborators = stickyCollaborator ? [stickyCollaborator, ...newParticipants, ...newCollaborators] : [...newParticipants, ...newCollaborators];
|
|
112
|
+
return resCollaborators;
|
|
103
113
|
};
|
|
104
114
|
export const transformToText = function (editor) {
|
|
105
115
|
let isFocusEnd = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
@@ -60,14 +60,7 @@ export const insertSdocFileLink = (editor, text, uuid) => {
|
|
|
60
60
|
removeShortCutSymbol(editor);
|
|
61
61
|
const sdocFileNode = generateSdocFileNode(uuid, text);
|
|
62
62
|
if (isCollapsed) {
|
|
63
|
-
// Insert Spaces before and after sdoclinks for easy operation
|
|
64
|
-
editor.insertText(' ');
|
|
65
63
|
Transforms.insertNodes(editor, sdocFileNode);
|
|
66
|
-
// Not being able to use insertText directly causes the added Spaces to be added to the linked text, as in the issue above, replaced by insertFragment
|
|
67
|
-
editor.insertFragment([{
|
|
68
|
-
id: slugid.nice(),
|
|
69
|
-
text: ' '
|
|
70
|
-
}]);
|
|
71
64
|
} else {
|
|
72
65
|
const selectedText = Editor.string(editor, selection); // Selected text
|
|
73
66
|
if (selectedText !== text) {
|
|
@@ -53,16 +53,15 @@
|
|
|
53
53
|
flex: 1;
|
|
54
54
|
display: flex;
|
|
55
55
|
flex-direction: column;
|
|
56
|
+
word-break: break-all;
|
|
56
57
|
overflow-x: hidden;
|
|
57
|
-
overflow-y: hidden;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.sdoc-outline-list-container:hover {
|
|
61
58
|
overflow-y: auto;
|
|
62
59
|
}
|
|
63
60
|
|
|
64
61
|
.sdoc-outline-item {
|
|
65
62
|
padding: 4px 0;
|
|
63
|
+
padding-right: 6px;
|
|
64
|
+
overflow-wrap: anywhere;
|
|
66
65
|
cursor: pointer;
|
|
67
66
|
}
|
|
68
67
|
|
package/dist/context.js
CHANGED
|
@@ -97,7 +97,10 @@ class Context {
|
|
|
97
97
|
return this.config;
|
|
98
98
|
}
|
|
99
99
|
getFileContent() {
|
|
100
|
-
return this.sdocServerApi.getDocContent()
|
|
100
|
+
return this.sdocServerApi.getDocContent().then(res => {
|
|
101
|
+
this.settings['last_modify_user'] = res.data.last_modify_user;
|
|
102
|
+
return res;
|
|
103
|
+
});
|
|
101
104
|
}
|
|
102
105
|
normalizeSdocContent() {
|
|
103
106
|
return this.sdocServerApi.normalizeSdocContent();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const base64ToUnit8Array = base64 => {
|
|
2
|
+
const arr = base64.split(',');
|
|
3
|
+
const mime = arr[0].match(/:(.*?);/)[1];
|
|
4
|
+
const bstr = atob(arr[1]);
|
|
5
|
+
let n = bstr.length;
|
|
6
|
+
const u8arr = new Uint8Array(n);
|
|
7
|
+
while (n--) {
|
|
8
|
+
u8arr[n] = bstr.charCodeAt(n);
|
|
9
|
+
}
|
|
10
|
+
return {
|
|
11
|
+
u8arr,
|
|
12
|
+
mime
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export default base64ToUnit8Array;
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seafile/sdoc-editor",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.48",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "This is a sdoc editor",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@seafile/print-js": "1.6.
|
|
8
|
+
"@seafile/print-js": "1.6.5",
|
|
9
9
|
"@seafile/react-image-lightbox": "2.0.4",
|
|
10
10
|
"@seafile/slate": "0.91.8",
|
|
11
11
|
"@seafile/slate-history": "0.86.2",
|