@seafile/sdoc-editor 0.5.41 → 0.5.42

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 (24) hide show
  1. package/dist/basic-sdk/constants/index.js +2 -1
  2. package/dist/basic-sdk/editor/comment-article.js +2 -1
  3. package/dist/basic-sdk/editor/editable-article.js +1 -0
  4. package/dist/basic-sdk/extension/commons/{history-files → file-insert-dialog}/index.js +115 -95
  5. package/dist/basic-sdk/extension/commons/file-insert-dialog/style.css +76 -0
  6. package/dist/basic-sdk/extension/commons/insert-element-dialog/index.js +9 -8
  7. package/dist/basic-sdk/extension/commons/menu-shortcut-indicator/style.css +5 -7
  8. package/dist/basic-sdk/extension/constants/element-type.js +1 -0
  9. package/dist/basic-sdk/extension/constants/index.js +2 -2
  10. package/dist/basic-sdk/extension/plugins/code-block/hover-menu/index.css +9 -0
  11. package/dist/basic-sdk/extension/plugins/code-block/hover-menu/index.js +41 -24
  12. package/dist/basic-sdk/extension/plugins/sdoc-link/helpers.js +62 -13
  13. package/dist/basic-sdk/extension/plugins/sdoc-link/index.js +3 -2
  14. package/dist/basic-sdk/extension/plugins/sdoc-link/plugin.js +33 -23
  15. package/dist/basic-sdk/extension/plugins/sdoc-link/{render-elem.css → render/render-elem.css} +5 -1
  16. package/dist/basic-sdk/extension/plugins/sdoc-link/{render-elem.js → render/render-elem.js} +6 -6
  17. package/dist/basic-sdk/extension/plugins/sdoc-link/render/render-file-link-temp-input.js +26 -0
  18. package/dist/basic-sdk/extension/render/custom-element.js +6 -1
  19. package/dist/components/doc-operations/more-operations.js +13 -10
  20. package/dist/components/doc-operations/style.css +15 -0
  21. package/package.json +1 -1
  22. package/public/locales/en/sdoc-editor.json +3 -1
  23. package/public/locales/zh_CN/sdoc-editor.json +3 -1
  24. package/dist/basic-sdk/extension/commons/history-files/index.css +0 -70
@@ -24,7 +24,8 @@ export const INTERNAL_EVENT = {
24
24
  TABLE_SHOW_DRAG_HANDLER: 'table_show_drag_handler',
25
25
  TABLE_HIDE_DRAG_HANDLER: 'table_show_drag_handler',
26
26
  ON_PRINT: 'on_print',
27
- COMMENT_EDITOR_POST_COMMENT: 'comment_editor_post_comment'
27
+ COMMENT_EDITOR_POST_COMMENT: 'comment_editor_post_comment',
28
+ CLOSE_FILE_INSET_DIALOG: 'close_file_insert_dialog'
28
29
  };
29
30
  export const REVISION_DIFF_KEY = 'diff';
30
31
  export const REVISION_DIFF_VALUE = '1';
@@ -85,7 +85,8 @@ const CommentArticle = _ref => {
85
85
  onCompositionStart: eventProxy.onCompositionStart,
86
86
  onCompositionUpdate: eventProxy.onCompositionUpdate,
87
87
  onCompositionEnd: eventProxy.onCompositionEnd,
88
- onKeyDown: onKeyDown
88
+ onKeyDown: onKeyDown,
89
+ onBeforeInput: eventProxy.onBeforeInput
89
90
  }));
90
91
  };
91
92
  export default CommentArticle;
@@ -178,6 +178,7 @@ const EditableArticle = _ref => {
178
178
  decorate: decorate,
179
179
  onCut: eventProxy.onCut,
180
180
  onCopy: eventProxy.onCopy,
181
+ onCompositionStart: eventProxy.onCompositionStart,
181
182
  id: "sdoc-editor"
182
183
  })), /*#__PURE__*/React.createElement(SideToolbar, null), isShowComment && /*#__PURE__*/React.createElement(CommentWrapper, {
183
184
  editor: editor,
@@ -1,33 +1,42 @@
1
1
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
- import React, { useCallback, useEffect, useState, useRef } from 'react';
3
- import { Editor } from '@seafile/slate';
2
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
4
3
  import { ReactEditor } from '@seafile/slate-react';
5
- import { withTranslation } from 'react-i18next';
4
+ import { useTranslation } from 'react-i18next';
5
+ import { Editor } from '@seafile/slate';
6
6
  import classNames from 'classnames';
7
- import debounce from 'lodash.debounce';
8
- import toaster from '../../../../components/toast';
9
- import EventBus from '../../../utils/event-bus';
10
7
  import context from '../../../../context';
11
- import { focusEditor } from '../../core';
12
- import { insertSdocFileLink } from '../../plugins/sdoc-link/helpers';
13
8
  import { LocalStorage, isEnglish } from '../../../../utils';
14
- import { INTERNAL_EVENT } from '../../../constants';
15
9
  import { EXTERNAL_EVENT } from '../../../../constants';
10
+ import EventBus from '../../../utils/event-bus';
11
+ import { INTERNAL_EVENT } from '../../../constants';
16
12
  import { SDOC_LINK } from '../../constants';
17
- import './index.css';
18
- const HistoryFiles = _ref => {
13
+ import toaster from '../../../../components/toast';
14
+ import { insertSdocFileLink, insertTextWhenRemoveFileNameCollector, removeTempInput } from '../../plugins/sdoc-link/helpers';
15
+ import './style.css';
16
+ const FileLinkInsertDialog = _ref => {
19
17
  let {
20
18
  editor,
21
- insertLinkCallback,
22
- closeDialog,
23
- t
19
+ element,
20
+ closeDialog
24
21
  } = _ref;
25
- const historyFilesRef = useRef();
26
- const historyFilesInputRef = useRef();
22
+ const eventBus = EventBus.getInstance();
23
+ const historyFileWrapperRef = useRef(document.querySelector('.sdoc-history-files-wrapper'));
27
24
  const [files, setFiles] = useState([]);
28
- const [position, setPosition] = useState({});
29
- const [header, setHeader] = useState(t('Recent_visited'));
25
+ const [position, setPosition] = useState({
26
+ top: 0,
27
+ left: 0
28
+ });
30
29
  const [newFileName, setNewFileName] = useState('');
30
+ const {
31
+ t
32
+ } = useTranslation();
33
+ const [header, setHeader] = useState(t('Recent_visited'));
34
+ const deleteInputAndInsertText = useCallback(function () {
35
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
36
+ args[_key] = arguments[_key];
37
+ }
38
+ return insertTextWhenRemoveFileNameCollector(editor, element, ...args);
39
+ }, [editor, element]);
31
40
  const getPosition = useCallback(() => {
32
41
  const {
33
42
  selection
@@ -35,80 +44,95 @@ const HistoryFiles = _ref => {
35
44
  const nodeEntry = Editor.node(editor, selection);
36
45
  const domNode = ReactEditor.toDOMNode(editor, nodeEntry[0]);
37
46
  if (domNode) {
47
+ const topGap = 20;
48
+ const leftGap = 5;
38
49
  const {
39
50
  top,
40
- right
51
+ left
41
52
  } = domNode.getBoundingClientRect();
53
+ let popoverTop = top + topGap;
54
+ let popoverLeft = left + leftGap;
55
+ // Insert gap between the popover and the selected node
56
+ // file item height 32px, header height 32px, add button height 32px, margin-top 8px, max-height 306px
57
+ const popoverHeight = Math.min(files.length * 32 + 32 * 3 + 8, 300);
58
+ // Insert gap between the popover and the selected node
59
+ const popoverBottomY = top + popoverHeight + topGap;
60
+ const viewportHeight = window.innerHeight;
61
+ if (popoverBottomY > viewportHeight) {
62
+ // 8px for the gap between the popover and the bottom of the viewport
63
+ const counterTopGap = 8;
64
+ popoverTop = top - popoverHeight - counterTopGap;
65
+ }
42
66
  setPosition({
43
- left: right + 5,
44
- top: top + 20
67
+ top: popoverTop,
68
+ left: popoverLeft
45
69
  });
46
70
  }
47
71
  // eslint-disable-next-line react-hooks/exhaustive-deps
48
- }, []);
72
+ }, [files]);
49
73
  const onClick = useCallback(e => {
50
- if (historyFilesRef.current.contains(e.target)) return;
74
+ var _historyFileWrapperRe, _historyFileWrapperRe2;
75
+ const isClickInside = (_historyFileWrapperRe = historyFileWrapperRef.current) === null || _historyFileWrapperRe === void 0 ? void 0 : (_historyFileWrapperRe2 = _historyFileWrapperRe.contains) === null || _historyFileWrapperRe2 === void 0 ? void 0 : _historyFileWrapperRe2.call(_historyFileWrapperRe, e.target);
76
+ if (isClickInside) return;
77
+ deleteInputAndInsertText();
51
78
  closeDialog();
52
- // eslint-disable-next-line react-hooks/exhaustive-deps
53
- }, []);
79
+ }, [closeDialog, deleteInputAndInsertText]);
54
80
  const onScroll = useCallback(e => {
55
81
  getPosition();
56
- // eslint-disable-next-line react-hooks/exhaustive-deps
57
- }, []);
82
+ }, [getPosition]);
58
83
  const getHistoryFiles = useCallback(e => {
59
84
  const files = LocalStorage.getItem('sdoc-recent-files') || [];
60
85
  setFiles(files);
61
86
  }, []);
62
- const onInsertLink = useCallback(params => {
87
+ useEffect(() => {
88
+ getHistoryFiles();
89
+ }, [getHistoryFiles]);
90
+ const onKeydown = useCallback(e => {
63
91
  const {
64
- insertSdocFileLinkCallback
65
- } = insertLinkCallback;
66
- insertSdocFileLinkCallback(editor, params.data.obj_name, params.data.doc_uuid);
67
- closeDialog();
68
- }, [closeDialog, editor, insertLinkCallback]);
92
+ key
93
+ } = e;
94
+ switch (key) {
95
+ case 'Escape':
96
+ deleteInputAndInsertText();
97
+ closeDialog();
98
+ break;
99
+ case 'ArrowRight':
100
+ case 'ArrowLeft':
101
+ deleteInputAndInsertText();
102
+ closeDialog();
103
+ break;
104
+ case 'ArrowUp':
105
+ case 'ArrowDown':
106
+ deleteInputAndInsertText();
107
+ closeDialog();
108
+ break;
109
+ default:
110
+ break;
111
+ }
112
+ }, [closeDialog, deleteInputAndInsertText]);
113
+ const onInsertLink = useCallback(params => {
114
+ insertSdocFileLink(editor, params.data.obj_name, params.data.doc_uuid);
115
+ removeTempInput();
116
+ }, [editor]);
69
117
  useEffect(() => {
70
118
  getPosition();
71
- getHistoryFiles();
72
- setTimeout(() => {
73
- historyFilesInputRef.current.focus();
74
- }, 0);
75
119
  const sdocScrollContainer = document.getElementById('sdoc-scroll-container');
120
+ document.addEventListener('click', onClick);
121
+ document.addEventListener('keydown', onKeydown);
76
122
  sdocScrollContainer.addEventListener('scroll', onScroll);
77
- const eventBus = EventBus.getInstance();
78
123
  const unsubscribeInsertLink = eventBus.subscribe(EXTERNAL_EVENT.INSERT_LINK, onInsertLink);
79
- document.addEventListener('click', onClick);
124
+ const unsubscribeCloseDialog = eventBus.subscribe(INTERNAL_EVENT.CLOSE_FILE_INSET_DIALOG, closeDialog);
80
125
  return () => {
81
126
  sdocScrollContainer.removeEventListener('scroll', onScroll);
82
- unsubscribeInsertLink();
83
127
  document.removeEventListener('click', onClick);
128
+ document.removeEventListener('keydown', onKeydown);
129
+ unsubscribeInsertLink();
130
+ unsubscribeCloseDialog();
84
131
  };
85
- // eslint-disable-next-line react-hooks/exhaustive-deps
86
- }, []);
87
- const onKeydown = useCallback(e => {
88
- const {
89
- key,
90
- target
91
- } = e;
92
- if (key === 'Backspace' && !target.selectionStart && !target.selectionEnd && !target.value) {
93
- focusEditor(editor);
94
- closeDialog();
95
- }
96
- }, [closeDialog, editor]);
97
- const onCompositionStart = e => {
98
- e.stopPropagation();
99
- historyFilesInputRef.current.typing = true;
100
- };
101
- const onCompositionEnd = e => {
102
- e.stopPropagation();
103
- historyFilesInputRef.current.typing = false;
104
- onSearch(e);
105
- };
106
- const onSearch = useCallback(async e => {
107
- // Ignore when entering Chinese
108
- if (historyFilesInputRef.current.typing) return;
109
-
132
+ }, [closeDialog, editor, eventBus, files, getPosition, onClick, onInsertLink, onKeydown, onScroll]);
133
+ const onSearch = useCallback(async searchText => {
110
134
  // Show history files when search is empty
111
- if (e.target.value.trim().length === 0) {
135
+ if (searchText.trim().length === 0) {
112
136
  setHeader(t('Recent_visited'));
113
137
  setNewFileName('');
114
138
  getHistoryFiles();
@@ -116,20 +140,20 @@ const HistoryFiles = _ref => {
116
140
  }
117
141
 
118
142
  // Cannot be found if the search is less than three characters.
119
- if (isEnglish(e.target.value.trim()) && e.target.value.length < 3) {
143
+ if (isEnglish(searchText.trim()) && searchText.length < 3) {
120
144
  setFiles([]);
121
- setHeader(t('The_document_does_not_exist'));
122
- setNewFileName(e.target.value);
145
+ setHeader(t('Enter_more_character_start_search'));
146
+ setNewFileName(searchText);
123
147
  return;
124
148
  }
125
149
  try {
126
150
  var _res$data;
127
- const res = await context.searchSdocFiles(e.target.value, 1, 10);
151
+ const res = await context.searchSdocFiles(searchText, 1, 10);
128
152
  if (res === null || res === void 0 ? void 0 : (_res$data = res.data) === null || _res$data === void 0 ? void 0 : _res$data.results) {
129
153
  let newFiles = res.data.results;
130
154
  if (newFiles.length === 0) {
131
155
  setHeader(t('The_document_does_not_exist'));
132
- setNewFileName(e.target.value);
156
+ setNewFileName(searchText);
133
157
  } else {
134
158
  setHeader('');
135
159
  setNewFileName('');
@@ -142,25 +166,27 @@ const HistoryFiles = _ref => {
142
166
  }
143
167
  // eslint-disable-next-line react-hooks/exhaustive-deps
144
168
  }, []);
169
+ useEffect(() => {
170
+ if (!(element === null || element === void 0 ? void 0 : element.children)) return;
171
+ const searchText = element.children[0].text;
172
+ onSearch(searchText);
173
+ }, [element, onSearch]);
145
174
  const onSelect = useCallback(fileInfo => {
146
175
  const {
147
176
  doc_uuid,
148
177
  name
149
178
  } = fileInfo;
150
- const {
151
- insertSdocFileLinkCallback
152
- } = insertLinkCallback;
153
- insertSdocFileLinkCallback(editor, name, doc_uuid);
179
+ removeTempInput(editor, element);
154
180
  closeDialog();
155
- // eslint-disable-next-line react-hooks/exhaustive-deps
156
- }, []);
181
+ insertSdocFileLink(editor, name, doc_uuid);
182
+ }, [closeDialog, editor, element]);
157
183
  const onShowMore = useCallback(() => {
158
- const eventBus = EventBus.getInstance();
159
184
  eventBus.dispatch(INTERNAL_EVENT.INSERT_ELEMENT, {
160
185
  type: SDOC_LINK,
161
186
  insertSdocFileLinkCallback: insertSdocFileLink
162
187
  });
163
- }, []);
188
+ removeTempInput(editor, element);
189
+ }, [editor, element, eventBus]);
164
190
  const onCreateFile = useCallback(() => {
165
191
  const eventBus = EventBus.getInstance();
166
192
  eventBus.dispatch(EXTERNAL_EVENT.CREATE_SDOC_FILE, {
@@ -168,20 +194,10 @@ const HistoryFiles = _ref => {
168
194
  });
169
195
  }, [newFileName]);
170
196
  return /*#__PURE__*/React.createElement("div", {
171
- ref: historyFilesRef,
172
- className: "sdoc-history-files-wrapper popover",
173
- style: _objectSpread({}, position)
174
- }, /*#__PURE__*/React.createElement("input", {
175
- id: "sdoc-history-files-search-input",
176
- className: "sdoc-history-files-search-input",
177
- ref: historyFilesInputRef,
178
- autoComplete: "off",
179
- onChange: debounce(onSearch, 200),
180
- onCompositionStart: onCompositionStart,
181
- onCompositionEnd: onCompositionEnd,
182
- onKeyDown: onKeydown
183
- }), /*#__PURE__*/React.createElement("div", {
184
- className: "sdoc-history-files-content"
197
+ className: "sdoc-history-files-content popover",
198
+ style: _objectSpread(_objectSpread({}, position), {}, {
199
+ position: 'absolute'
200
+ })
185
201
  }, header.length !== 0 && /*#__PURE__*/React.createElement("div", {
186
202
  className: "sdoc-history-files-header"
187
203
  }, header), /*#__PURE__*/React.createElement("div", {
@@ -206,6 +222,10 @@ const HistoryFiles = _ref => {
206
222
  onClick: onCreateFile
207
223
  }, /*#__PURE__*/React.createElement("i", {
208
224
  className: "sdocfont sdoc-append"
209
- }), /*#__PURE__*/React.createElement("span", null, newFileName ? t("Create ".concat(newFileName, ".sdoc")) : t('Create_a_new_sdoc_file')))));
225
+ }), /*#__PURE__*/React.createElement("span", {
226
+ className: "new-file-name"
227
+ }, newFileName ? t('Create_file_name_sdoc', {
228
+ file_name_sdoc: "".concat(newFileName, ".sdoc")
229
+ }) : t('Create_a_new_sdoc_file'))));
210
230
  };
211
- export default withTranslation('sdoc-editor')(HistoryFiles);
231
+ export default FileLinkInsertDialog;
@@ -0,0 +1,76 @@
1
+ .sdoc-history-files-content {
2
+ display: flex;
3
+ flex-direction: column;
4
+ position: absolute;
5
+ width: 400px;
6
+ max-height: 300px;
7
+ /* The same as hierarchy of comment drawer */
8
+ z-index: 103;
9
+ box-shadow: 0 1px 3px rgba(0, 0, 0, .15), 0 4px 8px 3px rgba(0, 0, 0, .15);
10
+ }
11
+
12
+ .sdoc-history-files-content .sdoc-history-files-header {
13
+ display: flex;
14
+ flex-shrink: 0;
15
+ align-items: center;
16
+ margin-top: 8px;
17
+ padding: 0px 16px;
18
+ height: 32px;
19
+ width: 100%;
20
+ color: #999999;
21
+ font-size: 14px;
22
+ user-select: none;
23
+ cursor: default;
24
+ }
25
+
26
+ .sdoc-history-files-content .sdoc-history-files {
27
+ flex-grow: 1;
28
+ overflow-y: auto;
29
+ cursor: pointer;
30
+ }
31
+
32
+ .sdoc-history-files-content .no-header {
33
+ margin-top: 8px;
34
+ width: 100%;
35
+ }
36
+
37
+ .sdoc-history-files-content .sdoc-history-files .sdoc-history-files-item {
38
+ padding: 0px 16px;
39
+ height: 32px;
40
+ line-height: 32px;
41
+ text-overflow: ellipsis;
42
+ font-size: 14px;
43
+ white-space: nowrap;
44
+ }
45
+
46
+ .sdoc-history-files-content .sdoc-history-files .sdoc-history-files-item :first-child {
47
+ font-size: 12px;
48
+ margin-right: 5px;
49
+ }
50
+
51
+ .sdoc-history-files-content .sdoc-history-files .sdoc-history-files-item:hover {
52
+ background-color: #f5f5f5;
53
+ }
54
+
55
+ .sdoc-history-files-content .sdoc-history-files-add {
56
+ display: flex;
57
+ flex-shrink: 0;
58
+ align-items: center;
59
+ padding: 0px 16px;
60
+ height: 32px;
61
+ width: 100%;
62
+ border-top: 1px solid #e9ecef;
63
+ font-size: 14px;
64
+ cursor: pointer;
65
+ }
66
+
67
+ .sdoc-history-files-content .sdoc-history-files-add :first-child {
68
+ color: #444444;
69
+ margin-right: 10px;
70
+ }
71
+
72
+ .sdoc-history-files-content .sdoc-history-files-add .new-file-name {
73
+ text-wrap: nowrap;
74
+ text-overflow: ellipsis;
75
+ overflow: hidden;
76
+ }
@@ -2,12 +2,12 @@ import React, { useCallback, useEffect, useState, useRef } from 'react';
2
2
  import { CustomTableSizeDialog, SplitCellSettingDialog } from '../../plugins/table/dialogs';
3
3
  import AddLinkDialog from '../../plugins/link/dialog/add-link-dialog';
4
4
  import SelectFileDialog from '../select-file-dialog/index.js';
5
- import HistoryFiles from '../history-files';
6
5
  import EventBus from '../../../utils/event-bus';
7
6
  import { INTERNAL_EVENT } from '../../../constants';
8
7
  import { ELEMENT_TYPE, INSERT_POSITION, LOCAL_IMAGE } from '../../constants';
9
8
  import { insertImage } from '../../plugins/image/helpers';
10
9
  import context from '../../../../context.js';
10
+ import FileLinkInsertDialog from '../file-insert-dialog/index.js';
11
11
  const InsertElementDialog = _ref => {
12
12
  let {
13
13
  editor
@@ -17,7 +17,6 @@ const InsertElementDialog = _ref => {
17
17
  const [insertPosition, setInsertPosition] = useState(INSERT_POSITION.CURRENT);
18
18
  const [slateNode, setSlateNode] = useState(null);
19
19
  const [insertLinkCallback, setInsertLinkCallback] = useState(null);
20
- const [isShowHistoryFiles, setIsShowHistoryFiles] = useState(false);
21
20
  const [validEditor, setValidEditor] = useState(editor);
22
21
  const uploadLocalImageInputRef = useRef();
23
22
  const onFileChanged = useCallback(event => {
@@ -46,7 +45,6 @@ const InsertElementDialog = _ref => {
46
45
  slateNode,
47
46
  insertFileLinkCallback,
48
47
  insertSdocFileLinkCallback,
49
- isShowHistoryFiles,
50
48
  editor: paramEditor
51
49
  } = _ref2;
52
50
  setInsertPosition(insertPosition);
@@ -57,7 +55,6 @@ const InsertElementDialog = _ref => {
57
55
  insertSdocFileLinkCallback,
58
56
  insertFileLinkCallback
59
57
  });
60
- setIsShowHistoryFiles(isShowHistoryFiles);
61
58
  // Apply for comment editor, as it has a different editor instance
62
59
  setValidEditor(paramEditor || editor);
63
60
  if (type === LOCAL_IMAGE) {
@@ -72,7 +69,6 @@ const InsertElementDialog = _ref => {
72
69
  setElement('');
73
70
  setDialogType('');
74
71
  setInsertLinkCallback(null);
75
- setIsShowHistoryFiles(false);
76
72
  setValidEditor(null);
77
73
  }, []);
78
74
  const props = {
@@ -103,9 +99,6 @@ const InsertElementDialog = _ref => {
103
99
  insertLinkCallback,
104
100
  closeDialog
105
101
  };
106
- if (isShowHistoryFiles) {
107
- return /*#__PURE__*/React.createElement(HistoryFiles, sdocLinkProps);
108
- }
109
102
  return /*#__PURE__*/React.createElement(SelectFileDialog, sdocLinkProps);
110
103
  }
111
104
  case ELEMENT_TYPE.FILE_LINK:
@@ -132,6 +125,14 @@ const InsertElementDialog = _ref => {
132
125
  onChange: onFileChanged
133
126
  });
134
127
  }
128
+ case ELEMENT_TYPE.FILE_LINK_INSET_INPUT_TEMP:
129
+ {
130
+ return /*#__PURE__*/React.createElement(FileLinkInsertDialog, {
131
+ element: slateNode,
132
+ editor: editor,
133
+ closeDialog: closeDialog
134
+ });
135
+ }
135
136
  default:
136
137
  {
137
138
  return null;
@@ -5,16 +5,14 @@
5
5
  margin-right: 1px;
6
6
  padding: 1px 3px;
7
7
  min-width: 12px;
8
- border-style: solid;
9
- border-color: rgba(0, 0, 0, 0.1);
10
- border-radius: 3px;
11
- border-width: 1px 1px 2px;
8
+ border: none;
12
9
  font: inherit;
13
10
  text-align: center;
14
- color: rgb(51, 51, 51);
15
- background-color: rgba(255, 255, 255, 0.25);
11
+ color: #999;
12
+ background-color: transparent;
16
13
  }
17
14
 
18
- .sdoc-shortcut-prompt-container:last-child {
15
+ .sdoc-shortcut-prompt-container kbd:last-child {
19
16
  margin-right: 0px;
17
+ padding-right: 0px;
20
18
  }
@@ -26,6 +26,7 @@ export const IMAGE_BLOCK = 'image_block';
26
26
  export const CALL_OUT = 'callout';
27
27
  export const MENTION = 'mention';
28
28
  export const MENTION_TEMP = 'mention_temp';
29
+ export const FILE_LINK_INSET_INPUT_TEMP = 'file_link_insert_input_temp';
29
30
 
30
31
  // font
31
32
  export const FONT_SIZE = 'font-size';
@@ -1,7 +1,7 @@
1
1
  // extension plugin
2
2
  import * as ELEMENT_TYPE from './element-type';
3
3
  // eslint-disable-next-line no-duplicate-imports
4
- import { BLOCKQUOTE, TITLE, SUBTITLE, HEADER, HEADER1, HEADER2, HEADER3, HEADER4, HEADER5, HEADER6, PARAGRAPH, ORDERED_LIST, UNORDERED_LIST, LIST_ITEM, CHECK_LIST_ITEM, CODE_BLOCK, CODE_LINE, TABLE, TABLE_CELL, TABLE_ROW, LINK, SDOC_LINK, FILE_LINK, IMAGE, IMAGE_BLOCK, TOP_LEVEL_TYPES, INLINE_LEVEL_TYPES, CALL_OUT, MENTION, MENTION_TEMP } from './element-type';
4
+ import { BLOCKQUOTE, TITLE, SUBTITLE, HEADER, HEADER1, HEADER2, HEADER3, HEADER4, HEADER5, HEADER6, PARAGRAPH, ORDERED_LIST, UNORDERED_LIST, LIST_ITEM, CHECK_LIST_ITEM, CODE_BLOCK, CODE_LINE, TABLE, TABLE_CELL, TABLE_ROW, LINK, SDOC_LINK, FILE_LINK, IMAGE, IMAGE_BLOCK, TOP_LEVEL_TYPES, INLINE_LEVEL_TYPES, CALL_OUT, MENTION, MENTION_TEMP, FILE_LINK_INSET_INPUT_TEMP } from './element-type';
5
5
  export { DEFAULT_COLORS, STANDARD_COLORS, DEFAULT_RECENT_USED_LIST, DEFAULT_FONT_COLOR, RECENT_USED_HIGHLIGHT_COLORS_KEY, RECENT_USED_FONT_COLORS_KEY, RECENT_USED_TABLE_CELL_BACKGROUND_COLORS_KEY, DEFAULT_LAST_USED_FONT_COLOR, DEFAULT_LAST_USED_HIGHLIGHT_COLOR, DEFAULT_LAST_USED_TABLE_CELL_BACKGROUND_COLOR } from './color';
6
6
  export { FONT_SIZE, DEFAULT_FONT, FONT, GOOGLE_FONT_CLASS, RECENT_USED_FONTS_KEY, SDOC_FONT_SIZE } from './font';
7
7
  export { DIFF_TYPE, ADDED_STYLE, DELETED_STYLE } from './diff-view';
@@ -57,4 +57,4 @@ export const MOUSE_ENTER_EVENT_DISABLED_MAP = {
57
57
  [CALL_OUT]: [CALL_OUT]
58
58
  };
59
59
  export const ROOT_ELEMENT_TYPES = [PARAGRAPH, TITLE, SUBTITLE, CHECK_LIST_ITEM, ORDERED_LIST, UNORDERED_LIST, BLOCKQUOTE, HEADER1, HEADER2, HEADER3, HEADER4, HEADER5, HEADER6, CALL_OUT, TABLE];
60
- export { ELEMENT_TYPE, BLOCKQUOTE, TITLE, SUBTITLE, HEADER, HEADER1, HEADER2, HEADER3, HEADER4, HEADER5, HEADER6, PARAGRAPH, ORDERED_LIST, UNORDERED_LIST, LIST_ITEM, CHECK_LIST_ITEM, CODE_BLOCK, CODE_LINE, TABLE, TABLE_CELL, TABLE_ROW, LINK, SDOC_LINK, FILE_LINK, IMAGE, IMAGE_BLOCK, TOP_LEVEL_TYPES, INLINE_LEVEL_TYPES, CALL_OUT, MENTION, MENTION_TEMP };
60
+ export { ELEMENT_TYPE, BLOCKQUOTE, TITLE, SUBTITLE, HEADER, HEADER1, HEADER2, HEADER3, HEADER4, HEADER5, HEADER6, PARAGRAPH, ORDERED_LIST, UNORDERED_LIST, LIST_ITEM, CHECK_LIST_ITEM, CODE_BLOCK, CODE_LINE, TABLE, TABLE_CELL, TABLE_ROW, LINK, SDOC_LINK, FILE_LINK, IMAGE, IMAGE_BLOCK, TOP_LEVEL_TYPES, INLINE_LEVEL_TYPES, CALL_OUT, MENTION, MENTION_TEMP, FILE_LINK_INSET_INPUT_TEMP };
@@ -101,6 +101,15 @@
101
101
  font-size: 14px;
102
102
  }
103
103
 
104
+ .langs-list-empty {
105
+ padding: 10px;
106
+ width: 100%;
107
+ font-size: 13px;
108
+ text-align: center;
109
+ line-height: 30px;
110
+ vertical-align: middle;
111
+ }
112
+
104
113
  .sdoc-langs-list-container .langs-list-ul {
105
114
  list-style: none;
106
115
  overflow-y: auto;
@@ -1,12 +1,43 @@
1
- import React, { useCallback, useEffect, useState } from 'react';
1
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
2
2
  import { Input } from 'reactstrap';
3
- import { withTranslation } from 'react-i18next';
3
+ import { useTranslation, withTranslation } from 'react-i18next';
4
4
  import Tooltip from '../../../../../components/tooltip';
5
5
  import { ElementPopover } from '../../../commons/';
6
6
  import { genCodeLangs } from '../prismjs';
7
7
  import { getSelectedLangOption } from '../helpers';
8
8
  import './index.css';
9
- const CodeBlockHoverMenu = _ref => {
9
+ const LangList = _ref => {
10
+ let {
11
+ langsData,
12
+ onSelectLang,
13
+ selectedLanguageText
14
+ } = _ref;
15
+ const {
16
+ t
17
+ } = useTranslation();
18
+ if (!langsData.length) {
19
+ return /*#__PURE__*/React.createElement("div", {
20
+ className: "langs-list-empty"
21
+ }, /*#__PURE__*/React.createElement("span", null, t('Search_not_found')));
22
+ }
23
+ return /*#__PURE__*/React.createElement("ul", {
24
+ className: "langs-list-ul"
25
+ }, langsData.map(item => {
26
+ return /*#__PURE__*/React.createElement("li", {
27
+ className: "langs-list-li ".concat(selectedLanguageText === item.text ? 'active' : ''),
28
+ id: item.value,
29
+ key: item.value,
30
+ onClick: () => {
31
+ onSelectLang(item);
32
+ }
33
+ }, item.text, /*#__PURE__*/React.createElement("span", {
34
+ className: "li-check-mark ".concat(selectedLanguageText === item.text ? 'li-checked' : '')
35
+ }, /*#__PURE__*/React.createElement("i", {
36
+ className: "sdocfont sdoc-check-mark icon-font"
37
+ })));
38
+ }));
39
+ };
40
+ const CodeBlockHoverMenu = _ref2 => {
10
41
  let {
11
42
  style,
12
43
  language,
@@ -16,7 +47,7 @@ const CodeBlockHoverMenu = _ref => {
16
47
  onCopyCodeBlock,
17
48
  onDeleteCodeBlock,
18
49
  t
19
- } = _ref;
50
+ } = _ref2;
20
51
  const {
21
52
  white_space = 'nowrap'
22
53
  } = style;
@@ -74,15 +105,12 @@ const CodeBlockHoverMenu = _ref => {
74
105
  }, [language]);
75
106
  const onChange = useCallback(e => {
76
107
  const filterData = [];
77
- const restData = [];
78
108
  genCodeLangs().forEach(item => {
79
109
  if (item.value.startsWith(e.currentTarget.value.toLowerCase())) {
80
110
  filterData.push(item);
81
- } else {
82
- restData.push(item);
83
111
  }
84
112
  });
85
- setLangsData([...filterData, ...restData]);
113
+ setLangsData(filterData);
86
114
  // eslint-disable-next-line react-hooks/exhaustive-deps
87
115
  }, []);
88
116
  return /*#__PURE__*/React.createElement(ElementPopover, null, /*#__PURE__*/React.createElement("div", {
@@ -150,21 +178,10 @@ const CodeBlockHoverMenu = _ref => {
150
178
  }, /*#__PURE__*/React.createElement(Input, {
151
179
  placeholder: t('Search_language'),
152
180
  onChange: onChange
153
- })), /*#__PURE__*/React.createElement("ul", {
154
- className: "langs-list-ul"
155
- }, langsData.map(item => {
156
- return /*#__PURE__*/React.createElement("li", {
157
- className: "langs-list-li ".concat(selectedLanguageText === item.text ? 'active' : ''),
158
- id: item.value,
159
- key: item.value,
160
- onClick: () => {
161
- onSelectLang(item);
162
- }
163
- }, item.text, /*#__PURE__*/React.createElement("span", {
164
- className: "li-check-mark ".concat(selectedLanguageText === item.text ? 'li-checked' : '')
165
- }, /*#__PURE__*/React.createElement("i", {
166
- className: "sdocfont sdoc-check-mark icon-font"
167
- })));
168
- }))))));
181
+ })), /*#__PURE__*/React.createElement(LangList, {
182
+ langsData: langsData,
183
+ onSelectLang: onSelectLang,
184
+ selectedLanguageText: selectedLanguageText
185
+ })))));
169
186
  };
170
187
  export default withTranslation('sdoc-editor')(CodeBlockHoverMenu);
@@ -1,11 +1,11 @@
1
1
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
2
  import { ReactEditor } from '@seafile/slate-react';
3
- import { Editor, Transforms, Range, Text } from '@seafile/slate';
3
+ import { Editor, Transforms, Range, Text, Path, Node } from '@seafile/slate';
4
4
  import slugid from 'slugid';
5
5
  import copy from 'copy-to-clipboard';
6
6
  import context from '../../../../context';
7
- import { focusEditor, getNodeType, getSelectedElems } from '../../core';
8
- import { SDOC_LINK, LINK, INSERT_FILE_DISPLAY_TYPE, CODE_BLOCK, CODE_LINE, PARAGRAPH } from '../../constants';
7
+ import { focusEditor, generateEmptyElement, getNodeType, getSelectedElems } from '../../core';
8
+ import { SDOC_LINK, LINK, INSERT_FILE_DISPLAY_TYPE, CODE_BLOCK, CODE_LINE, PARAGRAPH, FILE_LINK_INSET_INPUT_TEMP } from '../../constants';
9
9
  export const isMenuDisabled = (editor, readonly) => {
10
10
  if (readonly) return true;
11
11
  if (editor.selection == null) return true;
@@ -149,17 +149,13 @@ export const getBeforeText = editor => {
149
149
  range
150
150
  };
151
151
  };
152
- export const isTriggeredByShortCut = editor => {
153
- const {
154
- selection
155
- } = editor;
156
- const {
157
- anchor
158
- } = selection;
152
+ export const isTriggeredByShortcut = editor => {
159
153
  const {
160
154
  beforeText
161
155
  } = getBeforeText(editor);
162
- return beforeText.slice(-1) === '[' && Editor.isEnd(editor, anchor, anchor.path);
156
+ const fileSearchInput = getFileSearchInputEntry(editor);
157
+ if (fileSearchInput) return false;
158
+ return beforeText.endsWith('[');
163
159
  };
164
160
 
165
161
  // If insert operation is triggered by shortcut, remove the '[[' symbol
@@ -172,8 +168,8 @@ export const removeShortCutSymbol = editor => {
172
168
  beforeText,
173
169
  range: beforeRange
174
170
  } = getBeforeText(editor);
175
- const isTrrigeredByShortCut = beforeText.slice(-2) === '[[';
176
- isTrrigeredByShortCut && Transforms.delete(editor, {
171
+ const isTriggeredByShortCut = beforeText.slice(-2) === '[[';
172
+ isTriggeredByShortCut && Transforms.delete(editor, {
177
173
  at: {
178
174
  anchor: {
179
175
  path: beforeRange.focus.path,
@@ -184,4 +180,57 @@ export const removeShortCutSymbol = editor => {
184
180
  voids: true
185
181
  });
186
182
  focusEditor(editor);
183
+ };
184
+
185
+ // Generate temp input for collecting file name
186
+ const generateFileLinkInput = () => {
187
+ const input = generateEmptyElement(FILE_LINK_INSET_INPUT_TEMP);
188
+ return input;
189
+ };
190
+
191
+ // Insert temp input collecting file name
192
+ export const insertTempInput = editor => {
193
+ const {
194
+ selection
195
+ } = editor;
196
+ if (!Range.isCollapsed(selection)) return;
197
+ const tempInput = generateFileLinkInput();
198
+ const insertPoint = Editor.start(editor, selection);
199
+ Transforms.insertNodes(editor, tempInput, {
200
+ at: insertPoint
201
+ });
202
+ const path = Editor.path(editor, insertPoint);
203
+ const insertPath = Path.next(path);
204
+ const focusPoint = insertPath.concat(0);
205
+ focusEditor(editor, focusPoint);
206
+ };
207
+
208
+ // Remove temp input collecting file name
209
+ export const removeTempInput = (editor, element) => {
210
+ const path = ReactEditor.findPath(editor, element);
211
+ Transforms.delete(editor, {
212
+ at: path
213
+ });
214
+ };
215
+ export const getFileSearchInputEntry = editor => {
216
+ const [searchInputNodeEntry] = Editor.nodes(editor, {
217
+ match: n => n.type === FILE_LINK_INSET_INPUT_TEMP
218
+ });
219
+ return searchInputNodeEntry;
220
+ };
221
+
222
+ // Insert text when remove file name collector, such as inserting 'filename' into prevNode when close collector entered '[[filename'
223
+ export const insertTextWhenRemoveFileNameCollector = (editor, searchInputNode) => {
224
+ const inputNodePath = ReactEditor.findPath(editor, searchInputNode);
225
+ if (!inputNodePath) return;
226
+ const prevNodeEntry = Editor.previous(editor, {
227
+ at: inputNodePath
228
+ });
229
+ if (!prevNodeEntry) return;
230
+ const searchContent = Node.string(searchInputNode);
231
+ const insertPoint = Editor.end(editor, prevNodeEntry[1]);
232
+ Transforms.insertText(editor, searchContent, {
233
+ at: insertPoint
234
+ });
235
+ removeTempInput(editor, searchInputNode);
187
236
  };
@@ -1,11 +1,12 @@
1
1
  import { SDOC_LINK } from '../../constants';
2
2
  import SdocLinkMenu from './menu';
3
3
  import withSdocLink from './plugin';
4
- import renderSdocLink from './render-elem';
4
+ import renderSdocLink from './render/render-elem';
5
+ import renderFileLinkTempInput from './render/render-file-link-temp-input';
5
6
  const SdocLinkPlugin = {
6
7
  type: SDOC_LINK,
7
8
  editorMenus: [SdocLinkMenu],
8
9
  editorPlugin: withSdocLink,
9
- renderElements: [renderSdocLink]
10
+ renderElements: [renderSdocLink, renderFileLinkTempInput]
10
11
  };
11
12
  export default SdocLinkPlugin;
@@ -1,13 +1,14 @@
1
1
  import { Transforms, Node, Editor } from '@seafile/slate';
2
- import { ELEMENT_TYPE, SDOC_LINK } from '../../constants';
3
- import EventBus from '../../../utils/event-bus';
4
- import { INTERNAL_EVENT } from '../../../constants';
5
- import { insertSdocFileLink, isTriggeredByShortCut } from './helpers';
2
+ import { ReactEditor } from '@seafile/slate-react';
3
+ import { FILE_LINK_INSET_INPUT_TEMP, SDOC_LINK } from '../../constants';
4
+ import { getFileSearchInputEntry, insertTempInput, isTriggeredByShortcut } from './helpers';
5
+ import { getSelectedElems } from '../../core';
6
6
  const withSdocLink = editor => {
7
7
  const {
8
8
  isInline,
9
9
  deleteBackward,
10
- onHotKeyDown
10
+ insertText,
11
+ onCompositionStart
11
12
  } = editor;
12
13
  const newEditor = editor;
13
14
 
@@ -16,9 +17,8 @@ const withSdocLink = editor => {
16
17
  const {
17
18
  type
18
19
  } = elem;
19
- if (type === SDOC_LINK) {
20
- return true;
21
- }
20
+ const isInlineElem = [SDOC_LINK, FILE_LINK_INSET_INPUT_TEMP].includes(type);
21
+ if (isInlineElem) return true;
22
22
  return isInline(elem);
23
23
  };
24
24
  newEditor.deleteBackward = unit => {
@@ -29,13 +29,21 @@ const withSdocLink = editor => {
29
29
  return deleteBackward(unit);
30
30
  }
31
31
 
32
- // Delete file link node
32
+ // Delete file link node when the input is empty
33
+ const selectedElems = getSelectedElems(newEditor);
34
+ const fileLinkSearchInputNode = selectedElems.find(elem => elem.type === FILE_LINK_INSET_INPUT_TEMP);
35
+ if (fileLinkSearchInputNode) {
36
+ const path = ReactEditor.findPath(editor, fileLinkSearchInputNode);
37
+ if (Node.string(fileLinkSearchInputNode).length === 0) return Transforms.delete(newEditor, {
38
+ at: path
39
+ });
40
+ }
33
41
  const nodeEntry = Editor.node(newEditor, newEditor.selection);
34
42
  if (nodeEntry && Node.string(nodeEntry[0]).length === 0) {
35
43
  const beforePath = nodeEntry[1];
36
44
  beforePath.splice(-1, 1, Math.max(nodeEntry[1].at(-1) - 1, 0));
37
45
  const beforeNodeEntry = Editor.node(newEditor, beforePath);
38
- if (beforeNodeEntry && beforeNodeEntry[0].type === SDOC_LINK) {
46
+ if (beforeNodeEntry && [SDOC_LINK, FILE_LINK_INSET_INPUT_TEMP].includes(beforeNodeEntry[0].type)) {
39
47
  Transforms.delete(newEditor, {
40
48
  at: beforeNodeEntry[1]
41
49
  });
@@ -45,21 +53,23 @@ const withSdocLink = editor => {
45
53
  }
46
54
  return deleteBackward(unit);
47
55
  };
48
- newEditor.onHotKeyDown = event => {
49
- const {
50
- key
51
- } = event;
52
- if (key !== '[') return onHotKeyDown && onHotKeyDown(event);
56
+ newEditor.insertText = text => {
57
+ if (text !== '[') return insertText(text);
53
58
  // If user press '[[', open file modal
54
- const eventBus = EventBus.getInstance();
55
- if (isTriggeredByShortCut(newEditor)) {
56
- eventBus.dispatch(INTERNAL_EVENT.INSERT_ELEMENT, {
57
- type: ELEMENT_TYPE.SDOC_LINK,
58
- insertSdocFileLinkCallback: insertSdocFileLink,
59
- isShowHistoryFiles: true
60
- });
59
+ if (isTriggeredByShortcut(newEditor)) {
60
+ insertText(text);
61
+ insertTempInput(newEditor);
62
+ return;
63
+ }
64
+ return insertText(text);
65
+ };
66
+ newEditor.onCompositionStart = event => {
67
+ const fileSearchInputNodeEntry = getFileSearchInputEntry(newEditor);
68
+ if (fileSearchInputNodeEntry) {
69
+ event.preventDefault();
70
+ return true;
61
71
  }
62
- return onHotKeyDown && onHotKeyDown(event);
72
+ return onCompositionStart && onCompositionStart(event);
63
73
  };
64
74
  return newEditor;
65
75
  };
@@ -20,7 +20,7 @@
20
20
  }
21
21
 
22
22
  .sdoc-file-card-link .sdoc-file-link-icon :first-child {
23
- font-size: 24px;
23
+ font-size: 24px;
24
24
  }
25
25
 
26
26
  .sdoc-file-card-link .sdoc-file-link-icon {
@@ -39,3 +39,7 @@
39
39
  text-decoration: none;
40
40
  color: #333;
41
41
  }
42
+
43
+ .sdoc-file-name-insert-collector {
44
+ padding: 0 .25em;
45
+ }
@@ -2,12 +2,12 @@ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
2
  import React, { useCallback, useEffect, useState, useRef } from 'react';
3
3
  import { Editor, Range } from '@seafile/slate';
4
4
  import { ReactEditor, useReadOnly } from '@seafile/slate-react';
5
- import { useScrollContext } from '../../../hooks/use-scroll-context';
6
- import { unwrapLinkNode, getUrl } from './helpers';
7
- import HoverMenu from './hover-menu';
8
- import { DELETED_STYLE, ADDED_STYLE } from '../../constants';
9
- import { SDOC_LINK_TYPE } from './constants';
10
- import { focusEditor } from '../../core';
5
+ import { useScrollContext } from '../../../../hooks/use-scroll-context';
6
+ import { unwrapLinkNode, getUrl } from '../helpers';
7
+ import HoverMenu from '../hover-menu';
8
+ import { DELETED_STYLE, ADDED_STYLE } from '../../../constants';
9
+ import { SDOC_LINK_TYPE } from '../constants';
10
+ import { focusEditor } from '../../../core';
11
11
  import './render-elem.css';
12
12
  const SdocFileLink = _ref => {
13
13
  let {
@@ -0,0 +1,26 @@
1
+ import React, { useEffect } from 'react';
2
+ import EventBus from '../../../../utils/event-bus';
3
+ import { INTERNAL_EVENT } from '../../../../constants';
4
+ import { FILE_LINK_INSET_INPUT_TEMP } from '../../../constants';
5
+ import './render-elem.css';
6
+ const RenderFileLinkTempInput = _ref => {
7
+ let {
8
+ element,
9
+ attributes,
10
+ children
11
+ } = _ref;
12
+ const eventBus = EventBus.getInstance();
13
+ useEffect(() => {
14
+ eventBus.dispatch(INTERNAL_EVENT.INSERT_ELEMENT, {
15
+ type: FILE_LINK_INSET_INPUT_TEMP,
16
+ slateNode: element
17
+ });
18
+ return () => {
19
+ eventBus.dispatch(INTERNAL_EVENT.CLOSE_FILE_INSET_DIALOG);
20
+ };
21
+ }, [element, eventBus]);
22
+ return /*#__PURE__*/React.createElement("span", Object.assign({}, attributes, {
23
+ className: "sdoc-file-name-insert-collector"
24
+ }), children);
25
+ };
26
+ export default RenderFileLinkTempInput;
@@ -1,6 +1,6 @@
1
1
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
2
  import { useReadOnly, useSlateStatic } from '@seafile/slate-react';
3
- import { BLOCKQUOTE, LINK, CHECK_LIST_ITEM, HEADER1, HEADER2, HEADER3, HEADER4, HEADER5, HEADER6, LIST_ITEM, ORDERED_LIST, PARAGRAPH, UNORDERED_LIST, CODE_BLOCK, CODE_LINE, IMAGE, IMAGE_BLOCK, ELEMENT_TYPE, SDOC_LINK, FILE_LINK, TITLE, SUBTITLE, CALL_OUT, SUPPORTED_SIDE_OPERATION_TYPE, MENTION, MENTION_TEMP } from '../constants';
3
+ import { BLOCKQUOTE, LINK, CHECK_LIST_ITEM, HEADER1, HEADER2, HEADER3, HEADER4, HEADER5, HEADER6, LIST_ITEM, ORDERED_LIST, PARAGRAPH, UNORDERED_LIST, CODE_BLOCK, CODE_LINE, IMAGE, IMAGE_BLOCK, ELEMENT_TYPE, SDOC_LINK, FILE_LINK, TITLE, SUBTITLE, CALL_OUT, SUPPORTED_SIDE_OPERATION_TYPE, MENTION, MENTION_TEMP, FILE_LINK_INSET_INPUT_TEMP } from '../constants';
4
4
  import { BlockquotePlugin, LinkPlugin, CheckListPlugin, HeaderPlugin, ListPlugin, CodeBlockPlugin, ImagePlugin, TablePlugin, SdocLinkPlugin, ParagraphPlugin, FileLinkPlugin, CalloutPlugin, MentionPlugin } from '../plugins';
5
5
  import { onDragOver, onDragLeave, onDrop } from '../toolbar/side-toolbar/event';
6
6
  import { getParentNode } from '../core';
@@ -134,6 +134,11 @@ const CustomRenderElement = props => {
134
134
  const [renderFileLink] = FileLinkPlugin.renderElements;
135
135
  return renderFileLink(props, editor);
136
136
  }
137
+ case FILE_LINK_INSET_INPUT_TEMP:
138
+ {
139
+ const [, renderFileLinkFileSearchInput] = SdocLinkPlugin.renderElements;
140
+ return renderFileLinkFileSearchInput(props, editor);
141
+ }
137
142
  case CALL_OUT:
138
143
  {
139
144
  const [renderCallout] = CalloutPlugin.renderElements;
@@ -62,6 +62,7 @@ const MoreOperations = _ref => {
62
62
  return printTexts;
63
63
  }, []);
64
64
  return /*#__PURE__*/React.createElement(Dropdown, {
65
+ className: "sdoc-operator-folder",
65
66
  isOpen: isDropdownOpen,
66
67
  toggle: () => toggleDropdown(isDropdownOpen)
67
68
  }, /*#__PURE__*/React.createElement(DropdownToggle, {
@@ -72,26 +73,28 @@ const MoreOperations = _ref => {
72
73
  })), /*#__PURE__*/React.createElement(DropdownMenu, {
73
74
  className: "sdoc-dropdown-menu",
74
75
  right: true
75
- }, parentFolderURL && /*#__PURE__*/React.createElement(DropdownItem, {
76
- className: "sdoc-dropdown-menu-item",
77
- tag: "a",
78
- href: parentFolderURL
79
- }, t('Open_parent_folder')), isPro && isFreezed && /*#__PURE__*/React.createElement(DropdownItem, {
80
- className: "sdoc-dropdown-menu-item",
81
- onClick: unFreeze
82
- }, t('Unfreeze')), /*#__PURE__*/React.createElement(DropdownItem, {
76
+ }, /*#__PURE__*/React.createElement(DropdownItem, {
83
77
  className: "sdoc-dropdown-menu-item",
84
78
  onClick: handlePrint
85
79
  }, /*#__PURE__*/React.createElement("div", {
86
80
  className: "sdoc-dropdown-print-container"
87
81
  }, /*#__PURE__*/React.createElement("div", null, t('Print')), /*#__PURE__*/React.createElement(MenuShortcutPrompt, {
88
82
  shortcuts: printShortCutTexts
89
- }))), isPro && !isFreezed && /*#__PURE__*/React.createElement(DropdownItem, {
83
+ }))), isPro && isFreezed && /*#__PURE__*/React.createElement(DropdownItem, {
84
+ className: "sdoc-dropdown-menu-item",
85
+ onClick: unFreeze
86
+ }, t('Unfreeze')), isPro && !isFreezed && /*#__PURE__*/React.createElement(DropdownItem, {
90
87
  className: "sdoc-dropdown-menu-item",
91
88
  onClick: onFreezeDocument
92
89
  }, t('Freeze_document')), /*#__PURE__*/React.createElement(DropdownItem, {
93
90
  className: "sdoc-dropdown-menu-item",
94
91
  onClick: handleClickHistory
95
- }, t('Document_history'))));
92
+ }, t('Document_history')), parentFolderURL && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
93
+ className: "sdoc-operator-folder-divider"
94
+ }), /*#__PURE__*/React.createElement(DropdownItem, {
95
+ className: "sdoc-dropdown-menu-item",
96
+ tag: "a",
97
+ href: parentFolderURL
98
+ }, t('Open_parent_folder')))));
96
99
  };
97
100
  export default withTranslation('sdoc-editor')(MoreOperations);
@@ -32,3 +32,18 @@
32
32
  align-items: center;
33
33
  width: 100%;
34
34
  }
35
+
36
+ .sdoc-operator-folder .sdoc-dropdown-menu {
37
+ padding: 8px 0;
38
+ }
39
+
40
+ .sdoc-operator-folder .sdoc-dropdown-menu .sdoc-dropdown-menu-item {
41
+ padding: 4px 16px;
42
+ }
43
+
44
+ .sdoc-operator-folder .sdoc-dropdown-menu .sdoc-operator-folder-divider {
45
+ margin: 8px 0;
46
+ border-top: 1px solid #e6e9ed;
47
+ height: 1px;
48
+ width: 100%;
49
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seafile/sdoc-editor",
3
- "version": "0.5.41",
3
+ "version": "0.5.42",
4
4
  "private": false,
5
5
  "description": "This is a sdoc editor",
6
6
  "main": "dist/index.js",
@@ -453,5 +453,7 @@
453
453
  "Move_row_count": "Moving {{count}} row(s)",
454
454
  "Mark_all_as_read": "Mark all as read",
455
455
  "Alignment_type": "Alignment",
456
- "Print": "Print"
456
+ "Print": "Print",
457
+ "Enter_more_character_start_search": "Enter more characters to start search",
458
+ "Create_file_name_sdoc": "Create {{file_name_sdoc}}"
457
459
  }
@@ -453,5 +453,7 @@
453
453
  "Move_row_count": "移动{{count}}行",
454
454
  "Mark_all_as_read": "全部标记为已读",
455
455
  "Alignment_type": "对齐方式",
456
- "Print": "打印"
456
+ "Print": "打印",
457
+ "Enter_more_character_start_search": "输入更多字符开始搜索",
458
+ "Create_file_name_sdoc": "新建 {{file_name_sdoc}}"
457
459
  }
@@ -1,70 +0,0 @@
1
- .sdoc-history-files-wrapper {
2
- position: absolute;
3
- z-index: 101;
4
- width: 400px;
5
- cursor: pointer;
6
- }
7
-
8
- .sdoc-history-files-wrapper .sdoc-history-files-search-input {
9
- border: 0;
10
- outline: none;
11
- margin-top: -21px;
12
- position: absolute;
13
- background-color: transparent;
14
- padding: 0px;
15
- color: #212529;
16
- font-size: 14px;
17
- text-decoration: underline;
18
- }
19
-
20
- .sdoc-history-files-wrapper .sdoc-history-files-content .sdoc-history-files-header {
21
- color: #999999;
22
- font-size: 14px;
23
- margin-top: 8px;
24
- height: 32px;
25
- display: flex;
26
- align-items: center;
27
- padding: 0px 16px;
28
- }
29
-
30
- .sdoc-history-files-wrapper .sdoc-history-files-content .sdoc-history-files {
31
- max-height: 306px;
32
- overflow-y: scroll;
33
- }
34
-
35
- .sdoc-history-files-wrapper .sdoc-history-files-content .no-header {
36
- margin-top: 8px;
37
- }
38
-
39
- .sdoc-history-files-wrapper .sdoc-history-files-content .sdoc-history-files .sdoc-history-files-item {
40
- font-size: 14px;
41
- line-height: 32px;
42
- height: 32px;
43
- padding: 0px 16px;
44
- overflow:hidden;
45
- text-overflow:ellipsis;
46
- white-space:nowrap;
47
- }
48
-
49
- .sdoc-history-files-wrapper .sdoc-history-files-content .sdoc-history-files .sdoc-history-files-item :first-child {
50
- font-size: 12px;
51
- margin-right: 5px;
52
- }
53
-
54
- .sdoc-history-files-wrapper .sdoc-history-files-content .sdoc-history-files .sdoc-history-files-item:hover {
55
- background-color: #f5f5f5;
56
- }
57
-
58
- .sdoc-history-files-wrapper .sdoc-history-files-content .sdoc-history-files-add {
59
- height: 32px;
60
- padding: 0px 16px;
61
- border-top: 1px solid #e9ecef;
62
- font-size: 14px;
63
- display: flex;
64
- align-items: center;
65
- }
66
-
67
- .sdoc-history-files-wrapper .sdoc-history-files-content .sdoc-history-files-add :first-child {
68
- color: #444444;
69
- margin-right: 10px;
70
- }