@seafile/sdoc-editor 0.5.47 → 0.5.49

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.
@@ -28,7 +28,7 @@
28
28
  padding-left: 1.2em !important;
29
29
  }
30
30
 
31
- .sdoc-editor-container .article .list-container .sdoc-li-blod::marker {
31
+ .sdoc-editor-container .article .list-container .sdoc-li-bold::marker {
32
32
  font-weight: bold;
33
33
  }
34
34
 
@@ -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 {
@@ -71,7 +71,7 @@ const CommentItem = _ref => {
71
71
  updateCommentResolved(false);
72
72
  }, [updateCommentResolved]);
73
73
  const menuId = useMemo(() => "comment_".concat(comment.id), [comment]);
74
- return /*#__PURE__*/React.createElement("li", {
74
+ return /*#__PURE__*/React.createElement("div", {
75
75
  className: "comment-item"
76
76
  }, /*#__PURE__*/React.createElement("div", {
77
77
  className: "comment-header"
@@ -20,7 +20,7 @@ const CommentItemReply = _ref => {
20
20
  const {
21
21
  notificationsInfo
22
22
  } = useNotificationContext();
23
- const liRef = useRef(null);
23
+ const itemRef = useRef(null);
24
24
  const isUnseen = notificationsInfo.notifications_map["sdoc_notification_".concat(reply.comment_id, "_").concat(reply.id)] ? true : false;
25
25
  const [isEditing, setIsEditing] = useState(false);
26
26
  const [editorContent, setEditorContent] = useState('');
@@ -36,7 +36,8 @@ const CommentItemReply = _ref => {
36
36
  }, []);
37
37
  const transferHtml = async mdString => {
38
38
  const htmlString = await processor.process(mdString);
39
- setEditorContent(String(htmlString));
39
+ const formatHtml = String(htmlString).replace(/\n */g, '');
40
+ setEditorContent(formatHtml);
40
41
  };
41
42
  useEffect(() => {
42
43
  transferHtml(reply.reply);
@@ -57,9 +58,9 @@ const CommentItemReply = _ref => {
57
58
  setIsEditing(false);
58
59
  }, [reply, updateReply]);
59
60
  const user = context.getUserInfo();
60
- return /*#__PURE__*/React.createElement("li", {
61
+ return /*#__PURE__*/React.createElement("div", {
61
62
  className: "comment-item",
62
- ref: liRef
63
+ ref: itemRef
63
64
  }, /*#__PURE__*/React.createElement("div", {
64
65
  className: "comment-header"
65
66
  }, /*#__PURE__*/React.createElement("div", {
@@ -112,7 +113,7 @@ const CommentItemReply = _ref => {
112
113
  updateContent: updateContent,
113
114
  setIsEditing: setIsEditing
114
115
  }), isShowDeleteDialog && isActive && /*#__PURE__*/React.createElement(CommentDeletePopover, {
115
- parentDom: liRef.current,
116
+ parentDom: itemRef.current,
116
117
  type: "reply",
117
118
  deleteConfirm: _deleteReply,
118
119
  setIsShowDeleteModal: setIsShowDeleteDialog,
@@ -6,7 +6,7 @@ const CommentItemResolvedReply = _ref => {
6
6
  reply,
7
7
  t
8
8
  } = _ref;
9
- return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("li", {
9
+ return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", {
10
10
  className: "comment-item"
11
11
  }, /*#__PURE__*/React.createElement("div", {
12
12
  className: "comment-header"
@@ -244,7 +244,7 @@ const CommentItemWrapper = _ref => {
244
244
  className: "sdocfont sdoc-comment-quote mr-2"
245
245
  }), /*#__PURE__*/React.createElement("div", {
246
246
  className: "comment-item-selected-text"
247
- }, Node.string(element))), /*#__PURE__*/React.createElement("ul", {
247
+ }, Node.string(element))), /*#__PURE__*/React.createElement("div", {
248
248
  ref: listRef,
249
249
  className: "comment-item-list"
250
250
  }, /*#__PURE__*/React.createElement(CommentItemContent, {
@@ -3,7 +3,7 @@
3
3
  margin-top: 5px;
4
4
  }
5
5
 
6
- .sdoc-comment-list-container .article.sdoc-comment-editor {
6
+ .sdoc-comment-list-container .article.sdoc-comment-editor {
7
7
  font-size: 14px;
8
8
  }
9
9
 
@@ -57,12 +57,11 @@
57
57
  overflow-y: auto;
58
58
  margin: 0;
59
59
  padding: 0;
60
- list-style: none;
61
60
  }
62
61
 
63
62
  .sdoc-comment-list-container .comment-item {
64
63
  position: relative;
65
- padding: 16px 10px 0;
64
+ padding: 16px 16px 0;
66
65
  cursor: pointer;
67
66
  }
68
67
 
@@ -369,3 +368,11 @@
369
368
  .sdoc-article-container .sdoc-comment-list-container .comment-ui-container.active {
370
369
  padding: 16px;
371
370
  }
371
+
372
+ /* Override seafile ui */
373
+ .sdoc-comment-list-container .btn {
374
+ height: 30px;
375
+ line-height: 15px;
376
+ font-size: 14px;
377
+ font-weight: 500;
378
+ }
@@ -4,6 +4,7 @@ import { getElementCommentCountTop } from '../../helper';
4
4
  import { eventStopPropagation } from '../../../utils/mouse-event';
5
5
  import { focusToCommentElement } from '../../utils';
6
6
  import { Z_INDEX } from '../../../constants';
7
+ import { useScrollContext } from '../../../hooks/use-scroll-context';
7
8
  const ElementCommentCount = _ref => {
8
9
  let {
9
10
  elementId,
@@ -13,16 +14,17 @@ const ElementCommentCount = _ref => {
13
14
  } = _ref;
14
15
  const element = getNodeById(editor.children, elementId);
15
16
  const [top, setTop] = useState(-9999);
17
+ const scrollRef = useScrollContext();
16
18
  const onClick = useCallback(event => {
17
19
  eventStopPropagation(event);
18
20
  focusToCommentElement(editor, element);
19
21
  }, [editor, element]);
20
22
  useEffect(() => {
21
23
  if (!element) return;
22
- const scrollTop = 0;
24
+ const scrollTop = scrollRef.current.scrollTop || 0;
23
25
  const newTop = getElementCommentCountTop(editor, element, scrollTop);
24
26
  setTop(newTop);
25
- }, [editor, elementId, element, isElementSelected]);
27
+ }, [editor, elementId, element, isElementSelected, scrollRef]);
26
28
  if (!element) return null;
27
29
  let style = {
28
30
  top
@@ -18,7 +18,7 @@ export const getCursorPosition = () => {
18
18
  let range = getSelectionRange();
19
19
  if (range) {
20
20
  const rect = range.getBoundingClientRect();
21
- const headerHeight = 100;
21
+ const headerHeight = 93;
22
22
  x = rect.x || 0;
23
23
  y = rect.y - headerHeight + (rect.height - 24) / 2 || 0;
24
24
  }
@@ -59,5 +59,5 @@ export const getElementCommentCountTop = (editor, element, scrollTop) => {
59
59
  if (!minY) minY = y;
60
60
  minY = Math.min(minY, y);
61
61
  });
62
- return minY - 100 + scrollTop; // 100: header height(56) + toolbar height(44)
62
+ return minY - 93 + scrollTop; // 100: header height(56) + toolbar height(37)
63
63
  };
@@ -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, getSelectedElems } from '../../core';
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')) {
@@ -18,6 +18,6 @@ import CalloutPlugin from './callout';
18
18
  import SearchReplacePlugin from './search-replace';
19
19
  import MentionPlugin from './mention';
20
20
  const Plugins = [MarkDownPlugin, HtmlPlugin, HeaderPlugin, LinkPlugin, BlockquotePlugin, ListPlugin, CheckListPlugin, CodeBlockPlugin, ImagePlugin, TablePlugin, TextPlugin, TextAlignPlugin, FontPlugin, SdocLinkPlugin, ParagraphPlugin, FileLinkPlugin, CalloutPlugin, SearchReplacePlugin];
21
- const CommentPlugins = [TextPlugin, MarkDownPlugin, HtmlPlugin, ListPlugin, ImagePlugin, LinkPlugin, MentionPlugin];
21
+ const CommentPlugins = [MarkDownPlugin, HtmlPlugin, ParagraphPlugin, TextPlugin, ListPlugin, ImagePlugin, LinkPlugin, MentionPlugin, BlockquotePlugin];
22
22
  export default Plugins;
23
23
  export { MarkDownPlugin, HeaderPlugin, LinkPlugin, BlockquotePlugin, ListPlugin, CheckListPlugin, CodeBlockPlugin, ImagePlugin, TablePlugin, TextPlugin, HtmlPlugin, TextAlignPlugin, FontPlugin, SdocLinkPlugin, ParagraphPlugin, FileLinkPlugin, CalloutPlugin, SearchReplacePlugin, MentionPlugin, CommentPlugins };
@@ -33,12 +33,12 @@ const renderListItem = (props, editor) => {
33
33
  default:
34
34
  className = '';
35
35
  }
36
- const isBlod = element.children[0].children.every(item => item.bold === true);
36
+ const isBold = element.children[0].children.every(item => item.bold === true);
37
37
  return /*#__PURE__*/React.createElement("li", Object.assign({
38
38
  "data-id": element.id
39
39
  }, attributes, {
40
40
  className: classnames(className, {
41
- 'sdoc-li-blod': isBlod
41
+ 'sdoc-li-bold': isBold
42
42
  })
43
43
  }), children);
44
44
  };
@@ -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) {
@@ -1,7 +1,7 @@
1
1
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
2
  import { useReadOnly, useSlateStatic } from '@seafile/slate-react';
3
- import { LINK, LIST_ITEM, ORDERED_LIST, PARAGRAPH, UNORDERED_LIST, IMAGE, IMAGE_BLOCK, MENTION, MENTION_TEMP } from '../constants';
4
- import { LinkPlugin, ListPlugin, ImagePlugin, ParagraphPlugin, MentionPlugin } from '../plugins';
3
+ import { LINK, LIST_ITEM, ORDERED_LIST, PARAGRAPH, UNORDERED_LIST, IMAGE, IMAGE_BLOCK, MENTION, MENTION_TEMP, BLOCKQUOTE } from '../constants';
4
+ import { LinkPlugin, ListPlugin, ImagePlugin, ParagraphPlugin, MentionPlugin, BlockquotePlugin } from '../plugins';
5
5
  import { getParentNode } from '../core';
6
6
  const RenderCommentEditorCustomRenderElement = props => {
7
7
  const editor = useSlateStatic();
@@ -73,6 +73,11 @@ const RenderCommentEditorCustomRenderElement = props => {
73
73
  const [, renderMentionTemporaryInput] = MentionPlugin.renderElements;
74
74
  return renderMentionTemporaryInput(props, editor);
75
75
  }
76
+ case BLOCKQUOTE:
77
+ {
78
+ const [renderBlockquote] = BlockquotePlugin.renderElements;
79
+ return renderBlockquote(props, editor);
80
+ }
76
81
  default:
77
82
  {
78
83
  const [renderParagraph] = ParagraphPlugin.renderElements;
@@ -8,6 +8,7 @@ import ImageMenu from '../../plugins/image/menu';
8
8
  import EventBus from '../../../utils/event-bus';
9
9
  import LinkMenu from '../../plugins/link/menu';
10
10
  import PostCommentBtn from './post-comment';
11
+ import QuoteMenu from '../../plugins/blockquote/menu';
11
12
  const CommentEditorToolbar = _ref => {
12
13
  let {
13
14
  editor,
@@ -25,6 +26,9 @@ const CommentEditorToolbar = _ref => {
25
26
  }, /*#__PURE__*/React.createElement(CommentEditorTextStyleMenuList, {
26
27
  editor: editor,
27
28
  readonly: readonly
29
+ }), /*#__PURE__*/React.createElement(QuoteMenu, {
30
+ editor: editor,
31
+ readonly: readonly
28
32
  }), /*#__PURE__*/React.createElement(ListMenu, {
29
33
  editor: editor,
30
34
  type: UNORDERED_LIST,
@@ -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,6 +1,6 @@
1
1
  {
2
2
  "name": "@seafile/sdoc-editor",
3
- "version": "0.5.47",
3
+ "version": "0.5.49",
4
4
  "private": false,
5
5
  "description": "This is a sdoc editor",
6
6
  "main": "dist/index.js",