@seafile/sdoc-editor 2.0.41 → 2.0.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.
@@ -45,13 +45,11 @@ const InsertElementDialog = _ref => {
45
45
  const uploadLocalImageInputRef = (0, _react.useRef)();
46
46
  const uploadLocalVideoInputRef = (0, _react.useRef)();
47
47
  const onFileChanged = (0, _react.useCallback)(event => {
48
- const files = event.target.files;
49
- _context.default.uploadLocalImage(files).then(fileUrl => {
50
- (0, _helpers.insertImage)(validEditor, fileUrl, validEditor.selection, insertPosition);
51
- if (uploadLocalImageInputRef.current) {
52
- uploadLocalImageInputRef.current.value = '';
53
- }
54
- });
48
+ const imgInfos = (0, _helpers.generateImageInfos)(event.target.files);
49
+ (0, _helpers.insertImage)(validEditor, imgInfos, validEditor.selection, insertPosition);
50
+ if (uploadLocalImageInputRef.current) {
51
+ uploadLocalImageInputRef.current.value = '';
52
+ }
55
53
  // eslint-disable-next-line react-hooks/exhaustive-deps
56
54
  }, [validEditor, uploadLocalImageInputRef, insertPosition, slateNode]);
57
55
  const handleDisplayAlert = (0, _react.useCallback)(() => {
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.updateImage = exports.selectImageWhenSelectPartial = exports.resetCursor = exports.removeImageBlockNode = exports.queryCopyMoveProgressView = exports.isInsertImageMenuDisabled = exports.isImageUrlIsFromCopy = exports.insertImageFiles = exports.insertImage = exports.hasSdocImages = exports.handleBase64Image = exports.getSingleImageFromFragment = exports.getImageURL = exports.getImageData = exports.generateImageNode = void 0;
7
+ exports.updateImage = exports.selectImageWhenSelectPartial = exports.resetCursor = exports.removeImageBlockNode = exports.queryCopyMoveProgressView = exports.isInsertImageMenuDisabled = exports.isImageUrlIsFromUpload = exports.isImageUrlIsFromCopy = exports.insertImageFiles = exports.insertImage = exports.hasSdocImages = exports.handleBase64Image = exports.getSingleImageFromFragment = exports.getImageURL = exports.getImageData = exports.generateImageNode = exports.generateImageInfos = void 0;
8
8
  var _urlJoin = _interopRequireDefault(require("url-join"));
9
9
  var _slate = require("@seafile/slate");
10
10
  var _slateReact = require("@seafile/slate-react");
@@ -17,6 +17,7 @@ var _helpers = require("../seatable-column/helpers");
17
17
  var _constants = require("../../../constants");
18
18
  var _constants2 = require("../../constants");
19
19
  var _base64ToUnit8array = _interopRequireDefault(require("../../../../utils/base64-to-unit8array"));
20
+ var _imageCache = _interopRequireDefault(require("../../../../utils/image-cache"));
20
21
  const isInsertImageMenuDisabled = (editor, readonly) => {
21
22
  if (readonly) return true;
22
23
  const {
@@ -46,28 +47,36 @@ const isInsertImageMenuDisabled = (editor, readonly) => {
46
47
  return false;
47
48
  };
48
49
  exports.isInsertImageMenuDisabled = isInsertImageMenuDisabled;
49
- const generateImageNode = src => {
50
+ const generateImageNode = (src, file_uuid) => {
50
51
  const element = (0, _core.generateEmptyElement)(_constants2.IMAGE);
52
+ let data = {
53
+ src
54
+ };
55
+ if (file_uuid) {
56
+ data.file_uuid = file_uuid;
57
+ }
51
58
  return {
52
59
  ...element,
53
- data: {
54
- src
55
- }
60
+ data
56
61
  };
57
62
  };
58
63
  exports.generateImageNode = generateImageNode;
59
- const insertImage = function (editor, srcList, selection) {
64
+ const insertImage = function (editor, imgInfos, selection) {
60
65
  let position = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : _constants2.INSERT_POSITION.CURRENT;
61
- if (!srcList) return;
66
+ if (!imgInfos) return;
62
67
  if (position !== _constants2.INSERT_POSITION.AFTER) {
63
68
  if (isInsertImageMenuDisabled(editor)) return;
64
69
  }
65
- const imageNodes = srcList.map(src => {
70
+ const imageNodes = imgInfos.map(_ref => {
71
+ let {
72
+ src,
73
+ file_uuid
74
+ } = _ref;
66
75
  const isCommentEditor = editor.editorType === _constants.COMMENT_EDITOR;
67
76
  const imgSrc = isCommentEditor ? getImageURL({
68
77
  src
69
78
  }) : src;
70
- return generateImageNode(imgSrc);
79
+ return generateImageNode(imgSrc, file_uuid);
71
80
  });
72
81
  const validSelection = selection || editor.selection;
73
82
  let path = _slate.Editor.path(editor, validSelection);
@@ -153,6 +162,11 @@ const getImageURL = (data, editor) => {
153
162
  return imgUrl;
154
163
  }
155
164
  }
165
+
166
+ // upload image | drag drop image | cut image
167
+ if (isImageUrlIsFromUpload(url)) return url;
168
+
169
+ // copy from others doc
156
170
  if (isImageUrlIsFromCopy(url)) return url;
157
171
  const serviceUrl = _context.default.getSetting('serviceUrl');
158
172
  const assetsUrl = _context.default.getSetting('assetsUrl');
@@ -223,9 +237,8 @@ const getSingleImageFromFragment = data => {
223
237
  };
224
238
  exports.getSingleImageFromFragment = getSingleImageFromFragment;
225
239
  const insertImageFiles = (files, editor, targetPath) => {
226
- _context.default.uploadLocalImage(files).then(fileUrl => {
227
- insertImage(editor, fileUrl, targetPath, _constants2.INSERT_POSITION.AFTER);
228
- });
240
+ const imgInfos = generateImageInfos(files);
241
+ insertImage(editor, imgInfos, targetPath, _constants2.INSERT_POSITION.AFTER);
229
242
  };
230
243
  exports.insertImageFiles = insertImageFiles;
231
244
  const selectImageWhenSelectPartial = (event, editor, imageNode, isImageSelected) => {
@@ -284,6 +297,29 @@ const isImageUrlIsFromCopy = url => {
284
297
  return false;
285
298
  };
286
299
  exports.isImageUrlIsFromCopy = isImageUrlIsFromCopy;
300
+ const isImageUrlIsFromUpload = url => {
301
+ if (url && url.startsWith('blob:http')) return true;
302
+ return false;
303
+ };
304
+ exports.isImageUrlIsFromUpload = isImageUrlIsFromUpload;
305
+ const generateImageInfos = files => {
306
+ const newFiles = Array.from(files);
307
+ const imgInfos = newFiles.filter(item => {
308
+ if (item && !item.type.startsWith('image/')) return false;
309
+ if (item && item.type === 'image/svg+xml') return false;
310
+ return true;
311
+ }).map(file => {
312
+ const url = window.URL.createObjectURL(file);
313
+ const file_uuid = _slugid.default.nice();
314
+ _imageCache.default.saveImage(file_uuid, file);
315
+ return {
316
+ src: url,
317
+ file_uuid: file_uuid
318
+ };
319
+ });
320
+ return imgInfos;
321
+ };
322
+ exports.generateImageInfos = generateImageInfos;
287
323
  const removeImageBlockNode = (editor, path) => {
288
324
  _slate.Transforms.removeNodes(editor, {
289
325
  at: path
@@ -37,4 +37,13 @@
37
37
 
38
38
  .sdoc-image-process-container .copyright {
39
39
  margin-top: 4px;
40
+ color: #fff;
41
+ }
42
+
43
+ .sdoc-image-content.upload-error>span {
44
+ min-height: 300px;
45
+ min-width: 400px;
46
+ display: flex;
47
+ align-items: center;
48
+ justify-content: center;
40
49
  }
@@ -9,7 +9,8 @@ var _react = _interopRequireDefault(require("react"));
9
9
  require("./index.css");
10
10
  function ImageLoader(_ref) {
11
11
  let {
12
- copyright
12
+ copyright,
13
+ isError
13
14
  } = _ref;
14
15
  return /*#__PURE__*/_react.default.createElement("div", {
15
16
  className: "sdoc-image-process-container"
@@ -18,6 +19,6 @@ function ImageLoader(_ref) {
18
19
  }, /*#__PURE__*/_react.default.createElement("div", {
19
20
  className: "spinner"
20
21
  })), copyright && /*#__PURE__*/_react.default.createElement("div", {
21
- className: "copyright"
22
+ className: `copyright ${isError && 'error'}`
22
23
  }, copyright));
23
24
  }
@@ -75,9 +75,8 @@ const withImage = editor => {
75
75
  }
76
76
  }
77
77
  if (data.types && data.types.includes('Files') && data.files[0].type.includes(_constants.IMAGE)) {
78
- _context.default.uploadLocalImage(data.files).then(fileUrl => {
79
- (0, _helpers.insertImage)(newEditor, fileUrl, editor.selection, _constants.INSERT_POSITION.CURRENT);
80
- });
78
+ const imgInfos = (0, _helpers.generateImageInfos)(data.files);
79
+ (0, _helpers.insertImage)(newEditor, imgInfos, editor.selection, _constants.INSERT_POSITION.CURRENT);
81
80
  return;
82
81
  }
83
82
  insertData(data);
@@ -22,8 +22,9 @@ var _constants3 = require("../../constants");
22
22
  var _constants4 = require("../../../../constants");
23
23
  var _imagePlaceholder = _interopRequireDefault(require("../../../assets/images/image-placeholder.png"));
24
24
  var _copyImageErrorSvg = _interopRequireDefault(require("../../../../components/copy-image-error-svg"));
25
- var _useUploadImage = _interopRequireDefault(require("./use-upload-image"));
26
25
  var _imageLoader = _interopRequireDefault(require("./image-loader"));
26
+ var _useCopyImage = _interopRequireDefault(require("./use-copy-image"));
27
+ var _useUploadImage = _interopRequireDefault(require("./use-upload-image"));
27
28
  const Image = _ref => {
28
29
  var _imageRef$current, _imageRef$current2;
29
30
  let {
@@ -64,6 +65,13 @@ const Image = _ref => {
64
65
  isCopyImageLoading,
65
66
  isCopyImageError,
66
67
  setCopyImageLoading
68
+ } = (0, _useCopyImage.default)({
69
+ editor,
70
+ element
71
+ });
72
+ const {
73
+ isUploadLoading,
74
+ isUploadError
67
75
  } = (0, _useUploadImage.default)({
68
76
  editor,
69
77
  element
@@ -283,7 +291,9 @@ const Image = _ref => {
283
291
  }), /*#__PURE__*/_react.default.createElement("span", {
284
292
  className: "sdoc-image-inner"
285
293
  }, /*#__PURE__*/_react.default.createElement("span", {
286
- className: "sdoc-image-content"
294
+ className: (0, _classnames.default)('sdoc-image-content', {
295
+ 'upload-error': isUploadError
296
+ })
287
297
  }, /*#__PURE__*/_react.default.createElement("span", {
288
298
  style: imageStyle
289
299
  }, /*#__PURE__*/_react.default.createElement("img", {
@@ -298,8 +308,11 @@ const Image = _ref => {
298
308
  onLoad: onImageLoaded,
299
309
  onError: onImageLoadError,
300
310
  alt: ""
301
- }), isCopyImageLoading && /*#__PURE__*/_react.default.createElement(_imageLoader.default, {
311
+ }), (isCopyImageLoading || isUploadLoading) && /*#__PURE__*/_react.default.createElement(_imageLoader.default, {
302
312
  copyright: t('Image_is_uploading')
313
+ }), isUploadError && /*#__PURE__*/_react.default.createElement(_imageLoader.default, {
314
+ copyright: t('Image_is_upload_error'),
315
+ isError: true
303
316
  }), isSelected && /*#__PURE__*/_react.default.createElement("span", {
304
317
  className: "image-resizer",
305
318
  ref: resizerRef,
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = void 0;
8
+ var _react = require("react");
9
+ var _slate = require("@seafile/slate");
10
+ var _slateReact = require("@seafile/slate-react");
11
+ var _context = _interopRequireDefault(require("../../../../context"));
12
+ var _helpers = require("./helpers");
13
+ const updateImageNode = async function (editor, element, newUrl) {
14
+ let isError = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
15
+ const nodePath = _slateReact.ReactEditor.findPath(editor, element);
16
+ const newData = {
17
+ ...element.data,
18
+ src: newUrl,
19
+ is_copy_error: isError
20
+ };
21
+ _slate.Transforms.setNodes(editor, {
22
+ data: newData
23
+ }, {
24
+ at: nodePath
25
+ });
26
+ };
27
+ const useCopyImage = _ref => {
28
+ let {
29
+ editor,
30
+ element
31
+ } = _ref;
32
+ const {
33
+ data
34
+ } = element;
35
+ const {
36
+ is_copy_error = false
37
+ } = data;
38
+ const [isLoading, setIsLoading] = (0, _react.useState)();
39
+ const [isCopyError, setIsCopyError] = (0, _react.useState)(is_copy_error);
40
+ (0, _react.useEffect)(() => {
41
+ const {
42
+ src: url
43
+ } = data;
44
+ if (isCopyError) return;
45
+ if (!(0, _helpers.isImageUrlIsFromCopy)(url)) return;
46
+ const downloadAndUploadImages = async url => {
47
+ try {
48
+ const response = await fetch(url);
49
+ if (response.ok) {
50
+ const blob = await response.blob();
51
+ const file = new File([blob], 'downloaded_image.png', {
52
+ type: blob.type
53
+ });
54
+ const imageUrl = await _context.default.uploadLocalImage([file]);
55
+ if (imageUrl && imageUrl[0]) {
56
+ updateImageNode(editor, element, imageUrl[0]);
57
+ }
58
+ } else {
59
+ throw new Error(`HTTP error status: ${response.status}`);
60
+ }
61
+ } catch (error) {
62
+ console.error(error);
63
+ updateImageNode(editor, element, url, true);
64
+ setIsCopyError(true);
65
+ } finally {
66
+ setTimeout(() => {
67
+ setIsLoading(false);
68
+ }, 500);
69
+ }
70
+ };
71
+ downloadAndUploadImages(url);
72
+ // eslint-disable-next-line react-hooks/exhaustive-deps
73
+ }, []);
74
+ return {
75
+ isCopyImageLoading: isLoading,
76
+ setCopyImageLoading: setIsLoading,
77
+ isCopyImageError: isCopyError
78
+ };
79
+ };
80
+ var _default = exports.default = useCopyImage;
@@ -10,13 +10,11 @@ var _slate = require("@seafile/slate");
10
10
  var _slateReact = require("@seafile/slate-react");
11
11
  var _context = _interopRequireDefault(require("../../../../context"));
12
12
  var _helpers = require("./helpers");
13
- const updateImageNode = async function (editor, element, newUrl) {
14
- let isError = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
13
+ var _imageCache = _interopRequireDefault(require("../../../../utils/image-cache"));
14
+ const updateImageNode = async (editor, element, newUrl) => {
15
15
  const nodePath = _slateReact.ReactEditor.findPath(editor, element);
16
16
  const newData = {
17
- ...element.data,
18
- src: newUrl,
19
- is_copy_error: isError
17
+ src: newUrl
20
18
  };
21
19
  _slate.Transforms.setNodes(editor, {
22
20
  data: newData
@@ -24,7 +22,7 @@ const updateImageNode = async function (editor, element, newUrl) {
24
22
  at: nodePath
25
23
  });
26
24
  };
27
- const useImageUpload = _ref => {
25
+ const useUploadImage = _ref => {
28
26
  let {
29
27
  editor,
30
28
  element
@@ -32,49 +30,38 @@ const useImageUpload = _ref => {
32
30
  const {
33
31
  data
34
32
  } = element;
35
- const {
36
- is_copy_error = false
37
- } = data;
38
33
  const [isLoading, setIsLoading] = (0, _react.useState)();
39
- const [isCopyError, setIsCopyError] = (0, _react.useState)(is_copy_error);
34
+ const [isUploadError, setIsUploadError] = (0, _react.useState)(false);
40
35
  (0, _react.useEffect)(() => {
41
36
  const {
42
- src: url
37
+ src: url,
38
+ file_uuid
43
39
  } = data;
44
- if (isCopyError) return;
45
- if (!(0, _helpers.isImageUrlIsFromCopy)(url)) return;
46
- const downloadAndUploadImages = async url => {
40
+ if (!(0, _helpers.isImageUrlIsFromUpload)(url)) return;
41
+ setIsLoading(true);
42
+ const uploadCurrentImage = async () => {
47
43
  try {
48
- const response = await fetch(url);
49
- if (response.ok) {
50
- const blob = await response.blob();
51
- const file = new File([blob], 'downloaded_image.png', {
52
- type: blob.type
53
- });
54
- const imageUrl = await _context.default.uploadLocalImage([file]);
55
- if (imageUrl && imageUrl[0]) {
56
- updateImageNode(editor, element, imageUrl[0]);
57
- }
58
- } else {
59
- throw new Error(`HTTP error status: ${response.status}`);
44
+ const fileItem = _imageCache.default.getImage(file_uuid);
45
+ const imageUrl = await _context.default.uploadLocalImage([fileItem]);
46
+ if (imageUrl && imageUrl[0]) {
47
+ updateImageNode(editor, element, imageUrl[0]);
60
48
  }
61
49
  } catch (error) {
62
- console.error(error);
63
- updateImageNode(editor, element, url, true);
64
- setIsCopyError(true);
50
+ console.error(error.message);
51
+ setIsUploadError(true);
65
52
  } finally {
53
+ _imageCache.default.deleteImage(file_uuid);
66
54
  setTimeout(() => {
67
55
  setIsLoading(false);
68
56
  }, 500);
69
57
  }
70
58
  };
71
- downloadAndUploadImages(url);
59
+ uploadCurrentImage(url);
72
60
  // eslint-disable-next-line react-hooks/exhaustive-deps
73
61
  }, []);
74
62
  return {
75
- isCopyImageLoading: isLoading,
76
- setCopyImageLoading: setIsLoading,
77
- isCopyImageError: isCopyError
63
+ isUploadLoading: isLoading,
64
+ isUploadError: isUploadError
78
65
  };
79
66
  };
80
- var _default = exports.default = useImageUpload;
67
+ var _default = exports.default = useUploadImage;
@@ -48,7 +48,7 @@ const Column = _ref => {
48
48
  setColumnValue(displayValue);
49
49
  });
50
50
  }
51
- }, [editor, element.data, isLongTextColumn]);
51
+ }, [editor, element.data, isLongTextColumn, editor.currentRowIdx]);
52
52
  const [isClicked, setIsClicked] = (0, _react.useState)(false);
53
53
  (0, _react.useEffect)(() => {
54
54
  if (isSelected && !isReadOnly) {
@@ -274,7 +274,7 @@ const SideToolbar = () => {
274
274
  targetElement = event.currentTarget;
275
275
  targetElement.classList.remove('sdoc-draging');
276
276
  const dragTypes = event.dataTransfer.types;
277
- if (!dragTypes.includes(_event.DRAG_SDOC_EDITOR_ELEMENT)) return;
277
+ if (!dragTypes.includes(_event.DRAG_SDOC_EDITOR_ELEMENT) && dragTypes[0] !== 'Files') return;
278
278
 
279
279
  // Prevent dragging table data to the editor
280
280
  if (dragTypes.includes(_constants2.TABLE_DRAG_KEY)) return;
@@ -29,6 +29,7 @@ const DocumentPluginEditor = _ref => {
29
29
  tableId,
30
30
  columns,
31
31
  getColumnCellValue,
32
+ currentRowIdx,
32
33
  tables,
33
34
  getTableById,
34
35
  collaborators,
@@ -55,12 +56,12 @@ const DocumentPluginEditor = _ref => {
55
56
  const {
56
57
  cursors
57
58
  } = document;
58
- newEditor.getColumnCellValue = getColumnCellValue;
59
59
 
60
60
  // insert column
61
61
  newEditor.table_id = tableId;
62
62
  newEditor.columns = columns || [];
63
63
  newEditor.getColumnCellValue = getColumnCellValue;
64
+ newEditor.currentRowIdx = currentRowIdx;
64
65
 
65
66
  // insert table
66
67
  newEditor.tables = tables || [];
@@ -87,8 +88,9 @@ const DocumentPluginEditor = _ref => {
87
88
  (0, _react.useEffect)(() => {
88
89
  validEditor.getColumnCellValue = getColumnCellValue ? getColumnCellValue : null;
89
90
  validEditor.getArticleStyle = getArticleStyle;
91
+ validEditor.currentRowIdx = currentRowIdx;
90
92
  forceUpdate();
91
- }, [forceUpdate, getColumnCellValue, getArticleStyle, validEditor]);
93
+ }, [forceUpdate, getColumnCellValue, getArticleStyle, validEditor, currentRowIdx]);
92
94
  return /*#__PURE__*/_react.default.createElement(_errorBoundary.default, null, !isReadOnly && /*#__PURE__*/_react.default.createElement(_hooks.PluginsProvider, {
93
95
  plugins: [],
94
96
  showComment: false
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ class ImageCache {
8
+ constructor() {
9
+ this.imageCache = null;
10
+ }
11
+ static saveImage(key, item) {
12
+ if (!this.imageCache) {
13
+ this.imageCache = new Map();
14
+ }
15
+ this.imageCache.set(key, item);
16
+ }
17
+ static getImage(key) {
18
+ if (!this.imageCache) {
19
+ this.imageCache = new Map();
20
+ }
21
+ return this.imageCache.get(key);
22
+ }
23
+ static deleteImage(key) {
24
+ if (!this.imageCache) {
25
+ this.imageCache = new Map();
26
+ }
27
+ this.imageCache.delete(key);
28
+ }
29
+ }
30
+ var _default = exports.default = ImageCache;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seafile/sdoc-editor",
3
- "version": "2.0.41",
3
+ "version": "2.0.43",
4
4
  "private": false,
5
5
  "description": "This is a sdoc editor",
6
6
  "main": "dist/index.js",
@@ -626,5 +626,6 @@
626
626
  "Insert_chart": "Insert chart",
627
627
  "Edit_chart": "Edit chart",
628
628
  "Please_complete_the_chart_configuration_first": "Please complete the chart configuration first",
629
- "chart": "chart"
629
+ "chart": "chart",
630
+ "Image_is_upload_error": "Image upload failed, please delete it and try again"
630
631
  }
@@ -622,5 +622,7 @@
622
622
  "Double_click_then_adjust_field_width": "双击后调节字段宽度",
623
623
  "Insert_chart": "插入图表",
624
624
  "Edit_chart": "编辑图表",
625
- "Please_complete_the_chart_configuration_first": "请先完成图表配置"
625
+ "Please_complete_the_chart_configuration_first": "请先完成图表配置",
626
+ "chart": "图表",
627
+ "Image_is_upload_error": "图片上传失败,请删除后重新尝试"
626
628
  }