@seafile/sdoc-editor 0.4.0 → 0.4.1

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.
@@ -29,9 +29,9 @@ export const MODIFY_TYPE = {
29
29
  export const REBASE_TYPE = {
30
30
  MODIFY_MODIFY: 'modify_modify',
31
31
  DELETE_MODIFY: 'delete_modify',
32
- MODIFY_DELETE: 'modify_delete',
33
- CHILDREN_MODIFY: 'children_modify'
32
+ MODIFY_DELETE: 'modify_delete'
34
33
  };
34
+ export const REBASE_TYPES = [REBASE_TYPE.MODIFY_DELETE, REBASE_TYPE.DELETE_MODIFY, REBASE_TYPE.MODIFY_MODIFY];
35
35
  export const REBASE_MARK_KEY = {
36
36
  ORIGIN: 'origin',
37
37
  REBASE_TYPE: 'rebase_type',
@@ -1,14 +1,10 @@
1
- import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
- import { Editor, Element, Point, Transforms, Node, Range } from '@seafile/slate';
3
- import { ReactEditor } from '@seafile/slate-react';
4
- import { generateEmptyElement, getSelectedNodeByType, isSelectionAtBlockStart } from '../../core';
1
+ import { Editor, Element, Transforms, Node } from '@seafile/slate';
2
+ import { focusEditor, generateDefaultText, getSelectedNodeByType, isSelectionAtBlockStart } from '../../core';
5
3
  import { BLOCKQUOTE, PARAGRAPH, CODE_BLOCK, TABLE } from '../../constants';
6
4
  import { setBlockQuoteType, getFormattedElements, getFormattedRestElements } from './helpers';
7
- import { getCalloutEntry, insertElementAtNewLineInCallout } from '../callout/helper';
8
5
  const withBlockquote = editor => {
9
6
  const {
10
7
  insertBreak,
11
- insertText,
12
8
  deleteBackward,
13
9
  insertFragment
14
10
  } = editor;
@@ -18,40 +14,38 @@ const withBlockquote = editor => {
18
14
  selection
19
15
  } = editor;
20
16
  if (selection == null) return insertBreak();
21
- const [nodeEntry] = Editor.nodes(editor, {
17
+ const [quoteBlockEntry] = Editor.nodes(editor, {
22
18
  match: n => Element.isElement(n) && n.type === BLOCKQUOTE,
23
19
  universal: true
24
20
  });
25
- if (!nodeEntry) return insertBreak();
26
- const quoteElem = nodeEntry[0];
27
- const quotePath = ReactEditor.findPath(editor, quoteElem);
28
- const quoteEndLocation = Editor.end(editor, quotePath);
29
- if (Point.equals(quoteEndLocation, selection.focus)) {
30
- // Cursor is at the end of blockquote
31
- const str = Node.string(quoteElem);
32
- // The last of the blockquote text is \n;
33
- if (str && str.slice(-1) === '\n') {
34
- const calloutEntry = getCalloutEntry(editor);
35
- if (calloutEntry) {
36
- // If the cursor is at the end of the callout, insert a paragraph inside the callout
37
- // Remove the last \n
38
- editor.deleteBackward('character');
39
- insertElementAtNewLineInCallout(editor, PARAGRAPH, quotePath);
40
- return;
41
- }
42
- // Step 1: Remove the last \n
43
- editor.deleteBackward('character');
44
- // Step 2: Insert a paragraph
45
- const p = generateEmptyElement(PARAGRAPH);
46
- Transforms.insertNodes(newEditor, p, {
47
- mode: 'highest'
21
+ if (!quoteBlockEntry) return insertBreak();
22
+ const [currentLineEntry] = Editor.nodes(newEditor, {
23
+ match: n => Element.isElement(n) && n.type === PARAGRAPH,
24
+ mode: 'lowest'
25
+ });
26
+ // Exit blockquote when current line is empty
27
+ const isAtEnd = currentLineEntry[1].slice(-1)[0] === quoteBlockEntry[0].children.length - 1;
28
+ if (isAtEnd) {
29
+ const isEmptyLine = !(currentLineEntry && Editor.string(newEditor, currentLineEntry[1]).length);
30
+ const movePath = quoteBlockEntry[1];
31
+ movePath.push(movePath.pop() + 1);
32
+ if (isEmptyLine) {
33
+ Transforms.moveNodes(newEditor, {
34
+ at: currentLineEntry[1],
35
+ to: movePath
48
36
  });
49
37
  return;
50
38
  }
51
39
  }
52
40
 
53
- // In other cases, insert a newline
54
- insertText('\n');
41
+ // Insert new line
42
+ Transforms.insertNodes(editor, {
43
+ type: PARAGRAPH,
44
+ children: [generateDefaultText()]
45
+ }, {
46
+ at: newEditor.selection,
47
+ select: true
48
+ });
55
49
  };
56
50
  newEditor.deleteBackward = unit => {
57
51
  const {
@@ -63,32 +57,30 @@ const withBlockquote = editor => {
63
57
  }
64
58
  const node = getSelectedNodeByType(editor, BLOCKQUOTE);
65
59
  if (node) {
66
- if (isSelectionAtBlockStart(editor)) {
60
+ const [currentLineEntry] = Editor.nodes(newEditor, {
61
+ match: n => Element.isElement(n) && n.type === PARAGRAPH,
62
+ mode: 'lowest'
63
+ });
64
+ if (!currentLineEntry) return deleteBackward(unit);
65
+ const currentLineIndex = currentLineEntry[1].slice(-1)[0];
66
+ if (currentLineIndex === 0) {
67
67
  setBlockQuoteType(editor, PARAGRAPH);
68
68
  return;
69
69
  }
70
- if (unit === 'line' && Range.isCollapsed(selection)) {
71
- const quoteString = Node.string(node);
72
- for (let index = selection.anchor.offset; index > 1; index--) {
73
- const char = quoteString.slice(index - 1, index);
74
- if (char === '\n') {
75
- const deleteRange = selection.anchor.offset === index ? _objectSpread(_objectSpread({}, selection), {}, {
76
- anchor: _objectSpread(_objectSpread({}, selection.anchor), {}, {
77
- offset: index - 1
78
- })
79
- }) // cursor at beginning of line, delete \n
80
- : _objectSpread(_objectSpread({}, selection), {}, {
81
- anchor: _objectSpread(_objectSpread({}, selection.anchor), {}, {
82
- offset: index
83
- })
84
- }); // cursor at middle or end of line, save \n
85
- Transforms.delete(editor, {
86
- at: deleteRange
87
- });
88
- return;
89
- }
90
- }
91
- deleteBackward(unit);
70
+ if (isSelectionAtBlockStart(editor)) {
71
+ const lineText = Node.string(currentLineEntry[0]);
72
+ const previousNodeEntry = Editor.previous(editor, {
73
+ at: currentLineEntry[1]
74
+ });
75
+ const focusPoint = Editor.end(newEditor, previousNodeEntry[1]);
76
+ Transforms.insertText(newEditor, lineText, {
77
+ at: Editor.end(newEditor, previousNodeEntry[1])
78
+ });
79
+ Transforms.removeNodes(editor, {
80
+ at: currentLineEntry[1]
81
+ });
82
+ focusEditor(newEditor, focusPoint);
83
+ return;
92
84
  }
93
85
  }
94
86
  deleteBackward(unit);
@@ -19,7 +19,6 @@ const ImageHoverMenu = _ref => {
19
19
  element,
20
20
  parentNodeEntry,
21
21
  onHideImageHoverMenu,
22
- onShowCaption,
23
22
  t
24
23
  } = _ref;
25
24
  const {
@@ -31,7 +30,7 @@ const ImageHoverMenu = _ref => {
31
30
  type
32
31
  } = parentNodeEntry[0];
33
32
  const {
34
- caption = ''
33
+ show_caption = false
35
34
  } = data;
36
35
  const [popoverState, setPopoverState] = useState({
37
36
  displayPopover: false,
@@ -125,6 +124,14 @@ const ImageHoverMenu = _ref => {
125
124
  onHideImageHoverMenu();
126
125
  return;
127
126
  }
127
+ if (Object.keys(props)[0] === 'show_caption') {
128
+ Transforms.setNodes(editor, {
129
+ data: _objectSpread(_objectSpread({}, data), props)
130
+ }, {
131
+ at: path
132
+ });
133
+ return;
134
+ }
128
135
  }
129
136
  // eslint-disable-next-line react-hooks/exhaustive-deps
130
137
  }, []);
@@ -182,11 +189,11 @@ const ImageHoverMenu = _ref => {
182
189
  id: "sdoc_image_caption",
183
190
  role: "button",
184
191
  className: classnames('op-item', 'ml-1', {
185
- 'active': (caption === null || caption === void 0 ? void 0 : caption.length) !== 0
192
+ 'active': show_caption
186
193
  }),
187
- onClick: () => {
188
- onShowCaption();
189
- }
194
+ onClick: event => onSelect(event, {
195
+ 'show_caption': !show_caption
196
+ })
190
197
  }, /*#__PURE__*/React.createElement("i", {
191
198
  className: "sdocfont sdoc-describe icon-font mr-1"
192
199
  }), isShowTooltip && /*#__PURE__*/React.createElement(Tooltip, {
@@ -10,7 +10,7 @@ import { INTERNAL_EVENT } from '../../../constants';
10
10
  import ImageHoverMenu from './hover-menu';
11
11
  import { useScrollContext } from '../../../hooks/use-scroll-context';
12
12
  import { IMAGE_BORDER_TYPE } from './constants';
13
- import { ADDED_STYLE, DELETED_STYLE } from '../../constants';
13
+ import { ADDED_STYLE, DELETED_STYLE, IMAGE_BLOCK } from '../../constants';
14
14
  import imagePlaceholder from '../../../assets/images/image-placeholder.png';
15
15
  const Image = _ref => {
16
16
  let {
@@ -27,6 +27,9 @@ const Image = _ref => {
27
27
  data,
28
28
  border_type = IMAGE_BORDER_TYPE[0].type
29
29
  } = element;
30
+ const {
31
+ show_caption = false
32
+ } = data;
30
33
  const path = ReactEditor.findPath(editor, element);
31
34
  const nodeEntry = Editor.node(editor, [path[0]]);
32
35
  const imageStyle = {
@@ -42,7 +45,6 @@ const Image = _ref => {
42
45
  const [isShowImageHoverMenu, setIsShowImageHoverMenu] = useState(false);
43
46
  const [menuPosition, setMenuPosition] = useState({});
44
47
  const [caption, setCaption] = useState((data === null || data === void 0 ? void 0 : data.caption) || '');
45
- const [isShowCaption, setIsShowCaption] = useState(false);
46
48
  const registerEvent = useCallback(eventList => {
47
49
  eventList.forEach(element => {
48
50
  document.addEventListener(element.eventName, element.event);
@@ -114,7 +116,8 @@ const Image = _ref => {
114
116
  var _imagePreviewer$;
115
117
  if (isResizing) return;
116
118
  const imagePreviewer = document.getElementsByClassName('sf-editor-image-previewer');
117
- if (e.target === imageRef.current || ((_imagePreviewer$ = imagePreviewer[0]) === null || _imagePreviewer$ === void 0 ? void 0 : _imagePreviewer$.contains(e.target))) return;
119
+ const isCaptionInput = e.target.id === 'sdoc-image-caption-input';
120
+ if (e.target === imageRef.current || ((_imagePreviewer$ = imagePreviewer[0]) === null || _imagePreviewer$ === void 0 ? void 0 : _imagePreviewer$.contains(e.target)) || isCaptionInput) return;
118
121
  setIsShowImageHoverMenu(false);
119
122
  }, [isResizing]);
120
123
  useEffect(() => {
@@ -225,7 +228,8 @@ const Image = _ref => {
225
228
  }), isResizing && /*#__PURE__*/React.createElement("span", {
226
229
  className: "image-size",
227
230
  contentEditable: false
228
- }, /*#__PURE__*/React.createElement("span", null, t('Width'), ':', parseInt(movingWidth || imageRef.current.clientWidth)), /*#__PURE__*/React.createElement("span", null, "\xA0\xA0"), /*#__PURE__*/React.createElement("span", null, t('Height'), ':', imageRef.current.clientHeight))), nodeEntry[0].type === 'image_block' && (isShowCaption || (data === null || data === void 0 ? void 0 : data.caption)) && /*#__PURE__*/React.createElement("input", {
231
+ }, /*#__PURE__*/React.createElement("span", null, t('Width'), ':', parseInt(movingWidth || imageRef.current.clientWidth)), /*#__PURE__*/React.createElement("span", null, "\xA0\xA0"), /*#__PURE__*/React.createElement("span", null, t('Height'), ':', imageRef.current.clientHeight))), nodeEntry[0].type === IMAGE_BLOCK && show_caption && /*#__PURE__*/React.createElement("input", {
232
+ id: "sdoc-image-caption-input",
229
233
  className: "sdoc-image-caption-input-wrapper",
230
234
  style: {
231
235
  width: (data === null || data === void 0 ? void 0 : data.width) || imageRef.current.clientWidth
@@ -246,9 +250,6 @@ const Image = _ref => {
246
250
  parentNodeEntry: nodeEntry,
247
251
  onHideImageHoverMenu: () => {
248
252
  setIsShowImageHoverMenu(false);
249
- },
250
- onShowCaption: () => {
251
- setIsShowCaption(true);
252
253
  }
253
254
  })));
254
255
  };
@@ -1,8 +1,9 @@
1
1
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
2
  import isHotkey from 'is-hotkey';
3
- import { Editor, Transforms, Path } from '@seafile/slate';
4
- import { getNodeType, getParentNode, getSelectedNodeByType, isLastNode, generateEmptyElement } from '../../core';
5
- import { ELEMENT_TYPE, KEYBOARD, PARAGRAPH, CLIPBOARD_FORMAT_KEY } from '../../constants';
3
+ import { Editor, Transforms, Path, Element } from '@seafile/slate';
4
+ import { ReactEditor } from '@seafile/slate-react';
5
+ import { getNodeType, getParentNode, getSelectedNodeByType, isLastNode, generateEmptyElement, focusEditor } from '../../core';
6
+ import { ELEMENT_TYPE, KEYBOARD, PARAGRAPH, CLIPBOARD_FORMAT_KEY, CHECK_LIST_ITEM, ORDERED_LIST, UNORDERED_LIST } from '../../constants';
6
7
  import { TABLE_MAX_ROWS, EMPTY_SELECTED_RANGE, TABLE_ELEMENT, TABLE_ELEMENT_POSITION } from './constants';
7
8
  import ObjectUtils from '../../../utils/object-utils';
8
9
  import { getSelectedInfo, insertTableElement, removeTable, insertMultipleRowsAndColumns, setTableFragmentData, deleteTableRangeData, focusCell, deleteHandler, isTableLocation, isLastTableCell } from './helpers';
@@ -88,9 +89,25 @@ const withTable = editor => {
88
89
  const before = Editor.before(newEditor, selection);
89
90
  if (before) {
90
91
  // If the current is not a table and the previous one is a table, no deletion will be performed. Otherwise, the last cell of the table will be deleted
92
+ // If deleting node is empty check-list, order-list, unordered-list, change to paragraph
91
93
  const isTableOnBeforeLocation = isTableLocation(newEditor, before);
92
94
  const isTableOnCurSelection = isTableLocation(newEditor, selection);
93
95
  if (isTableOnBeforeLocation && !isTableOnCurSelection) {
96
+ const transformTypes = [CHECK_LIST_ITEM, ORDERED_LIST, UNORDERED_LIST];
97
+ const [currentNodeEntry] = Editor.nodes(editor, {
98
+ match: n => Element.isElement(n) && !Editor.parent(n, ReactEditor.findPath(editor, n))[1].length
99
+ });
100
+ if (!currentNodeEntry) return;
101
+ const [currentNode, currentPath] = Array.from(currentNodeEntry);
102
+ if (transformTypes.includes(currentNode.type)) {
103
+ Transforms.delete(newEditor, {
104
+ at: currentPath
105
+ });
106
+ Transforms.insertNodes(newEditor, generateEmptyElement(PARAGRAPH), {
107
+ at: currentPath
108
+ });
109
+ focusEditor(editor, Editor.start(editor, currentPath));
110
+ }
94
111
  return;
95
112
  }
96
113
  }
@@ -1,29 +1,46 @@
1
1
  .sdoc-rebase-btn-group {
2
+ display: flex;
3
+ width: 100%;
2
4
  color: #aaa;
5
+ margin-bottom: 3px;
3
6
  }
4
7
 
5
8
  .sdoc-rebase-btn-group .sdoc-rebase-btn {
6
9
  cursor: pointer;
7
10
  }
8
11
 
9
- .sdoc-rebase-current-changes-start {
12
+ .sdoc-rebase-other-changes-title {
13
+ width: 100%;
14
+ padding-left: 4px;
10
15
  background-color: rgb(202, 232, 254);
16
+ border-radius: 3px 3px 0 0;
11
17
  }
12
18
 
13
- .sdoc-rebase-current-changes {
19
+ .sdoc-rebase-other-changes {
14
20
  background-color: rgba(202, 232, 254, .8);
21
+ border-radius: 0 0 3px 3px;
22
+ margin-bottom: 3px;
15
23
  }
16
24
 
17
- .sdoc-rebase-incoming-changes {
25
+ .sdoc-rebase-my-changes-title {
26
+ width: 100%;
27
+ padding-left: 4px;
28
+ background-color: rgb(212, 212, 254);
29
+ border-radius: 3px 3px 0 0;
30
+ }
31
+
32
+ .sdoc-rebase-my-changes {
18
33
  background-color: rgb(222, 232, 254);
34
+ border-radius: 0 0 3px 3px;
19
35
  }
20
36
 
21
- .sdoc-rebase-incoming-changes > *:first-child,
22
- .sdoc-rebase-current-changes > *:first-child {
23
- margin: 0;
24
- padding: 0.8em 0 0.8em 0.2em;
37
+ .sdoc-rebase-my-changes.empty,
38
+ .sdoc-rebase-other-changes.empty {
39
+ height: 3px;
25
40
  }
26
41
 
27
- .sdoc-rebase-incoming-changes-end {
28
- background-color: rgb(212, 212, 254);
42
+ .sdoc-rebase-my-changes > *:first-child,
43
+ .sdoc-rebase-other-changes > *:first-child {
44
+ margin: 0;
45
+ padding: 0.8em 0 0.8em 0.2em;
29
46
  }
@@ -35,7 +35,7 @@ const RebaseDeleteModifyDecorate = _ref => {
35
35
  // eslint-disable-next-line react-hooks/exhaustive-deps
36
36
  }, [editor, element]);
37
37
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
38
- className: "w-100 d-flex sdoc-rebase-btn-group",
38
+ className: "sdoc-rebase-btn-group",
39
39
  contentEditable: false
40
40
  }, /*#__PURE__*/React.createElement("div", {
41
41
  className: "sdoc-rebase-btn",
@@ -51,17 +51,17 @@ const RebaseDeleteModifyDecorate = _ref => {
51
51
  className: "sdoc-rebase-btn",
52
52
  onClick: deleteMark
53
53
  }, t('Keep_both_modification'))), /*#__PURE__*/React.createElement("div", {
54
- className: "w-100 sdoc-rebase-current-changes-start",
54
+ className: "sdoc-rebase-other-changes-title",
55
55
  contentEditable: false
56
- }, '<<<<<<<'), /*#__PURE__*/React.createElement("div", {
57
- className: "w-100",
56
+ }, t('Other_modification')), /*#__PURE__*/React.createElement("div", {
57
+ className: "sdoc-rebase-other-changes empty",
58
58
  contentEditable: false
59
- }, '======='), /*#__PURE__*/React.createElement("div", {
60
- className: "w-100 sdoc-rebase-incoming-changes",
59
+ }), /*#__PURE__*/React.createElement("div", {
60
+ className: "sdoc-rebase-my-changes-title",
61
61
  contentEditable: false
62
- }, children), /*#__PURE__*/React.createElement("div", {
63
- className: "w-100 sdoc-rebase-incoming-changes-end",
62
+ }, t('My_modification')), /*#__PURE__*/React.createElement("div", {
63
+ className: "sdoc-rebase-my-changes",
64
64
  contentEditable: false
65
- }, '>>>>>>>'));
65
+ }, children));
66
66
  };
67
67
  export default RebaseDeleteModifyDecorate;
@@ -35,7 +35,7 @@ const RebaseModifyDeleteDecorate = _ref => {
35
35
  // eslint-disable-next-line react-hooks/exhaustive-deps
36
36
  }, [editor, element]);
37
37
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
38
- className: "w-100 d-flex sdoc-rebase-btn-group",
38
+ className: "sdoc-rebase-btn-group",
39
39
  contentEditable: false
40
40
  }, /*#__PURE__*/React.createElement("div", {
41
41
  className: "sdoc-rebase-btn",
@@ -51,17 +51,17 @@ const RebaseModifyDeleteDecorate = _ref => {
51
51
  className: "sdoc-rebase-btn",
52
52
  onClick: deleteMark
53
53
  }, t('Keep_both_modification'))), /*#__PURE__*/React.createElement("div", {
54
- className: "w-100 sdoc-rebase-current-changes-start",
54
+ className: "sdoc-rebase-other-changes-title",
55
55
  contentEditable: false
56
- }, '<<<<<<<'), /*#__PURE__*/React.createElement("div", {
57
- className: "w-100 sdoc-rebase-incoming-changes",
56
+ }, t('Other_modification')), /*#__PURE__*/React.createElement("div", {
57
+ className: "w-100 sdoc-rebase-my-changes",
58
58
  contentEditable: false
59
59
  }, children), /*#__PURE__*/React.createElement("div", {
60
- className: "w-100",
60
+ className: "sdoc-rebase-my-changes-title",
61
61
  contentEditable: false
62
- }, '======='), /*#__PURE__*/React.createElement("div", {
63
- className: "w-100 sdoc-rebase-incoming-changes-end",
62
+ }, t('My_modification')), /*#__PURE__*/React.createElement("div", {
63
+ className: "sdoc-rebase-my-changes empty",
64
64
  contentEditable: false
65
- }, '>>>>>>>'));
65
+ }));
66
66
  };
67
67
  export default RebaseModifyDeleteDecorate;
@@ -62,7 +62,7 @@ const RebaseModifyModifyDecorate = _ref => {
62
62
  }, [editor, element]);
63
63
  if (element[REBASE_MARK_KEY.ORIGIN] === REBASE_ORIGIN.OTHER) {
64
64
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
65
- className: "w-100 d-flex sdoc-rebase-btn-group",
65
+ className: "sdoc-rebase-btn-group",
66
66
  contentEditable: false
67
67
  }, /*#__PURE__*/React.createElement("div", {
68
68
  className: "sdoc-rebase-btn",
@@ -78,22 +78,19 @@ const RebaseModifyModifyDecorate = _ref => {
78
78
  className: "sdoc-rebase-btn",
79
79
  onClick: useBothChanges
80
80
  }, t('Keep_both_modification'))), /*#__PURE__*/React.createElement("div", {
81
- className: "w-100 sdoc-rebase-current-changes-start",
81
+ className: "sdoc-rebase-other-changes-title",
82
82
  contentEditable: false
83
- }, '<<<<<<<'), /*#__PURE__*/React.createElement("div", {
84
- className: "w-100 sdoc-rebase-current-changes",
83
+ }, t('Other_modification')), /*#__PURE__*/React.createElement("div", {
84
+ className: "sdoc-rebase-other-changes",
85
85
  contentEditable: false
86
86
  }, children));
87
87
  }
88
88
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
89
- className: "w-100",
89
+ className: "sdoc-rebase-my-changes-title",
90
90
  contentEditable: false
91
- }, '======='), /*#__PURE__*/React.createElement("div", {
92
- className: "w-100 sdoc-rebase-incoming-changes",
91
+ }, t('My_modification')), /*#__PURE__*/React.createElement("div", {
92
+ className: "sdoc-rebase-my-changes",
93
93
  contentEditable: false
94
- }, children), /*#__PURE__*/React.createElement("div", {
95
- className: "w-100 sdoc-rebase-incoming-changes-end",
96
- contentEditable: false
97
- }, '>>>>>>>'));
94
+ }, children));
98
95
  };
99
96
  export default RebaseModifyModifyDecorate;
@@ -1,12 +1,29 @@
1
1
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
2
  import { generateIdMapAndIds, getIdDiffs } from './diff';
3
3
  import ObjectUtils from './object-utils';
4
- import { MODIFY_TYPE, REBASE_TYPE, REBASE_MARK_KEY, REBASE_ORIGIN } from '../constants';
4
+ import { MODIFY_TYPE, REBASE_TYPE, REBASE_MARK_KEY, REBASE_ORIGIN, REBASE_TYPES } from '../constants';
5
5
  import { ELEMENT_TYPE } from '../extension/constants';
6
6
  import { replaceNodeId } from '../node-id/helpers';
7
7
  export const hasConflict = content => {
8
8
  if (!Array.isArray(content) || content.length === 0) return false;
9
- return content.filter(item => item.rebase_type).length !== 0;
9
+ let flag = false;
10
+ for (let i = 0; i < content.length; i++) {
11
+ const element = content[i];
12
+ const {
13
+ rebase_type,
14
+ children
15
+ } = element;
16
+ if (REBASE_TYPES.includes(rebase_type)) {
17
+ flag = true;
18
+ break;
19
+ } else {
20
+ const childrenFlag = hasConflict(children);
21
+ if (!childrenFlag) continue;
22
+ flag = childrenFlag;
23
+ break;
24
+ }
25
+ }
26
+ return flag;
10
27
  };
11
28
  const getChanges = (masterContent, revisionContent) => {
12
29
  const {
@@ -156,8 +173,7 @@ const getMergeElement = (diffElement, baseElement) => {
156
173
  content: childrenContent
157
174
  } = getMergeContent(baseElement, diffElement.children);
158
175
  return [_objectSpread(_objectSpread({}, newElement), {}, {
159
- children: childrenContent,
160
- [REBASE_MARK_KEY.REBASE_TYPE]: REBASE_TYPE.CHILDREN_MODIFY
176
+ children: childrenContent
161
177
  })];
162
178
  }
163
179
  newElement[REBASE_MARK_KEY.OLD_ELEMENT] && delete newElement[REBASE_MARK_KEY.OLD_ELEMENT];
@@ -2,7 +2,6 @@ import React from 'react';
2
2
  import { withTranslation } from 'react-i18next';
3
3
  import context from '../../context';
4
4
  import RevisionOperations from './revision-operations';
5
- import HistoryOperation from './history-operation';
6
5
  import CollaboratorsOperation from './collaborators-operation';
7
6
  import MoreOperations from './more-operations';
8
7
  import CommentsOperation from './comments-operation';
@@ -34,6 +33,6 @@ const DocOperations = _ref => {
34
33
  handleViewChangesToggle: handleViewChangesToggle,
35
34
  handleRevisionMerged: handleRevisionMerged,
36
35
  handleRevisionPublished: handleRevisionPublished
37
- }), !isPublished && /*#__PURE__*/React.createElement(TagOperation, null), !isPublished && /*#__PURE__*/React.createElement(CommentsOperation, null), !isSdocRevision && /*#__PURE__*/React.createElement(ShareOperation, null), /*#__PURE__*/React.createElement(HistoryOperation, null), !isPublished && /*#__PURE__*/React.createElement(CollaboratorsOperation, null), !isSdocRevision && /*#__PURE__*/React.createElement(MoreOperations, null));
36
+ }), !isPublished && /*#__PURE__*/React.createElement(TagOperation, null), !isPublished && /*#__PURE__*/React.createElement(CommentsOperation, null), !isSdocRevision && /*#__PURE__*/React.createElement(ShareOperation, null), !isPublished && /*#__PURE__*/React.createElement(CollaboratorsOperation, null), !isSdocRevision && /*#__PURE__*/React.createElement(MoreOperations, null));
38
37
  };
39
38
  export default withTranslation('sdoc-editor')(DocOperations);
@@ -9,6 +9,12 @@ const MoreOperations = _ref => {
9
9
  t
10
10
  } = _ref;
11
11
  const [isDropdownOpen, setIsDropdownOpen] = useState(false);
12
+ const parentFolderURL = context.getSetting('parentFolderURL');
13
+ const isPro = context.getSetting('isPro');
14
+ const isFreezed = context.getSetting('isFreezed');
15
+ const docPerm = context.getSetting('docPerm');
16
+ const historyURL = context.getSetting('historyURL');
17
+ const isSdocRevision = context.getSetting('isSdocRevision');
12
18
  const toggleDropdown = useCallback(isDropdownOpen => {
13
19
  setIsDropdownOpen(!isDropdownOpen);
14
20
  }, []);
@@ -20,9 +26,13 @@ const MoreOperations = _ref => {
20
26
  const eventBus = EventBus.getInstance();
21
27
  eventBus.dispatch(EXTERNAL_EVENT.UNFREEZE);
22
28
  }, []);
23
- const parentFolderURL = context.getSetting('parentFolderURL');
24
- const isPro = context.getSetting('isPro');
25
- const isFreezed = context.getSetting('isFreezed');
29
+ const handleClickHistory = useCallback(event => {
30
+ if (docPerm !== 'rw' || !historyURL) return;
31
+ if (isSdocRevision) return;
32
+ event.stopPropagation();
33
+ event.nativeEvent.stopImmediatePropagation();
34
+ window.location.href = historyURL;
35
+ }, [docPerm, historyURL, isSdocRevision]);
26
36
  return /*#__PURE__*/React.createElement(Dropdown, {
27
37
  isOpen: isDropdownOpen,
28
38
  toggle: () => toggleDropdown(isDropdownOpen)
@@ -44,6 +54,9 @@ const MoreOperations = _ref => {
44
54
  }, t('Unfreeze')), isPro && !isFreezed && /*#__PURE__*/React.createElement(DropdownItem, {
45
55
  className: "sdoc-dropdown-menu-item",
46
56
  onClick: onFreezeDocument
47
- }, t('Freeze_Document'))));
57
+ }, t('Freeze_Document')), /*#__PURE__*/React.createElement(DropdownItem, {
58
+ className: "sdoc-dropdown-menu-item",
59
+ onClick: handleClickHistory
60
+ }, t('Document_history'))));
48
61
  };
49
62
  export default withTranslation('sdoc-editor')(MoreOperations);
@@ -27,7 +27,7 @@ const TipDialog = _ref => {
27
27
  // eslint-disable-next-line react-hooks/exhaustive-deps
28
28
  }, [tipType, isSubmitting]);
29
29
  const onSubmit = useCallback(() => {
30
- if (tipType === TIP_TYPE.HAS_CONFLICT_BEFORE_VIEW_CHANGES) {
30
+ if ([TIP_TYPE.HAS_CONFLICT_BEFORE_VIEW_CHANGES, TIP_TYPE.HAS_CONFLICT_BEFORE_PUBLISH].includes(tipType)) {
31
31
  closeDialog();
32
32
  return;
33
33
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seafile/sdoc-editor",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "private": false,
5
5
  "description": "This is a sdoc editor",
6
6
  "main": "dist/index.js",
@@ -425,5 +425,8 @@
425
425
  "Column_number": "Column number",
426
426
  "The_maximum_row_number_is_{number}": "The maximum row number is {number}",
427
427
  "Freeze_Document": "Freeze Document",
428
- "Unfreeze": "Unfreeze"
428
+ "Unfreeze": "Unfreeze",
429
+ "Other_modification": "Other's modification",
430
+ "My_modification": "My modification",
431
+ "Document_history": "Document history"
429
432
  }
@@ -424,5 +424,6 @@
424
424
  "Row_number": "Row number",
425
425
  "Column_number": "Column number",
426
426
  "The_maximum_row_number_is_{number}": "The maximum row number is {number}",
427
- "The_maximum_column_number_is_{number}": "The maximum column number is {number}"
427
+ "Freeze_Document": "Freeze Document",
428
+ "Unfreeze": "Unfreeze"
428
429
  }
@@ -424,6 +424,6 @@
424
424
  "Row_number": "Номер строки",
425
425
  "Column_number": "Номер столбца",
426
426
  "The_maximum_row_number_is_{number}": "Максимальное количество строк - {number}",
427
- "Freeze_Document": "Freeze Document",
428
- "Unfreeze": "Unfreeze"
427
+ "Freeze_Document": "Заморозить документ",
428
+ "Unfreeze": "Разморозить"
429
429
  }
@@ -376,7 +376,7 @@
376
376
  "Link_sdoc": "链接 sdoc",
377
377
  "Link_file": "文件链接",
378
378
  "Keep_my_modification": "保留我的更改",
379
- "Keep_other_modification": "保留其他的更改",
379
+ "Keep_other_modification": "保留他人的更改",
380
380
  "Keep_both_modification": "保留两者更改",
381
381
  "Tip": "提示",
382
382
  "Rebase_delete_no_change_revision_tip": "修订改没有更改,是否删除修订稿?",
@@ -425,5 +425,8 @@
425
425
  "Column_number": "列数",
426
426
  "The_maximum_row_number_is_{number}": "最大行数为 {number}",
427
427
  "Freeze_Document": "冻结文档",
428
- "Unfreeze": "取消冻结"
428
+ "Unfreeze": "取消冻结",
429
+ "Other_modification": "他人更改",
430
+ "My_modification": "我的更改",
431
+ "Document_history":"文档历史"
429
432
  }
@@ -1,23 +0,0 @@
1
- import React, { useCallback } from 'react';
2
- import context from '../../context';
3
- const HistoryOperation = () => {
4
- const docPerm = context.getSetting('docPerm');
5
- const historyURL = context.getSetting('historyURL');
6
- const isSdocRevision = context.getSetting('isSdocRevision');
7
- const toggleHistory = useCallback(event => {
8
- event.stopPropagation();
9
- event.nativeEvent.stopImmediatePropagation();
10
- window.location.href = historyURL;
11
-
12
- // eslint-disable-next-line react-hooks/exhaustive-deps
13
- }, []);
14
- if (docPerm !== 'rw' || !historyURL) return null;
15
- if (isSdocRevision) return null;
16
- return /*#__PURE__*/React.createElement("span", {
17
- className: "op-item",
18
- onClick: toggleHistory
19
- }, /*#__PURE__*/React.createElement("i", {
20
- className: "sdocfont sdoc-history"
21
- }));
22
- };
23
- export default HistoryOperation;