@seafile/sdoc-editor 1.0.46 → 1.0.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.
@@ -5,10 +5,10 @@ import { ReactEditor } from '@seafile/slate-react';
5
5
  import slugId from 'slugid';
6
6
  import context from '../../../../context';
7
7
  import EventBus from '../../../utils/event-bus';
8
- import { generateEmptyElement, getNodeType, isTextNode, getParentNode, focusEditor } from '../../core';
8
+ import { generateEmptyElement, getNodeType, isTextNode, getParentNode, focusEditor, getAboveBlockNode } from '../../core';
9
9
  import { isList } from '../../toolbar/side-toolbar/helpers';
10
10
  import { COMMENT_EDITOR, INTERNAL_EVENT } from '../../../constants';
11
- import { CODE_BLOCK, ELEMENT_TYPE, IMAGE, IMAGE_BLOCK, INSERT_POSITION } from '../../constants';
11
+ import { CODE_BLOCK, ELEMENT_TYPE, IMAGE, IMAGE_BLOCK, INSERT_POSITION, PARAGRAPH, SUBTITLE, TITLE } from '../../constants';
12
12
  import base64ToUnit8Array from '../../../../utils/base64-to-unit8array';
13
13
  export const isInsertImageMenuDisabled = (editor, readonly) => {
14
14
  if (readonly) return true;
@@ -26,6 +26,8 @@ export const isInsertImageMenuDisabled = (editor, readonly) => {
26
26
  }
27
27
  if (type === CODE_BLOCK) return true;
28
28
  if (type.startsWith('header')) return true;
29
+ if (type === TITLE) return true;
30
+ if (type === SUBTITLE) return true;
29
31
  if (Editor.isVoid(editor, n)) return true;
30
32
  return false;
31
33
  },
@@ -55,6 +57,22 @@ export const insertImage = function (editor, srcList, selection) {
55
57
  });
56
58
  const validSelection = selection || editor.selection;
57
59
  let path = Editor.path(editor, validSelection);
60
+ const aboveNodeEntry = getAboveBlockNode(editor);
61
+ const isEmptyParagraph = aboveNodeEntry[0].type === PARAGRAPH && Node.string(aboveNodeEntry[0]).length === 0;
62
+ if (imageNodes.length === 1 && isEmptyParagraph) {
63
+ const imageNode = imageNodes[0];
64
+ Transforms.insertNodes(editor, imageNode, {
65
+ at: validSelection
66
+ });
67
+ Transforms.setNodes(editor, {
68
+ type: IMAGE_BLOCK
69
+ }, {
70
+ at: validSelection
71
+ });
72
+ const imageEndSelection = Path.next(Path.next(path));
73
+ focusEditor(editor, imageEndSelection);
74
+ return;
75
+ }
58
76
  if (position === INSERT_POSITION.AFTER) {
59
77
  if (isList(editor, path)) {
60
78
  const targetPath = path.slice(0, -2);
@@ -147,11 +165,13 @@ export const resetCursor = editor => {
147
165
  Transforms.select(editor, targetPath);
148
166
  });
149
167
  };
150
- export const isSingleImage = data => {
151
- if (data.length !== 1) return false;
152
- if (Node.string(data[0]).length !== 0) return false;
153
- if (data[0].children.filter(item => (item === null || item === void 0 ? void 0 : item.type) === IMAGE).length !== 1) return false;
154
- return true;
168
+ export const getSingleImageFromFragment = data => {
169
+ if (data.length !== 1) return null;
170
+ if (Node.string(data[0]).length !== 0) return null;
171
+ const children = data[0].children;
172
+ const images = children.filter(item => (item === null || item === void 0 ? void 0 : item.type) === IMAGE);
173
+ if (images.length !== 1) return null;
174
+ return images[0];
155
175
  };
156
176
  export const insertImageFiles = (files, editor, targetPath) => {
157
177
  context.uploadLocalImage(files).then(fileUrl => {
@@ -2,11 +2,11 @@ import { Transforms, Path, Editor, Element, Range } from '@seafile/slate';
2
2
  import toaster from '../../../../components/toast';
3
3
  import context from '../../../../context';
4
4
  import EventBus from '../../../utils/event-bus';
5
- import { insertImage, hasSdocImages, getImageData, queryCopyMoveProgressView, resetCursor, isSingleImage } from './helpers';
6
- import { focusEditor, generateEmptyElement, isBlockAboveEmpty } from '../../core';
5
+ import { insertImage, hasSdocImages, getImageData, queryCopyMoveProgressView, resetCursor, isInsertImageMenuDisabled, getSingleImageFromFragment } from './helpers';
6
+ import { focusEditor, generateEmptyElement, getLastChildPath, getSelectedNodeEntryByType, isBlockAboveEmpty, isSelectionAtBlockStart } from '../../core';
7
7
  import { getErrorMsg } from '../../../../utils';
8
8
  import { getSlateFragmentAttribute } from '../../../utils/document-utils';
9
- import { INSERT_POSITION, CLIPBOARD_FORMAT_KEY, CLIPBOARD_ORIGIN_SDOC_KEY, IMAGE, IMAGE_BLOCK, PARAGRAPH } from '../../constants';
9
+ import { INSERT_POSITION, CLIPBOARD_FORMAT_KEY, CLIPBOARD_ORIGIN_SDOC_KEY, IMAGE, IMAGE_BLOCK, PARAGRAPH, ELEMENT_TYPE } from '../../constants';
10
10
  import { INTERNAL_EVENT } from '../../../constants';
11
11
  const withImage = editor => {
12
12
  const {
@@ -70,14 +70,27 @@ const withImage = editor => {
70
70
  if (data.types && data.types.includes('Files') && data.files[0].type.includes(IMAGE)) {
71
71
  context.uploadLocalImage(data.files).then(fileUrl => {
72
72
  insertImage(newEditor, fileUrl, editor.selection, INSERT_POSITION.CURRENT);
73
- resetCursor(newEditor);
74
73
  });
75
74
  return;
76
75
  }
77
76
  insertData(data);
78
77
  };
79
78
  newEditor.insertFragment = data => {
80
- if (isSingleImage(data)) {
79
+ const singleImage = getSingleImageFromFragment(data);
80
+ if (singleImage && isInsertImageMenuDisabled(editor)) {
81
+ const path = Editor.path(editor, editor.selection);
82
+ const nextPath = Path.next([path[0]]);
83
+ const p = generateEmptyElement(ELEMENT_TYPE.PARAGRAPH);
84
+ p.children = [singleImage];
85
+ Transforms.insertNodes(editor, p, {
86
+ at: nextPath
87
+ });
88
+ // There will be a space before and after the image
89
+ const imagePath = [...nextPath, 1];
90
+ focusEditor(editor, Path.next(imagePath));
91
+ return;
92
+ }
93
+ if (singleImage) {
81
94
  resetCursor(newEditor);
82
95
  }
83
96
  return insertFragment(data);
@@ -110,28 +123,39 @@ const withImage = editor => {
110
123
  const {
111
124
  selection
112
125
  } = editor;
113
- const focusPoint = Editor.before(editor, selection);
126
+ if (!selection) return deleteBackward(unit);
114
127
  const point = Editor.before(editor, selection, {
115
128
  distance: 1
116
129
  });
117
130
  if (!point) return deleteBackward(unit);
118
- const [node, path] = Editor.node(editor, [point.path[0], point.path[1]]);
119
- const isPerviousNodeImage = node.type === IMAGE;
120
- if (isPerviousNodeImage && Range.isCollapsed(selection) && isBlockAboveEmpty(editor) && !Path.isCommon(path, selection.anchor.path)) {
121
- deleteBackward(unit);
122
- focusEditor(newEditor, Editor.end(newEditor, focusPoint));
123
- return;
131
+ if (!Range.isCollapsed(selection)) {
132
+ return deleteBackward(unit);
124
133
  }
125
- if (Element.isElement(node) && node.type === IMAGE) {
126
- // If the wrapping element is image_block, delete the wrapping element
127
- const [parentNode, p] = Editor.node(editor, [path[0]]);
128
- if (parentNode.type === IMAGE_BLOCK) {
129
- Transforms.removeNodes(editor, {
130
- at: p
131
- });
134
+ if (isSelectionAtBlockStart(editor)) {
135
+ const path = selection.anchor.path;
136
+ const beforePath = [path[0] - 1];
137
+ const beforeBlock = Editor.node(editor, beforePath);
138
+ if (beforeBlock && beforeBlock[0].type === IMAGE_BLOCK) {
139
+ focusEditor(editor, [...beforePath, 1]);
132
140
  return;
133
141
  }
134
- focusEditor(editor, Path.next(path));
142
+ }
143
+ const imageBlock = getSelectedNodeEntryByType(editor, IMAGE_BLOCK);
144
+ if (imageBlock) {
145
+ const path = selection.anchor.path;
146
+ const deletePath = [path[0]];
147
+ Transforms.removeNodes(editor, {
148
+ at: deletePath
149
+ });
150
+ const beforeEntry = Editor.node(editor, Path.previous(deletePath));
151
+ const selectPath = getLastChildPath(beforeEntry);
152
+ const endOfFirstNode = Editor.end(editor, selectPath);
153
+ const range = {
154
+ anchor: endOfFirstNode,
155
+ focus: endOfFirstNode
156
+ };
157
+ focusEditor(editor, range);
158
+ return;
135
159
  }
136
160
  deleteBackward(unit);
137
161
  };
@@ -201,7 +201,8 @@ const Image = _ref => {
201
201
  }, attributes, {
202
202
  style: _objectSpread({}, style),
203
203
  onMouseOver: e => selectImageWhenSelectPartial(e, editor, element, isSelected),
204
- contentEditable: "true"
204
+ contentEditable: "true",
205
+ suppressContentEditableWarning: true
205
206
  }), /*#__PURE__*/React.createElement("img", {
206
207
  ref: imageRef,
207
208
  src: imagePlaceholder,
@@ -214,10 +215,10 @@ const Image = _ref => {
214
215
  }, attributes, {
215
216
  style: _objectSpread({}, style),
216
217
  onMouseOver: e => selectImageWhenSelectPartial(e, editor, element, isSelected),
217
- contentEditable: "true"
218
+ contentEditable: "true",
219
+ suppressContentEditableWarning: true
218
220
  }), /*#__PURE__*/React.createElement("span", {
219
- className: "sdoc-image-inner",
220
- contentEditable: "false"
221
+ className: "sdoc-image-inner"
221
222
  }, /*#__PURE__*/React.createElement("span", {
222
223
  className: "sdoc-image-content"
223
224
  }, /*#__PURE__*/React.createElement("span", {
@@ -238,8 +239,7 @@ const Image = _ref => {
238
239
  ref: resizerRef,
239
240
  onMouseDown: onResizeStart
240
241
  }), isResizing && /*#__PURE__*/React.createElement("span", {
241
- className: "image-size",
242
- contentEditable: false
242
+ className: "image-size"
243
243
  }, /*#__PURE__*/React.createElement("span", null, t('Width'), ':', parseInt(movingWidth || ((_imageRef$current = imageRef.current) === null || _imageRef$current === void 0 ? void 0 : _imageRef$current.clientWidth))), /*#__PURE__*/React.createElement("span", null, "\xA0\xA0"), /*#__PURE__*/React.createElement("span", null, t('Height'), ':', imageRef.current.clientHeight))), nodeEntry[0].type === IMAGE_BLOCK && show_caption && /*#__PURE__*/React.createElement("input", {
244
244
  id: "sdoc-image-caption-input",
245
245
  ref: imageCaptionInputRef,
@@ -18,6 +18,8 @@ export const isInsertSeaTableTableDisabled = (editor, readonly) => {
18
18
  type = getNodeType(parentNode);
19
19
  }
20
20
  if (type.startsWith('header')) return true;
21
+ if (type === ELEMENT_TYPE.TITLE) return true;
22
+ if (type === ELEMENT_TYPE.SUBTITLE) return true;
21
23
  if (type === ELEMENT_TYPE.CODE_BLOCK) return true;
22
24
  if (type === ELEMENT_TYPE.ORDERED_LIST) return true;
23
25
  if (type === ELEMENT_TYPE.UNORDERED_LIST) return true;
@@ -25,6 +25,8 @@ export const isTableMenuDisabled = (editor, readonly) => {
25
25
  type = getNodeType(parentNode);
26
26
  }
27
27
  if (type.startsWith('header')) return true;
28
+ if (type === ELEMENT_TYPE.TITLE) return true;
29
+ if (type === ELEMENT_TYPE.SUBTITLE) return true;
28
30
  if (type === ELEMENT_TYPE.CODE_BLOCK) return true;
29
31
  if (type === ELEMENT_TYPE.ORDERED_LIST) return true;
30
32
  if (type === ELEMENT_TYPE.UNORDERED_LIST) return true;
@@ -575,8 +577,10 @@ export const removeTableElement = (editor, type) => {
575
577
  return;
576
578
  }
577
579
  for (let i = minRowIndex; i <= maxRowIndex; i++) {
578
- Transforms.removeNodes(editor, {
579
- at: [...tablePath, minRowIndex]
580
+ queueMicrotask(() => {
581
+ Transforms.removeNodes(editor, {
582
+ at: [...tablePath, minRowIndex]
583
+ });
580
584
  });
581
585
  }
582
586
  const focusPath = [...tablePath, minRowIndex === 0 ? 0 : minRowIndex - 1, cellIndex];
@@ -1770,9 +1774,27 @@ export const isHideDragHandlerLine = (editor, displayType, table, cellPath, isDr
1770
1774
  if (displayType === DRAG_HANDLER_COLUMN && cellIndex > 0) {
1771
1775
  const prevCell = table.children[rowIndex].children[cellIndex - 1];
1772
1776
  preCellDom = ReactEditor.toDOMNode(editor, prevCell);
1777
+
1778
+ // Check if there are merged cells in the columns before and after the drag line
1779
+ const beforeLineColumnHasCombined = table.children.find(item => {
1780
+ const cell = item.children[cellIndex - 1];
1781
+ return cell.children.length > 1;
1782
+ });
1783
+ const afterLineColumnHasCombined = table.children.find(item => {
1784
+ const cell = item.children[cellIndex];
1785
+ return (cell === null || cell === void 0 ? void 0 : cell.is_combined) === true;
1786
+ });
1787
+ if (beforeLineColumnHasCombined && afterLineColumnHasCombined) return true;
1773
1788
  } else if (displayType === DRAG_HANDLER_ROW && rowIndex > 0) {
1774
1789
  const prevCell = table.children[rowIndex - 1].children[cellIndex];
1775
1790
  preCellDom = ReactEditor.toDOMNode(editor, prevCell);
1791
+
1792
+ // Check whether there are merged cells in the rows before and after the drag line
1793
+ const beforeLineRow = table.children[rowIndex - 1];
1794
+ const afterLineRow = table.children[rowIndex];
1795
+ const beforeLineRowHasCombined = beforeLineRow.children.find(item => item.children.length > 1);
1796
+ const afterLineRowHasCombined = afterLineRow.children.find(item => (item === null || item === void 0 ? void 0 : item.is_combined) === true);
1797
+ if (beforeLineRowHasCombined && afterLineRowHasCombined) return true;
1776
1798
  }
1777
1799
 
1778
1800
  // Check is above cell selected
@@ -46,7 +46,7 @@ class TableContextMenu extends React.Component {
46
46
  } = this.props;
47
47
  insertTableElement(editor, type, position, count);
48
48
  });
49
- _defineProperty(this, "removeTableElement", type => {
49
+ _defineProperty(this, "removeTableElements", type => {
50
50
  const {
51
51
  editor
52
52
  } = this.props;
@@ -54,7 +54,7 @@ class TableContextMenu extends React.Component {
54
54
  });
55
55
  _defineProperty(this, "renderRemoveBtn", (type, title) => {
56
56
  return /*#__PURE__*/React.createElement("button", {
57
- onMouseDown: this.removeTableElement.bind(this, type),
57
+ onMouseDown: this.removeTableElements.bind(this, type),
58
58
  className: "dropdown-item"
59
59
  }, this.props.t(title));
60
60
  });
@@ -6,7 +6,6 @@ import { PAGE_EDIT_AREA_WIDTH, WIKI_EDITOR } from '../basic-sdk/constants';
6
6
  import { createWikiEditor } from '../basic-sdk/extension';
7
7
  import withNodeId from '../basic-sdk/node-id';
8
8
  import { withSocketIO } from '../basic-sdk/socket';
9
- import { TITLE } from '../basic-sdk/extension/constants';
10
9
  import WikiEditor from '../basic-sdk/editor/wiki-editor';
11
10
  import '../assets/css/simple-viewer.css';
12
11
  const SdocWikiEditor = _ref => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seafile/sdoc-editor",
3
- "version": "1.0.46",
3
+ "version": "1.0.48",
4
4
  "private": false,
5
5
  "description": "This is a sdoc editor",
6
6
  "main": "dist/index.js",