@seafile/sdoc-editor 2.0.1 → 2.0.3

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.
Files changed (22) hide show
  1. package/dist/basic-sdk/assets/css/sdoc-editor-plugins.css +0 -23
  2. package/dist/basic-sdk/extension/commons/search-list/index.css +28 -0
  3. package/dist/basic-sdk/extension/commons/search-list/index.js +148 -0
  4. package/dist/basic-sdk/extension/plugins/font/helpers.js +7 -0
  5. package/dist/basic-sdk/extension/plugins/header/render-elem.js +2 -1
  6. package/dist/basic-sdk/extension/plugins/image/helpers.js +9 -21
  7. package/dist/basic-sdk/extension/plugins/image/image-loader/index.css +37 -0
  8. package/dist/basic-sdk/extension/plugins/image/image-loader/index.js +23 -0
  9. package/dist/basic-sdk/extension/plugins/image/render-elem.js +24 -76
  10. package/dist/basic-sdk/extension/plugins/image/use-upload-image.js +80 -0
  11. package/dist/basic-sdk/extension/plugins/multi-column/plugin.js +1 -1
  12. package/dist/basic-sdk/extension/plugins/seatable-column/menu/column-list-item.js +36 -0
  13. package/dist/basic-sdk/extension/plugins/seatable-column/menu/column-list-menu.css +4 -2
  14. package/dist/basic-sdk/extension/plugins/seatable-column/menu/column-list-menu.js +8 -13
  15. package/dist/basic-sdk/extension/plugins/seatable-column/plugin.js +9 -1
  16. package/dist/basic-sdk/extension/plugins/seatable-column/render-elem.js +71 -7
  17. package/dist/basic-sdk/extension/plugins/text-style/helpers.js +1 -1
  18. package/dist/basic-sdk/extension/plugins/text-style/menu/index.js +10 -1
  19. package/dist/basic-sdk/extension/toolbar/side-toolbar/helpers.js +2 -1
  20. package/package.json +2 -2
  21. package/public/locales/en/sdoc-editor.json +2 -1
  22. package/public/locales/zh_CN/sdoc-editor.json +2 -1
@@ -94,29 +94,6 @@
94
94
  pointer-events: none;
95
95
  }
96
96
 
97
- .sdoc-editor__article .sdoc-image-process-container {
98
- width: 40px;
99
- height: 40px;
100
- display: flex;
101
- align-items: center;
102
- }
103
-
104
- .sdoc-editor__article .sdoc-image-process-container .loading-spinner {
105
- border: 5px solid #d8d8d8;
106
- border-top: 5px solid #939393;
107
- border-radius: 50%;
108
- width: 30px;
109
- height: 30px;
110
- animation: spin 1s linear infinite;
111
- user-select: none;
112
- pointer-events: none;
113
- }
114
-
115
- @keyframes spin {
116
- 0% { transform: rotate(0deg); }
117
- 100% { transform: rotate(360deg); }
118
- }
119
-
120
97
  .sdoc-editor__article .sdoc-image-inner {
121
98
  position: relative;
122
99
  display: inline-block;
@@ -0,0 +1,28 @@
1
+ .sdoc-search-list {
2
+ display: flex;
3
+ height: 100%;
4
+ width: 100%;
5
+ flex-direction: column;
6
+ }
7
+
8
+ .sdoc-search-list .sdoc-search-list-wrapper {
9
+ padding: 12px;
10
+ }
11
+
12
+ .sdoc-search-list .sdoc-search-list-wrapper>input {
13
+ font-size: 12px;
14
+ max-height: 30px;
15
+ }
16
+
17
+ .sdoc-search-list .sdoc-search-list-content-wrapper {
18
+ min-height: 0;
19
+ min-width: 0;
20
+ flex: 1;
21
+ overflow: auto;
22
+ max-height: 300px;
23
+ }
24
+
25
+ .sdoc-search-list .sdoc-search-list-with-no-results {
26
+ font-size: 12px;
27
+ padding: 4px 16px;
28
+ }
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = SearchList;
9
+ var _react = _interopRequireWildcard(require("react"));
10
+ var _reactI18next = require("react-i18next");
11
+ var _reactstrap = require("reactstrap");
12
+ var _keyCodes = _interopRequireDefault(require("../../../../constants/key-codes"));
13
+ require("./index.css");
14
+ function SearchList(_ref) {
15
+ let {
16
+ list: originalList,
17
+ listItem: ListItem,
18
+ onListItemClick,
19
+ onEscClick
20
+ } = _ref;
21
+ const {
22
+ t
23
+ } = (0, _reactI18next.useTranslation)('sdoc-editor');
24
+ const inputWrapperRef = (0, _react.useRef)(null);
25
+ const isComposingRef = (0, _react.useRef)(null);
26
+ const listRefs = (0, _react.useRef)([]);
27
+ const [searchedList, setSearchedList] = (0, _react.useState)(originalList);
28
+ const [currentSelectIndex, setCurrentSelectIndex] = (0, _react.useState)(-1);
29
+
30
+ // search input
31
+ const onChange = (0, _react.useCallback)(event => {
32
+ if (isComposingRef.current) return;
33
+ const value = event.target.value.trim();
34
+ if (value) {
35
+ const list = originalList.filter(item => item.label.indexOf(value) > -1);
36
+ setSearchedList(list);
37
+ } else {
38
+ setSearchedList(originalList);
39
+ }
40
+ }, [originalList]);
41
+ const onCompositionStart = (0, _react.useCallback)(() => {
42
+ isComposingRef.current = true;
43
+ }, []);
44
+ const onCompositionEnd = (0, _react.useCallback)(e => {
45
+ isComposingRef.current = false;
46
+ onChange(e);
47
+ }, [onChange]);
48
+
49
+ // search content list
50
+ const onItemClick = (0, _react.useCallback)(item => {
51
+ onListItemClick && onListItemClick(item);
52
+ }, [onListItemClick]);
53
+ const onHandleInputFocus = (0, _react.useCallback)(isFocus => {
54
+ if (inputWrapperRef.current) {
55
+ queueMicrotask(() => {
56
+ isFocus ? inputWrapperRef.current.focus() : inputWrapperRef.current.blur();
57
+ });
58
+ }
59
+ }, []);
60
+ (0, _react.useEffect)(() => {
61
+ if (currentSelectIndex === -1) {
62
+ onHandleInputFocus(true);
63
+ } else {
64
+ onHandleInputFocus(false);
65
+ }
66
+ }, [currentSelectIndex, onHandleInputFocus]);
67
+ const handleClick = (0, _react.useCallback)(event => {
68
+ if (inputWrapperRef !== null && inputWrapperRef !== void 0 && inputWrapperRef.current.contains(event.target) || inputWrapperRef.current === event.target) {
69
+ event.stopPropagation();
70
+ event.nativeEvent && event.nativeEvent.stopImmediatePropagation && event.nativeEvent.stopImmediatePropagation();
71
+ return;
72
+ }
73
+ }, []);
74
+ const scrollIntoView = (0, _react.useCallback)(index => {
75
+ listRefs.current[index].scrollIntoView({
76
+ behavior: 'smooth',
77
+ block: 'center',
78
+ inline: 'nearest'
79
+ });
80
+ }, []);
81
+ const handleKeyDown = (0, _react.useCallback)(e => {
82
+ const {
83
+ UpArrow,
84
+ DownArrow,
85
+ Enter,
86
+ Esc
87
+ } = _keyCodes.default;
88
+ const {
89
+ keyCode
90
+ } = e;
91
+ if (keyCode === UpArrow) {
92
+ e.preventDefault();
93
+ if (currentSelectIndex > -1) {
94
+ setCurrentSelectIndex(currentSelectIndex - 1);
95
+ scrollIntoView(currentSelectIndex - 1);
96
+ }
97
+ }
98
+ if (keyCode === DownArrow) {
99
+ e.preventDefault();
100
+ if (currentSelectIndex === searchedList.length - 1) return;
101
+ if (currentSelectIndex < searchedList.length - 1) {
102
+ setCurrentSelectIndex(currentSelectIndex + 1);
103
+ scrollIntoView(currentSelectIndex + 1);
104
+ }
105
+ }
106
+ if (keyCode === Enter) {
107
+ e.preventDefault();
108
+ const item = searchedList[currentSelectIndex];
109
+ onItemClick(item);
110
+ }
111
+ if (keyCode === Esc) {
112
+ e.preventDefault();
113
+ onEscClick && onEscClick();
114
+ }
115
+ }, [currentSelectIndex, onEscClick, onItemClick, scrollIntoView, searchedList]);
116
+ (0, _react.useEffect)(() => {
117
+ document.addEventListener('mousedown', handleClick);
118
+ document.addEventListener('keydown', handleKeyDown);
119
+ return () => {
120
+ document.removeEventListener('keydown', handleKeyDown);
121
+ document.removeEventListener('click', handleClick);
122
+ };
123
+ }, [handleClick, handleKeyDown]);
124
+ return /*#__PURE__*/_react.default.createElement("div", {
125
+ className: "sdoc-search-list"
126
+ }, /*#__PURE__*/_react.default.createElement("div", {
127
+ className: "sdoc-search-list-wrapper"
128
+ }, /*#__PURE__*/_react.default.createElement(_reactstrap.Input, {
129
+ innerRef: inputWrapperRef,
130
+ placeholder: t('Search_action'),
131
+ onChange: onChange,
132
+ onCompositionStart: onCompositionStart,
133
+ onCompositionEnd: onCompositionEnd
134
+ })), /*#__PURE__*/_react.default.createElement("div", {
135
+ className: "sdoc-search-list-content-wrapper"
136
+ }, searchedList.length === 0 && /*#__PURE__*/_react.default.createElement("div", {
137
+ className: "sdoc-search-list-with-no-results"
138
+ }, t('No_results')), searchedList.map((item, index) => {
139
+ const isSelected = index === currentSelectIndex;
140
+ return /*#__PURE__*/_react.default.createElement(ListItem, {
141
+ innerRef: el => listRefs.current[index] = el,
142
+ key: index,
143
+ item: item,
144
+ onItemClick: onItemClick,
145
+ isSelected: isSelected
146
+ });
147
+ })));
148
+ }
@@ -52,6 +52,13 @@ const getFontSize = editor => {
52
52
  }
53
53
  return false;
54
54
  }
55
+ if (!_slate.Editor.isEditor(n) && _slate.Editor.isVoid(editor, n)) {
56
+ const parentNode = (0, _core.getParentNode)(editor.children, n.id);
57
+ if (!parentNode) return false;
58
+ if ([_constants.TITLE, _constants.SUBTITLE, ..._constants.HEADERS, _constants.CODE_LINE].includes(parentNode.type)) {
59
+ return true;
60
+ }
61
+ }
55
62
  return false;
56
63
  }
57
64
  });
@@ -9,6 +9,7 @@ var _react = _interopRequireDefault(require("react"));
9
9
  var _slate = require("@seafile/slate");
10
10
  var _core = require("../../core");
11
11
  var _constants = require("../../constants");
12
+ var _helper = require("../paragraph/helper");
12
13
  const renderTitle = (props, editor) => {
13
14
  const {
14
15
  element,
@@ -69,7 +70,7 @@ const renderHeader = (props, editor) => {
69
70
  })
70
71
  };
71
72
  let isShowPlaceHolder = false;
72
- if (_slate.Node.string(element) === '' && !isComposing) {
73
+ if ((0, _helper.isEmptyNode)(element) && _slate.Node.string(element) === '' && !isComposing) {
73
74
  isShowPlaceHolder = true;
74
75
  }
75
76
  return /*#__PURE__*/_react.default.createElement("div", Object.assign({
@@ -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.updateImageNode = exports.updateImage = exports.selectImageWhenSelectPartial = exports.resetCursor = exports.queryCopyMoveProgressView = exports.isInsertImageMenuDisabled = 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.queryCopyMoveProgressView = exports.isInsertImageMenuDisabled = exports.isImagUrlIsFromCopy = exports.insertImageFiles = exports.insertImage = exports.hasSdocImages = exports.handleBase64Image = exports.getSingleImageFromFragment = exports.getImageURL = exports.getImageData = exports.generateImageNode = 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");
@@ -133,24 +133,6 @@ const updateImage = (editor, data) => {
133
133
  });
134
134
  };
135
135
  exports.updateImage = updateImage;
136
- const updateImageNode = (editor, originalUrl, newUrl) => {
137
- _slate.Editor.nodes(editor, {
138
- match: n => n.type === _constants2.IMAGE && n.data.src === originalUrl,
139
- at: []
140
- }).forEach(_ref => {
141
- let [node, path] = _ref;
142
- const newData = {
143
- ...node.data,
144
- src: newUrl
145
- };
146
- _slate.Transforms.setNodes(editor, {
147
- data: newData
148
- }, {
149
- at: path
150
- });
151
- });
152
- };
153
- exports.updateImageNode = updateImageNode;
154
136
  const getImageURL = (data, editor) => {
155
137
  const {
156
138
  src: url,
@@ -171,7 +153,7 @@ const getImageURL = (data, editor) => {
171
153
  return imgUrl;
172
154
  }
173
155
  }
174
- if (url && url.startsWith('http')) return url;
156
+ if (isImagUrlIsFromCopy(url)) return url;
175
157
  const serviceUrl = _context.default.getSetting('serviceUrl');
176
158
  const assetsUrl = _context.default.getSetting('assetsUrl');
177
159
  return (0, _urlJoin.default)(serviceUrl, assetsUrl, url);
@@ -295,4 +277,10 @@ const handleBase64Image = (editor, path, imgData) => {
295
277
  });
296
278
  });
297
279
  };
298
- exports.handleBase64Image = handleBase64Image;
280
+ exports.handleBase64Image = handleBase64Image;
281
+ const isImagUrlIsFromCopy = url => {
282
+ if (url && url.startsWith('http')) return true;
283
+ if (url && url.startsWith('attachment')) return true; // from yuque
284
+ return false;
285
+ };
286
+ exports.isImagUrlIsFromCopy = isImagUrlIsFromCopy;
@@ -0,0 +1,37 @@
1
+ .sdoc-image-process-container {
2
+ position: absolute;
3
+ width: 100%;
4
+ height: 100%;
5
+ display: flex;
6
+ flex-direction: column;
7
+ align-items: center;
8
+ justify-content: center;
9
+ top: 0;
10
+ left: 0;
11
+ background-color: 'rgba(0, 0, 0, 0.5)'
12
+ }
13
+
14
+ @keyframes spin {
15
+ 0% {
16
+ transform: rotate(0deg);
17
+ }
18
+
19
+ 100% {
20
+ transform: rotate(360deg);
21
+ }
22
+ }
23
+
24
+ .sdoc-image-process-container .loading-spinner {
25
+ border: 3px solid #d8d8d8;
26
+ border-top: 3px solid #939393;
27
+ border-radius: 50%;
28
+ width: 20px;
29
+ height: 20px;
30
+ animation: spin 1s linear infinite;
31
+ user-select: none;
32
+ pointer-events: none;
33
+ }
34
+
35
+ .sdoc-image-process-container .copyright {
36
+ margin-top: 4px;
37
+ }
@@ -0,0 +1,23 @@
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 = ImageLoader;
8
+ var _react = _interopRequireDefault(require("react"));
9
+ require("./index.css");
10
+ function ImageLoader(_ref) {
11
+ let {
12
+ copyright
13
+ } = _ref;
14
+ return /*#__PURE__*/_react.default.createElement("div", {
15
+ className: "sdoc-image-process-container"
16
+ }, /*#__PURE__*/_react.default.createElement("div", {
17
+ className: "loading-spinner"
18
+ }, /*#__PURE__*/_react.default.createElement("div", {
19
+ className: "spinner"
20
+ })), copyright && /*#__PURE__*/_react.default.createElement("div", {
21
+ className: "copyright"
22
+ }, copyright));
23
+ }
@@ -21,8 +21,9 @@ var _constants2 = require("./constants");
21
21
  var _constants3 = require("../../constants");
22
22
  var _constants4 = require("../../../../constants");
23
23
  var _imagePlaceholder = _interopRequireDefault(require("../../../assets/images/image-placeholder.png"));
24
- var _context = _interopRequireDefault(require("../../../../context"));
25
24
  var _copyImageErrorSvg = _interopRequireDefault(require("../../../../components/copy-image-error-svg"));
25
+ var _useUploadImage = _interopRequireDefault(require("./use-upload-image"));
26
+ var _imageLoader = _interopRequireDefault(require("./image-loader"));
26
27
  const Image = _ref => {
27
28
  var _imageRef$current, _imageRef$current2;
28
29
  let {
@@ -52,7 +53,6 @@ const Image = _ref => {
52
53
  const imageRef = (0, _react.useRef)(null);
53
54
  const resizerRef = (0, _react.useRef)(null);
54
55
  const imageCaptionInputRef = (0, _react.useRef)(null);
55
- const isLoadingRef = (0, _react.useRef)(false);
56
56
  const scrollRef = (0, _useScrollContext.useScrollContext)();
57
57
  const [movingWidth, setMovingWidth] = (0, _react.useState)(null);
58
58
  const [isResizing, setIsResizing] = (0, _react.useState)(false);
@@ -60,8 +60,14 @@ const Image = _ref => {
60
60
  const [isShowImageHoverMenu, setIsShowImageHoverMenu] = (0, _react.useState)(false);
61
61
  const [menuPosition, setMenuPosition] = (0, _react.useState)({});
62
62
  const [caption, setCaption] = (0, _react.useState)((data === null || data === void 0 ? void 0 : data.caption) || '');
63
- const [isLoading, setIsLoading] = (0, _react.useState)(false);
64
- const [isCopyError, setIsCopyError] = (0, _react.useState)(false);
63
+ const {
64
+ isCopyImageLoading,
65
+ isCopyImageError,
66
+ setCopyImageLoading
67
+ } = (0, _useUploadImage.default)({
68
+ editor,
69
+ element
70
+ });
65
71
  const registerEvent = (0, _react.useCallback)(eventList => {
66
72
  eventList.forEach(element => {
67
73
  document.addEventListener(element.eventName, element.event);
@@ -202,20 +208,16 @@ const Image = _ref => {
202
208
  setIsShowImagePlaceholder(false);
203
209
  }
204
210
  }, [data, editor]);
211
+ const onImageLoaded = (0, _react.useCallback)(() => {
212
+ if ((0, _helpers.isImagUrlIsFromCopy)(data.src)) {
213
+ setCopyImageLoading(true);
214
+ }
215
+ }, [data.src, setCopyImageLoading]);
205
216
  const onImageLoadError = (0, _react.useCallback)(() => {
206
217
  // Check is due to the image is pasted from the clipboard in base64
207
218
  if (data.src.startsWith('data:image/jpeg;base64')) {
208
219
  return (0, _helpers.handleBase64Image)(editor, path, data);
209
220
  }
210
-
211
- // Check whether copying images is wrong
212
- if (data.src.startsWith('attachment') || data.src.endsWith('_copy_error')) {
213
- if (!isCopyError) {
214
- setIsCopyError(true);
215
- }
216
- return;
217
- }
218
- if (isLoadingRef.current) return;
219
221
  setIsShowImagePlaceholder(true);
220
222
  // External network images do not reload after failure to load
221
223
  if (!data.src.startsWith('http')) {
@@ -238,66 +240,7 @@ const Image = _ref => {
238
240
  });
239
241
  }
240
242
  }, [data, editor, element]);
241
- (0, _react.useEffect)(() => {
242
- isLoadingRef.current = isLoading;
243
- if (data.src.endsWith('_copy_error') && !isCopyError) {
244
- setIsCopyError(true);
245
- }
246
- // eslint-disable-next-line react-hooks/exhaustive-deps
247
- }, [isLoading, data.src]);
248
- (0, _react.useEffect)(() => {
249
- const {
250
- src: url
251
- } = data;
252
- if (url && !url.startsWith('http')) return;
253
- if (url && url.endsWith('_copy_error')) {
254
- setIsCopyError(true);
255
- return;
256
- }
257
- // Return if copying image from local server
258
- const serviceUrl = _context.default.getSetting('serviceUrl');
259
- if (url && url.startsWith(serviceUrl)) return;
260
- if (url && url.startsWith('http')) {
261
- setIsLoading(true);
262
- const downloadAndUploadImages = async url => {
263
- try {
264
- const response = await fetch(url);
265
- if (response.ok) {
266
- const blob = await response.blob();
267
- const file = new File([blob], 'downloaded_image.png', {
268
- type: blob.type
269
- });
270
- const imageUrl = await _context.default.uploadLocalImage([file]);
271
- if (imageUrl && imageUrl[0]) {
272
- (0, _helpers.updateImageNode)(editor, url, imageUrl[0]);
273
- }
274
- } else {
275
- console.error(response.status);
276
- const newUrl = url + '_copy_error';
277
- (0, _helpers.updateImageNode)(editor, url, newUrl);
278
- }
279
- } catch (error) {
280
- console.error(error);
281
- const newUrl = url + '_copy_error';
282
- (0, _helpers.updateImageNode)(editor, url, newUrl);
283
- } finally {
284
- setIsLoading(false);
285
- }
286
- };
287
- downloadAndUploadImages(url);
288
- }
289
- // eslint-disable-next-line react-hooks/exhaustive-deps
290
- }, []);
291
- return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, isLoading && /*#__PURE__*/_react.default.createElement("div", {
292
- className: "sdoc-image-process-container",
293
- style: {
294
- display: 'inline-block'
295
- }
296
- }, /*#__PURE__*/_react.default.createElement("div", {
297
- className: "loading-spinner"
298
- }, /*#__PURE__*/_react.default.createElement("div", {
299
- className: "spinner"
300
- }))), isShowImagePlaceholder && /*#__PURE__*/_react.default.createElement("span", Object.assign({
243
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, isShowImagePlaceholder && /*#__PURE__*/_react.default.createElement("span", Object.assign({
301
244
  className: (0, _classnames.default)('sdoc-image-wrapper', className)
302
245
  }, attributes, {
303
246
  style: {
@@ -305,6 +248,7 @@ const Image = _ref => {
305
248
  },
306
249
  onMouseOver: e => (0, _helpers.selectImageWhenSelectPartial)(e, editor, element, isSelected),
307
250
  contentEditable: "false",
251
+ "data-src": (0, _helpers.getImageURL)(data, editor),
308
252
  suppressContentEditableWarning: true
309
253
  }), /*#__PURE__*/_react.default.createElement("img", {
310
254
  ref: imageRef,
@@ -312,7 +256,7 @@ const Image = _ref => {
312
256
  style: getImageStyle(),
313
257
  draggable: false,
314
258
  alt: ""
315
- }), children), isCopyError && /*#__PURE__*/_react.default.createElement("span", Object.assign({
259
+ }), children), isCopyImageError && /*#__PURE__*/_react.default.createElement("span", Object.assign({
316
260
  className: (0, _classnames.default)('sdoc-image-wrapper', className)
317
261
  }, attributes, {
318
262
  style: {
@@ -320,12 +264,13 @@ const Image = _ref => {
320
264
  },
321
265
  onMouseOver: e => (0, _helpers.selectImageWhenSelectPartial)(e, editor, element, isSelected),
322
266
  contentEditable: "false",
267
+ "data-src": data.src,
323
268
  suppressContentEditableWarning: true
324
269
  }), /*#__PURE__*/_react.default.createElement(_copyImageErrorSvg.default, {
325
270
  t: t,
326
271
  isSelected: isSelected,
327
272
  imageRef: imageRef
328
- }), children), !isShowImagePlaceholder && !isCopyError && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("span", Object.assign({
273
+ }), children), !isShowImagePlaceholder && !isCopyImageError && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("span", Object.assign({
329
274
  "data-id": element.id,
330
275
  className: (0, _classnames.default)('sdoc-image-wrapper', className)
331
276
  }, attributes, {
@@ -342,16 +287,19 @@ const Image = _ref => {
342
287
  }, /*#__PURE__*/_react.default.createElement("span", {
343
288
  style: imageStyle
344
289
  }, /*#__PURE__*/_react.default.createElement("img", {
290
+ ref: imageRef,
345
291
  className: (0, _classnames.default)({
346
292
  'image-selected': isSelected
347
293
  }),
348
294
  onClick: onClickImage,
349
- ref: imageRef,
350
295
  src: (0, _helpers.getImageURL)(data, editor),
351
296
  style: getImageStyle(),
352
297
  draggable: false,
298
+ onLoad: onImageLoaded,
353
299
  onError: onImageLoadError,
354
300
  alt: ""
301
+ }), isCopyImageLoading && /*#__PURE__*/_react.default.createElement(_imageLoader.default, {
302
+ copyright: t('Image_is_uploading')
355
303
  }), isSelected && /*#__PURE__*/_react.default.createElement("span", {
356
304
  className: "image-resizer",
357
305
  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 useImageUpload = _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)(false);
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.isImagUrlIsFromCopy)(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 = useImageUpload;
@@ -82,7 +82,7 @@ const withMultiColumn = editor => {
82
82
  const nextNode = _slate.Editor.next(newEditor);
83
83
  const nextColumnIndex = nextNode[1][1];
84
84
  const currentMultiColumnEntry = (0, _core.getSelectedNodeEntryByType)(editor, _constants.ELEMENT_TYPE.MULTI_COLUMN);
85
- if (!currentMultiColumnEntry) return deleteBackward(unit);
85
+ if (!currentMultiColumnEntry) return deleteForward(unit);
86
86
  const {
87
87
  column,
88
88
  children: childColumn
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+
3
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
4
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = ColumnListItem;
9
+ var _classnames = _interopRequireDefault(require("classnames"));
10
+ var _react = _interopRequireWildcard(require("react"));
11
+ function ColumnListItem(_ref) {
12
+ let {
13
+ innerRef,
14
+ item,
15
+ onItemClick,
16
+ isSelected
17
+ } = _ref;
18
+ const onMouseDown = (0, _react.useCallback)(() => {
19
+ onItemClick(item);
20
+ }, [onItemClick, item]);
21
+ const clazzNames = (0, _classnames.default)('column-list-menu-item-container', {
22
+ 'selected': isSelected
23
+ });
24
+ return /*#__PURE__*/_react.default.createElement("div", {
25
+ ref: innerRef,
26
+ key: item.value,
27
+ className: clazzNames,
28
+ onClick: onMouseDown
29
+ }, /*#__PURE__*/_react.default.createElement("div", {
30
+ className: "column-list-menu-item"
31
+ }, /*#__PURE__*/_react.default.createElement("span", {
32
+ className: `control-icon ${item.iconClass}`
33
+ }), /*#__PURE__*/_react.default.createElement("span", {
34
+ className: "control-label"
35
+ }, item.label)));
36
+ }
@@ -8,8 +8,6 @@
8
8
  background-color: #fff;
9
9
  min-width: 12rem;
10
10
  width: 200px;
11
- max-height: 300px;
12
- overflow: auto;
13
11
  padding: 8px 0;
14
12
  }
15
13
 
@@ -46,3 +44,7 @@
46
44
  background-color: #f5f5f5;
47
45
  cursor: pointer;
48
46
  }
47
+
48
+ .column-list-menu .column-list-menu-item-container.selected {
49
+ background-color: #e3e3e3;
50
+ }
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
3
4
  var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
4
5
  Object.defineProperty(exports, "__esModule", {
5
6
  value: true
@@ -10,6 +11,8 @@ var _column = require("../constants/column");
10
11
  var _helpers = require("../helpers");
11
12
  var _elementType = require("../../../constants/element-type");
12
13
  var _utils = require("../../../utils");
14
+ var _searchList = _interopRequireDefault(require("../../../commons/search-list"));
15
+ var _columnListItem = _interopRequireDefault(require("./column-list-item"));
13
16
  require("./column-list-menu.css");
14
17
  const NOT_SUPPORT_COLUMN_TYPES = ['button', 'file'];
15
18
  function ColumnListMenu(_ref) {
@@ -51,7 +54,7 @@ function ColumnListMenu(_ref) {
51
54
  const isActive = editor => {
52
55
  return (0, _helpers.getColumnType)(editor) === _elementType.SEATABLE_COLUMN;
53
56
  };
54
- const onMousedown = (0, _react.useCallback)(option => {
57
+ const onListItemClick = (0, _react.useCallback)(option => {
55
58
  const active = isActive(editor);
56
59
  (0, _helpers.insertSeaTableColumn)(editor, active, option, insertPosition);
57
60
  toggle && toggle();
@@ -60,17 +63,9 @@ function ColumnListMenu(_ref) {
60
63
  ref: columnRef,
61
64
  className: "column-list-menu",
62
65
  style: computedStyle
63
- }, options.map(option => {
64
- return /*#__PURE__*/_react.default.createElement("div", {
65
- key: option.value,
66
- className: "column-list-menu-item-container",
67
- onClick: () => onMousedown(option)
68
- }, /*#__PURE__*/_react.default.createElement("div", {
69
- className: "column-list-menu-item"
70
- }, /*#__PURE__*/_react.default.createElement("span", {
71
- className: `control-icon ${option.iconClass}`
72
- }), /*#__PURE__*/_react.default.createElement("span", {
73
- className: "control-label"
74
- }, option.label)));
66
+ }, /*#__PURE__*/_react.default.createElement(_searchList.default, {
67
+ list: options,
68
+ listItem: _columnListItem.default,
69
+ onListItemClick: onListItemClick
75
70
  }));
76
71
  }
@@ -8,7 +8,8 @@ var _constants = require("../../constants");
8
8
  const withColumn = editor => {
9
9
  const {
10
10
  isInline,
11
- isVoid
11
+ isVoid,
12
+ markableVoid
12
13
  } = editor;
13
14
  const newEditor = editor;
14
15
  newEditor.isInline = element => {
@@ -25,6 +26,13 @@ const withColumn = editor => {
25
26
  if (type === _constants.ELEMENT_TYPE.SEATABLE_COLUMN) return true;
26
27
  return isVoid(element);
27
28
  };
29
+ newEditor.markableVoid = element => {
30
+ const {
31
+ type
32
+ } = element;
33
+ if (type === _constants.ELEMENT_TYPE.SEATABLE_COLUMN) return true;
34
+ return markableVoid(element);
35
+ };
28
36
  return newEditor;
29
37
  };
30
38
  var _default = exports.default = withColumn;
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
3
4
  var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
4
5
  Object.defineProperty(exports, "__esModule", {
5
6
  value: true
@@ -7,6 +8,7 @@ Object.defineProperty(exports, "__esModule", {
7
8
  exports.default = void 0;
8
9
  var _react = _interopRequireWildcard(require("react"));
9
10
  var _slateReact = require("@seafile/slate-react");
11
+ var _mdToHtml = _interopRequireDefault(require("../../../../slate-convert/md-to-html"));
10
12
  const Column = _ref => {
11
13
  let {
12
14
  props,
@@ -19,15 +21,34 @@ const Column = _ref => {
19
21
  } = props;
20
22
  const isReadOnly = (0, _slateReact.useReadOnly)();
21
23
  const isSelected = (0, _slateReact.useSelected)();
24
+ const [columnValue, setColumnValue] = (0, _react.useState)('');
22
25
  const data = element.data || {};
23
26
  const {
24
- key: columnKey,
25
- name: columnName
27
+ key: columnKey
26
28
  } = data;
27
- let displayValue = columnName ? `{${columnName}}` : '';
28
- if (editor.getColumnCellValue) {
29
- displayValue = editor.getColumnCellValue(columnKey) || 'null';
30
- }
29
+ const column = editor.columns.find(item => item.key === columnKey);
30
+ const isLongTextColumn = (0, _react.useMemo)(() => {
31
+ return column && column.type === 'long-text';
32
+ }, [column]);
33
+ (0, _react.useEffect)(() => {
34
+ const data = element.data || {};
35
+ const {
36
+ key: columnKey,
37
+ name: columnName
38
+ } = data;
39
+ let displayValue = columnName ? `{${columnName}}` : '';
40
+ if (editor.getColumnCellValue) {
41
+ displayValue = editor.getColumnCellValue(columnKey) || 'null';
42
+ if (!isLongTextColumn) {
43
+ setColumnValue(displayValue);
44
+ return;
45
+ }
46
+ _mdToHtml.default.process(displayValue).then(res => {
47
+ displayValue = String(res);
48
+ setColumnValue(displayValue);
49
+ });
50
+ }
51
+ }, [editor, element.data, isLongTextColumn]);
31
52
  const [isClicked, setIsClicked] = (0, _react.useState)(false);
32
53
  (0, _react.useEffect)(() => {
33
54
  if (isSelected && !isReadOnly) {
@@ -36,16 +57,59 @@ const Column = _ref => {
36
57
  setIsClicked(false);
37
58
  }
38
59
  }, [isSelected, isReadOnly]);
60
+ const {
61
+ font_size = null,
62
+ font = null,
63
+ bold = null,
64
+ italic = null,
65
+ underline = null,
66
+ color = null,
67
+ highlight_color = null,
68
+ strikethrough = null
69
+ } = element.children[0];
39
70
  const style = {
40
71
  margin: '0 10px',
41
72
  border: '1px solid transparent',
73
+ userSelect: 'none',
74
+ display: 'inline-block',
42
75
  ...(isClicked && {
43
76
  border: '1px solid red'
77
+ }),
78
+ ...(font_size && {
79
+ fontSize: font_size
80
+ }),
81
+ ...(font && {
82
+ fontFamily: font
83
+ }),
84
+ ...(bold && {
85
+ fontWeight: 600
86
+ }),
87
+ ...(italic && {
88
+ fontStyle: 'italic'
89
+ }),
90
+ ...(underline && {
91
+ textDecoration: 'underline'
92
+ }),
93
+ ...(color && {
94
+ color: color
95
+ }),
96
+ ...(highlight_color && {
97
+ backgroundColor: highlight_color
98
+ }),
99
+ ...(strikethrough && {
100
+ textDecoration: 'line-through'
44
101
  })
45
102
  };
46
103
  return /*#__PURE__*/_react.default.createElement("span", Object.assign({}, attributes, {
47
104
  style: style
48
- }), displayValue, children);
105
+ }), !isLongTextColumn && columnValue, isLongTextColumn && /*#__PURE__*/_react.default.createElement("div", {
106
+ style: {
107
+ padding: '10px'
108
+ },
109
+ dangerouslySetInnerHTML: {
110
+ __html: columnValue
111
+ }
112
+ }), children);
49
113
  };
50
114
  const renderColumn = (props, editor) => {
51
115
  return /*#__PURE__*/_react.default.createElement(Column, {
@@ -16,7 +16,7 @@ const isMenuDisabled = (editor, readonly) => {
16
16
  match: n => {
17
17
  const type = (0, _core.getNodeType)(n);
18
18
  if (type === _elementType.CODE_BLOCK) return true; // Code block
19
- if (_slate.Editor.isVoid(editor, n)) return true; // void node
19
+ if (_slate.Editor.isVoid(editor, n) && (n === null || n === void 0 ? void 0 : n.type) !== _elementType.SEATABLE_COLUMN) return true; // void node
20
20
 
21
21
  return false;
22
22
  },
@@ -49,6 +49,10 @@ const TextStyleMenuList = _ref => {
49
49
  return (0, _helpers2.isMenuDisabled)(editor, readonly);
50
50
  // eslint-disable-next-line react-hooks/exhaustive-deps
51
51
  }, [editor, readonly]);
52
+ const isSelectedSeaTableColumn = (0, _react.useCallback)(() => {
53
+ const entery = (0, _core.getSelectedNodeByType)(editor, _constants.SEATABLE_COLUMN);
54
+ return !!entery;
55
+ }, [editor]);
52
56
  const openLinkDialog = (0, _react.useCallback)(() => {
53
57
  const eventBus = _eventBus.default.getInstance();
54
58
  eventBus.dispatch(_constants2.INTERNAL_EVENT.INSERT_ELEMENT, {
@@ -99,11 +103,16 @@ const TextStyleMenuList = _ref => {
99
103
  }, [editor, selectedFontSize, selectedFontSizeValue]);
100
104
  const getTextStyleList = (0, _react.useCallback)(key => {
101
105
  return _constants.MENUS_CONFIG_MAP[key].map(item => {
106
+ let disable = isDisabled();
107
+ const disableTypes = [_constants.TEXT_STYLE_MAP.CODE, _constants.TEXT_STYLE_MAP.LINK, _constants.TEXT_STYLE_MAP.SUPERSCRIPT, _constants.TEXT_STYLE_MAP.SUBSCRIPT];
108
+ if (disableTypes.includes(item.type)) {
109
+ disable = isSelectedSeaTableColumn() ? true : disable;
110
+ }
102
111
  let itemProps = {
103
112
  isRichEditor,
104
113
  className,
105
114
  ariaLabel: item === null || item === void 0 ? void 0 : item.ariaLabel,
106
- disabled: isDisabled(),
115
+ disabled: disable,
107
116
  isActive: isActive(item.type),
108
117
  onMouseDown: item.isColor ? () => {} : onMouseDown
109
118
  };
@@ -134,7 +134,8 @@ const isVoidNode = node => {
134
134
  const isCodeBlock = node.type === _constants.CODE_BLOCK;
135
135
  const isCallout = node.type === _constants.CALL_OUT;
136
136
  const isSeaTableTable = node.type === _constants.SEATABLE_TABLE;
137
- return _slate.Node.string(node) === '' && !hasImage && !isVideo && !isTable && !isCodeBlock && !isCallout && !isSeaTableTable;
137
+ const isSeaTableColumn = node.type === _constants.SEATABLE_COLUMN;
138
+ return _slate.Node.string(node) === '' && !hasImage && !isVideo && !isTable && !isCodeBlock && !isCallout && !isSeaTableTable && !isSeaTableColumn;
138
139
  };
139
140
  exports.isVoidNode = isVoidNode;
140
141
  const isNotSupportTransform = node => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seafile/sdoc-editor",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "private": false,
5
5
  "description": "This is a sdoc editor",
6
6
  "main": "dist/index.js",
@@ -16,7 +16,7 @@
16
16
  "copy-to-clipboard": "^3.3.3",
17
17
  "dayjs": "1.10.7",
18
18
  "deep-copy": "1.4.2",
19
- "dtable-ui-component": "^5.1.9",
19
+ "dtable-ui-component": "6.0.0",
20
20
  "is-hotkey": "0.2.0",
21
21
  "is-url": "^1.2.4",
22
22
  "lodash.isequal": "4.5.0",
@@ -613,5 +613,6 @@
613
613
  "Support_Youtube_Tencent_Bilibili_and_more": "Support Youtube, Tencent, Bilibili and more",
614
614
  "Image_cannot_be_copied_Please_download_the_source_image": "Image cannot be copied. Please download the source image,",
615
615
  "And_select_insert_-_image_to_upload": "and select 「insert」 - 「image」 to upload.",
616
- "Image_copy_error": "Image copy error"
616
+ "Image_copy_error": "Image copy error",
617
+ "Image_is_uploading": "Image is uploading..."
617
618
  }
@@ -613,5 +613,6 @@
613
613
  "Support_Youtube_Tencent_Bilibili_and_more": "支持Youtube,腾讯视频,B站及其他平台",
614
614
  "Image_cannot_be_copied_Please_download_the_source_image": "此照片不支持复制,请下载原图",
615
615
  "And_select_insert_-_image_to_upload": "后点击工具栏「插入」- 「照片」上传",
616
- "Image_copy_error": "图片复制错误"
616
+ "Image_copy_error": "图片复制错误",
617
+ "Image_is_uploading": "图片正在上传..."
617
618
  }