@seafile/sdoc-editor 0.5.42 → 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.
@@ -9,7 +9,7 @@ import { useCursors } from '../cursor/use-cursors';
9
9
  import { INTERNAL_EVENT } from '../constants';
10
10
  import { usePipDecorate } from '../decorates';
11
11
  import EventBus from '../utils/event-bus';
12
- import { IMAGE } from '../extension/constants';
12
+ import { IMAGE, IMAGE_BLOCK } from '../extension/constants';
13
13
  import RenderCommentEditorCustomRenderElement from '../extension/render/render-comment-editor-element';
14
14
  import EventProxy from '../utils/event-handler';
15
15
  const CommentArticle = _ref => {
@@ -40,14 +40,12 @@ const CommentArticle = _ref => {
40
40
  const {
41
41
  selection
42
42
  } = editor;
43
- if (Range.isCollapsed(selection)) {
44
- // Do not scroll into view, when focus on image
45
- const [imageNodeEntry] = Editor.nodes(editor, {
46
- match: n => n.type === IMAGE,
47
- at: selection
48
- });
49
- if (imageNodeEntry) return;
50
- }
43
+ // Do not scroll into view, when focus on image
44
+ const [imageNodeEntry] = Editor.nodes(editor, {
45
+ match: n => [IMAGE, IMAGE_BLOCK].includes(n.type),
46
+ at: selection
47
+ });
48
+ if (imageNodeEntry) return;
51
49
  const focusedNode = Node.get(editor, selection.focus.path);
52
50
  const domNode = ReactEditor.toDOMNode(editor, focusedNode);
53
51
  if (!domNode) return;
@@ -14,7 +14,7 @@ import EventBus from '../utils/event-bus';
14
14
  import { ArticleContainer } from '../layout';
15
15
  import { useScrollContext } from '../hooks/use-scroll-context';
16
16
  import { SetNodeToDecorations } from '../highlight';
17
- import { IMAGE } from '../extension/constants';
17
+ import { IMAGE, IMAGE_BLOCK } from '../extension/constants';
18
18
  import { isPreventResetTableSelectedRange } from '../extension/plugins/table/helpers';
19
19
  const EditableArticle = _ref => {
20
20
  let {
@@ -144,14 +144,12 @@ const EditableArticle = _ref => {
144
144
  const {
145
145
  selection
146
146
  } = editor;
147
- if (Range.isCollapsed(selection)) {
148
- // Do not scroll into view, when focus on image
149
- const [imageNodeEntry] = Editor.nodes(editor, {
150
- match: n => n.type === IMAGE,
151
- at: selection
152
- });
153
- if (imageNodeEntry) return;
154
- }
147
+ // Do not scroll into view, when focus on image
148
+ const [imageNodeEntry] = Editor.nodes(editor, {
149
+ match: n => [IMAGE, IMAGE_BLOCK].includes(n.type),
150
+ at: selection
151
+ });
152
+ if (imageNodeEntry) return;
155
153
  const focusedNode = Node.get(editor, selection.focus.path);
156
154
  const domNode = ReactEditor.toDOMNode(editor, focusedNode);
157
155
  if (!domNode) return;
@@ -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), children);
312
+ }, attributes, {
313
+ onMouseOver: e => selectImageWhenSelectPartial(e, editor, element, isSelected)
314
+ }), children);
309
315
  }
@@ -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] : {};
@@ -1,17 +1,17 @@
1
1
  import React, { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import Tooltip from '../../../tooltip';
4
- import { getTopLevelChanges } from '../../../../basic-sdk/utils/diff';
4
+ import { getTopLevelChanges, getMergedChanges } from '../../../../basic-sdk/utils/diff';
5
5
  import './index.css';
6
6
  const ChangesCount = _ref => {
7
7
  let {
8
- changes
8
+ allChanges
9
9
  } = _ref;
10
10
  const {
11
11
  t
12
12
  } = useTranslation();
13
13
  const [currentDiffIndex, setDiffIndex] = useState(0);
14
- const [topLevelChanges, setTopLevelChanges] = useState([]);
14
+ const [changes, setChanges] = useState([]);
15
15
  const intervalRef = useRef();
16
16
  useEffect(() => {
17
17
  // Article rendering is delayed, so we need to wait for the Article to render before we can get the changes
@@ -25,18 +25,19 @@ const ChangesCount = _ref => {
25
25
  }
26
26
  }, 100);
27
27
  }).then(() => {
28
- if (changes.length !== 0) {
29
- const topLevelChanges = getTopLevelChanges(changes);
30
- setTopLevelChanges([...topLevelChanges]);
28
+ if (allChanges.changes.length !== 0) {
29
+ const topLevelChanges = getTopLevelChanges(allChanges.changes);
30
+ const changes = getMergedChanges(topLevelChanges, allChanges.value);
31
+ setChanges(changes);
31
32
  }
32
33
  });
33
34
  return () => {
34
35
  intervalRef.current && clearInterval(intervalRef.current);
35
36
  };
36
- }, [changes]);
37
+ }, [allChanges]);
37
38
  const jumpToElement = useCallback(currentDiffIndex => {
38
39
  setDiffIndex(currentDiffIndex);
39
- const change = topLevelChanges[currentDiffIndex];
40
+ const change = changes[currentDiffIndex];
40
41
  const changeElement = document.querySelectorAll("[data-id=\"".concat(change, "\"]"))[0];
41
42
  if (changeElement) {
42
43
  const scrollContainer = document.getElementById('sdoc-scroll-container');
@@ -46,31 +47,31 @@ const ChangesCount = _ref => {
46
47
  }
47
48
 
48
49
  // eslint-disable-next-line react-hooks/exhaustive-deps
49
- }, [topLevelChanges, currentDiffIndex]);
50
+ }, [changes, currentDiffIndex]);
50
51
  const lastChange = useCallback(() => {
51
52
  if (currentDiffIndex === 0) {
52
- jumpToElement(topLevelChanges.length - 1);
53
+ jumpToElement(changes.length - 1);
53
54
  return;
54
55
  }
55
56
  jumpToElement(currentDiffIndex - 1);
56
57
 
57
58
  // eslint-disable-next-line react-hooks/exhaustive-deps
58
- }, [topLevelChanges, currentDiffIndex]);
59
+ }, [changes, currentDiffIndex]);
59
60
  const nextChange = useCallback(() => {
60
- if (currentDiffIndex === topLevelChanges.length - 1) {
61
+ if (currentDiffIndex === changes.length - 1) {
61
62
  jumpToElement(0);
62
63
  return;
63
64
  }
64
65
  jumpToElement(currentDiffIndex + 1);
65
66
 
66
67
  // eslint-disable-next-line react-hooks/exhaustive-deps
67
- }, [topLevelChanges, currentDiffIndex]);
68
- if (!Array.isArray(topLevelChanges) || topLevelChanges.length === 0) {
68
+ }, [changes, currentDiffIndex]);
69
+ if (!Array.isArray(changes) || changes.length === 0) {
69
70
  return /*#__PURE__*/React.createElement("div", {
70
71
  className: "sdoc-revision-changes-container d-flex align-items-center pl-2 pr-2 ml-4"
71
72
  }, t('No_changes'));
72
73
  }
73
- const changesCount = topLevelChanges.length;
74
+ const changesCount = changes.length;
74
75
  return /*#__PURE__*/React.createElement("div", {
75
76
  className: "sdoc-revision-changes-container d-flex align-items-center ml-4"
76
77
  }, /*#__PURE__*/React.createElement("div", {
@@ -192,7 +192,7 @@ const RevisionOperations = _ref => {
192
192
  setShowTip(false);
193
193
  }, []);
194
194
  return /*#__PURE__*/React.createElement(React.Fragment, null, !isSdocRevision && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(MoreRevisionOperations, null), /*#__PURE__*/React.createElement(Revisions, null)), isSdocRevision && isShowChanges && /*#__PURE__*/React.createElement(ChangesCount, {
195
- changes: changes
195
+ allChanges: changes
196
196
  }), isSdocRevision && /*#__PURE__*/React.createElement(ViewChanges, {
197
197
  isShowChanges: isShowChanges,
198
198
  onViewChangesToggle: onViewChangesToggle
@@ -50,7 +50,7 @@ const PublishedRevisionViewer = () => {
50
50
  });
51
51
  }, []);
52
52
  const setDiffChanges = useCallback(diff => {
53
- setChanges((diff === null || diff === void 0 ? void 0 : diff.changes) || []);
53
+ setChanges(diff);
54
54
  }, []);
55
55
  const handleViewChangesToggle = useCallback(isShowChanges => {
56
56
  setShowChanges(isShowChanges);
@@ -40,7 +40,7 @@ const SimpleEditor = _ref => {
40
40
  // eslint-disable-next-line react-hooks/exhaustive-deps
41
41
  }, []);
42
42
  const setDiffChanges = useCallback(diff => {
43
- setChanges(diff.changes);
43
+ setChanges(diff);
44
44
  // eslint-disable-next-line react-hooks/exhaustive-deps
45
45
  }, [isShowChanges]);
46
46
  const handleViewChangesToggle = useCallback(isShowChanges => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seafile/sdoc-editor",
3
- "version": "0.5.42",
3
+ "version": "0.5.43",
4
4
  "private": false,
5
5
  "description": "This is a sdoc editor",
6
6
  "main": "dist/index.js",