@seafile/sdoc-editor 0.4.21 → 0.4.23
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.
- package/dist/basic-sdk/constants/index.js +2 -1
- package/dist/basic-sdk/extension/plugins/callout/helper.js +1 -10
- package/dist/basic-sdk/extension/plugins/callout/render-elem/color-selector.js +18 -21
- package/dist/basic-sdk/extension/plugins/callout/render-elem/index.js +33 -32
- package/dist/basic-sdk/extension/plugins/image/plugin.js +1 -1
- package/dist/basic-sdk/extension/plugins/search-replace/menu/index.js +4 -2
- package/dist/basic-sdk/extension/plugins/search-replace/popover/index.css +7 -0
- package/dist/basic-sdk/extension/plugins/search-replace/popover/index.js +16 -3
- package/dist/basic-sdk/extension/plugins/table/constants/index.js +8 -1
- package/dist/basic-sdk/extension/plugins/table/helpers.js +87 -86
- package/dist/basic-sdk/extension/plugins/table/render/index.css +47 -1
- package/dist/basic-sdk/extension/plugins/table/render/index.js +27 -3
- package/dist/basic-sdk/extension/plugins/table/render/render-cell.js +17 -5
- package/dist/basic-sdk/extension/plugins/table/render/resize-handlers/column-resize-handler.js +25 -45
- package/dist/basic-sdk/extension/plugins/table/render/resize-handlers/first-column-left-resize-handler.js +21 -41
- package/dist/basic-sdk/extension/plugins/table/render/resize-handlers/index.js +44 -35
- package/dist/basic-sdk/extension/plugins/table/render/resize-handlers/row-resize-handler.js +22 -32
- package/dist/basic-sdk/extension/plugins/table/render/resize-mask/index.js +133 -0
- package/dist/basic-sdk/extension/plugins/table/render/table-header/rows-header/row-header.js +9 -15
- package/package.json +1 -1
- package/public/locales/zh_CN/sdoc-editor.json +1 -1
- package/public/media/sdoc-editor-font/iconfont.eot +0 -0
- package/public/media/sdoc-editor-font/iconfont.svg +16 -2
- package/public/media/sdoc-editor-font/iconfont.ttf +0 -0
- package/public/media/sdoc-editor-font/iconfont.woff +0 -0
- package/public/media/sdoc-editor-font/iconfont.woff2 +0 -0
- package/public/media/sdoc-editor-font.css +38 -10
|
@@ -16,7 +16,8 @@ export const INTERNAL_EVENT = {
|
|
|
16
16
|
UNSEEN_NOTIFICATIONS_COUNT: 'unseen_notifications_count',
|
|
17
17
|
CLOSE_CALLOUT_COLOR_PICKER: 'close_callout_color_picker',
|
|
18
18
|
OPEN_SEARCH_REPLACE_MODAL: 'open_search_replace_modal',
|
|
19
|
-
UPDATE_SEARCH_REPLACE_HIGHLIGHT: 'update_search_replace_highlight'
|
|
19
|
+
UPDATE_SEARCH_REPLACE_HIGHLIGHT: 'update_search_replace_highlight',
|
|
20
|
+
TABLE_CELL_MOUSE_ENTER: 'table_cell_mouse_enter'
|
|
20
21
|
};
|
|
21
22
|
export const REVISION_DIFF_KEY = 'diff';
|
|
22
23
|
export const REVISION_DIFF_VALUE = '1';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Editor, Node, Path, Transforms } from '@seafile/slate';
|
|
2
2
|
import { CALL_OUT } from '../../constants/element-type';
|
|
3
|
-
import {
|
|
3
|
+
import { focusEditor, generateEmptyElement, getSelectedElems, isRangeAcrossBlocks } from '../../core';
|
|
4
4
|
import { CALLOUT_ALLOWED_INSIDE_TYPES, CALLOUT_COLOR_MAP } from './constant';
|
|
5
5
|
export const isMenuActive = editor => {
|
|
6
6
|
const {
|
|
@@ -91,15 +91,6 @@ export const getCalloutEntry = function (editor) {
|
|
|
91
91
|
});
|
|
92
92
|
return aboveNodeEntry;
|
|
93
93
|
};
|
|
94
|
-
|
|
95
|
-
// Use in render-elem, to judge whether to display placeholder
|
|
96
|
-
export const isFocusOnElement = (editor, element) => {
|
|
97
|
-
var _editor$selection, _editor$selection$anc;
|
|
98
|
-
if (!editor.selection || !element) return false;
|
|
99
|
-
const elementPath = findPath(editor, element);
|
|
100
|
-
const isSelectOnElement = Path.isAncestor(elementPath, editor === null || editor === void 0 ? void 0 : (_editor$selection = editor.selection) === null || _editor$selection === void 0 ? void 0 : (_editor$selection$anc = _editor$selection.anchor) === null || _editor$selection$anc === void 0 ? void 0 : _editor$selection$anc.path);
|
|
101
|
-
return isSelectOnElement;
|
|
102
|
-
};
|
|
103
94
|
export const isCalloutContentEmpty = calloutEntry => {
|
|
104
95
|
const [calloutNode] = calloutEntry;
|
|
105
96
|
const contentString = Node.string(calloutNode);
|
|
@@ -1,39 +1,34 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
2
|
import { Transforms } from '@seafile/slate';
|
|
3
3
|
import { CALLOUT_COLOR_MAP } from '../constant';
|
|
4
4
|
import { findPath } from '../../../core';
|
|
5
5
|
import { changeFillBackgroundColor } from '../helper';
|
|
6
6
|
import { ElementPopover } from '../../../commons';
|
|
7
7
|
import './index.css';
|
|
8
|
-
const ColorSelector =
|
|
8
|
+
const ColorSelector = _ref => {
|
|
9
9
|
let {
|
|
10
10
|
editor,
|
|
11
11
|
element,
|
|
12
12
|
popoverPosition
|
|
13
13
|
} = _ref;
|
|
14
|
-
const
|
|
15
|
-
|
|
14
|
+
const onColorClick = useCallback(event => {
|
|
15
|
+
const {
|
|
16
|
+
backgroundColor
|
|
17
|
+
} = event.target.dataset;
|
|
16
18
|
const currentPath = findPath(editor, element);
|
|
17
19
|
Transforms.select(editor, currentPath);
|
|
18
|
-
changeFillBackgroundColor(editor,
|
|
19
|
-
}, []);
|
|
20
|
-
|
|
21
|
-
colorSelectorContainer: selectorRef.current
|
|
22
|
-
}));
|
|
23
|
-
const isShowCheckedIcon = useCallback((element, currentBackgroundColor) => {
|
|
20
|
+
changeFillBackgroundColor(editor, backgroundColor);
|
|
21
|
+
}, [editor, element]);
|
|
22
|
+
const isShowCheckedIcon = useCallback(currentBackgroundColor => {
|
|
24
23
|
const {
|
|
25
24
|
background_color
|
|
26
|
-
} = element.style;
|
|
25
|
+
} = element.style || {};
|
|
27
26
|
return background_color && background_color === currentBackgroundColor;
|
|
28
|
-
}, []);
|
|
27
|
+
}, [element.style]);
|
|
29
28
|
return /*#__PURE__*/React.createElement(ElementPopover, null, /*#__PURE__*/React.createElement("div", {
|
|
30
29
|
className: "sdoc-callout-color-selector-container",
|
|
31
|
-
ref: selectorRef,
|
|
32
30
|
contentEditable: false,
|
|
33
|
-
style:
|
|
34
|
-
top: popoverPosition.top,
|
|
35
|
-
left: popoverPosition.left
|
|
36
|
-
}
|
|
31
|
+
style: popoverPosition
|
|
37
32
|
}, /*#__PURE__*/React.createElement("ul", {
|
|
38
33
|
className: "sdoc-color-selector-list"
|
|
39
34
|
}, Object.values(CALLOUT_COLOR_MAP).map((_ref2, index) => {
|
|
@@ -44,14 +39,16 @@ const ColorSelector = (_ref, ref) => {
|
|
|
44
39
|
return /*#__PURE__*/React.createElement("li", {
|
|
45
40
|
key: "sdoc-callout-color-selector-".concat(index),
|
|
46
41
|
className: "sdoc-callout-color-item",
|
|
47
|
-
|
|
42
|
+
"data-border-color": border_color,
|
|
43
|
+
"data-background-color": background_color,
|
|
48
44
|
style: {
|
|
49
45
|
borderColor: border_color,
|
|
50
46
|
backgroundColor: background_color
|
|
51
|
-
}
|
|
52
|
-
|
|
47
|
+
},
|
|
48
|
+
onClick: onColorClick
|
|
49
|
+
}, isShowCheckedIcon(background_color) && /*#__PURE__*/React.createElement("i", {
|
|
53
50
|
className: "sdoc-callout-color-checked-icon sdocfont sdoc-check-mark"
|
|
54
51
|
}));
|
|
55
52
|
}))));
|
|
56
53
|
};
|
|
57
|
-
export default
|
|
54
|
+
export default ColorSelector;
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
/* eslint-disable react-hooks/rules-of-hooks */
|
|
2
|
-
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
|
-
import {
|
|
2
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { Node } from '@seafile/slate';
|
|
4
|
+
import { useReadOnly, useSelected } from '@seafile/slate-react';
|
|
4
5
|
import { useTranslation } from 'react-i18next';
|
|
5
6
|
import ColorSelector from './color-selector';
|
|
6
7
|
import { CALLOUT_COLOR_MAP } from '../constant';
|
|
7
|
-
import { isFocusOnElement } from '../helper';
|
|
8
|
-
import { Editor } from '@seafile/slate';
|
|
9
|
-
import { findPath } from '../../../core';
|
|
10
8
|
import { INTERNAL_EVENT } from '../../../../constants';
|
|
11
9
|
import EventBus from '../../../../utils/event-bus';
|
|
12
10
|
import { useScrollContext } from '../../../../hooks/use-scroll-context';
|
|
@@ -17,24 +15,40 @@ const renderCallout = (_ref, editor) => {
|
|
|
17
15
|
children,
|
|
18
16
|
element
|
|
19
17
|
} = _ref;
|
|
20
|
-
const [isShowColorSelector, setIsShowColorSelector] = useState(false);
|
|
21
|
-
const [popoverPosition, setPopoverPosition] = useState({
|
|
22
|
-
top: '',
|
|
23
|
-
left: ''
|
|
24
|
-
});
|
|
25
18
|
const readOnly = useReadOnly();
|
|
26
19
|
const scrollRef = useScrollContext();
|
|
27
|
-
const
|
|
28
|
-
const colorSelectorRef = useRef({
|
|
29
|
-
colorSelectorContainer: null
|
|
30
|
-
});
|
|
20
|
+
const isSelected = useSelected();
|
|
31
21
|
const {
|
|
32
22
|
t
|
|
33
23
|
} = useTranslation();
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
24
|
+
const calloutRef = useRef();
|
|
25
|
+
const [isShowColorSelector, setIsShowColorSelector] = useState(false);
|
|
26
|
+
const [popoverPosition, setPopoverPosition] = useState({
|
|
27
|
+
top: '',
|
|
28
|
+
left: ''
|
|
29
|
+
});
|
|
30
|
+
const containerStyle = useMemo(() => {
|
|
31
|
+
const {
|
|
32
|
+
background_color = 'transparent'
|
|
33
|
+
} = element.style;
|
|
34
|
+
let borderColor = 'transparent';
|
|
35
|
+
if (isSelected) {
|
|
36
|
+
var _CALLOUT_COLOR_MAP$ba;
|
|
37
|
+
borderColor = (_CALLOUT_COLOR_MAP$ba = CALLOUT_COLOR_MAP[background_color]) === null || _CALLOUT_COLOR_MAP$ba === void 0 ? void 0 : _CALLOUT_COLOR_MAP$ba.border_color;
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
backgroundColor: background_color,
|
|
41
|
+
borderColor
|
|
42
|
+
};
|
|
43
|
+
}, [element.style, isSelected]);
|
|
44
|
+
const isShowPlaceholder = useCallback(() => {
|
|
45
|
+
if (isSelected) return false;
|
|
46
|
+
// If element contains more than one element or element is not paragraph, show placeholder
|
|
47
|
+
const isContainUnitElement = element.children.length !== 1 || element.children.some(childElement => childElement.type !== 'paragraph');
|
|
48
|
+
if (isContainUnitElement) return false;
|
|
49
|
+
const elementContent = Node.string(element);
|
|
50
|
+
return !elementContent.length;
|
|
51
|
+
}, [element, isSelected]);
|
|
38
52
|
const handleCloseColorSelector = useCallback(() => {
|
|
39
53
|
setIsShowColorSelector(false);
|
|
40
54
|
}, []);
|
|
@@ -87,15 +101,6 @@ const renderCallout = (_ref, editor) => {
|
|
|
87
101
|
const handleClick = useCallback(e => {
|
|
88
102
|
handleDisplayColorSelector();
|
|
89
103
|
}, [handleDisplayColorSelector]);
|
|
90
|
-
const isShowPlaceholder = useCallback(() => {
|
|
91
|
-
if (isFocusOnCallout) return false;
|
|
92
|
-
// If element contains more than one element or element is not paragraph, show placeholder
|
|
93
|
-
const isContainUnitElement = element.children.length !== 1 || element.children.some(childElement => childElement.type !== 'paragraph');
|
|
94
|
-
if (isContainUnitElement) return false;
|
|
95
|
-
const elementPath = findPath(editor, element);
|
|
96
|
-
const elementContent = Editor.string(editor, elementPath);
|
|
97
|
-
return !elementContent.length;
|
|
98
|
-
}, [editor, element, isFocusOnCallout]);
|
|
99
104
|
return /*#__PURE__*/React.createElement("div", Object.assign({}, attributes, {
|
|
100
105
|
"data-id": element.id,
|
|
101
106
|
className: "sdoc-callout-white-wrapper",
|
|
@@ -104,15 +109,11 @@ const renderCallout = (_ref, editor) => {
|
|
|
104
109
|
onClick: handleClick,
|
|
105
110
|
ref: calloutRef,
|
|
106
111
|
className: "".concat(attributes.className, " sdoc-callout-container"),
|
|
107
|
-
style:
|
|
108
|
-
backgroundColor: background_color ? CALLOUT_COLOR_MAP[background_color].background_color : 'transparent',
|
|
109
|
-
borderColor: isFocusOnCallout ? CALLOUT_COLOR_MAP[background_color].border_color : 'transparent'
|
|
110
|
-
}
|
|
112
|
+
style: containerStyle
|
|
111
113
|
}, children, isShowPlaceholder() && /*#__PURE__*/React.createElement("div", {
|
|
112
114
|
contentEditable: false,
|
|
113
115
|
className: "sdoc-callout-placeholder"
|
|
114
116
|
}, t('Please_enter...')), isShowColorSelector && /*#__PURE__*/React.createElement(ColorSelector, {
|
|
115
|
-
ref: colorSelectorRef,
|
|
116
117
|
editor: editor,
|
|
117
118
|
element: element,
|
|
118
119
|
popoverPosition: popoverPosition
|
|
@@ -112,7 +112,7 @@ const withImage = editor => {
|
|
|
112
112
|
} = editor;
|
|
113
113
|
const focusPoint = Editor.before(editor, selection);
|
|
114
114
|
const point = Editor.before(editor, selection, {
|
|
115
|
-
distance:
|
|
115
|
+
distance: 1
|
|
116
116
|
});
|
|
117
117
|
if (!point) return;
|
|
118
118
|
const [node, path] = Editor.node(editor, [point.path[0], point.path[1]]);
|
|
@@ -12,7 +12,8 @@ const SearchReplaceMenu = _ref => {
|
|
|
12
12
|
let {
|
|
13
13
|
isRichEditor,
|
|
14
14
|
className,
|
|
15
|
-
editor
|
|
15
|
+
editor,
|
|
16
|
+
readonly
|
|
16
17
|
} = _ref;
|
|
17
18
|
const [isOpenPopover, setIsOpenPopover] = useState(false);
|
|
18
19
|
useEffect(() => {
|
|
@@ -38,7 +39,7 @@ const SearchReplaceMenu = _ref => {
|
|
|
38
39
|
clientHeight
|
|
39
40
|
};
|
|
40
41
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
41
|
-
}, [isOpenPopover
|
|
42
|
+
}, [isOpenPopover]);
|
|
42
43
|
const renderCanvasses = useMemo(() => {
|
|
43
44
|
if (!isOpenPopover) return false;
|
|
44
45
|
const generateCount = Math.ceil(articleContainerSize.offsetHeight / 5000);
|
|
@@ -66,6 +67,7 @@ const SearchReplaceMenu = _ref => {
|
|
|
66
67
|
onMouseDown: onMouseDown
|
|
67
68
|
}, menuConfig)), isOpenPopover && /*#__PURE__*/React.createElement(SearchReplacePopover, {
|
|
68
69
|
editor: editor,
|
|
70
|
+
readonly: readonly,
|
|
69
71
|
isOpen: isOpenPopover,
|
|
70
72
|
closePopover: onMouseDown
|
|
71
73
|
}), isOpenPopover && createPortal( /*#__PURE__*/React.createElement("div", {
|
|
@@ -52,6 +52,13 @@
|
|
|
52
52
|
justify-content: space-between;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
.sdoc-search-replace-popover-body .sdoc-search-replace-popover-btn-group .btn {
|
|
56
|
+
padding: 0;
|
|
57
|
+
width: 23%;
|
|
58
|
+
min-height: 35px;
|
|
59
|
+
border-radius: 5px;
|
|
60
|
+
}
|
|
61
|
+
|
|
55
62
|
.sdoc-replace-all-confirm-modal {
|
|
56
63
|
position: absolute;
|
|
57
64
|
top: 0;
|
|
@@ -8,11 +8,13 @@ import { handleReplaceKeyword, getHighlightInfos, drawHighlights } from '../help
|
|
|
8
8
|
import ReplaceAllConfirmModal from './replace-all-confirm-modal';
|
|
9
9
|
import EventBus from '../../../../utils/event-bus';
|
|
10
10
|
import { INTERNAL_EVENT } from '../../../../constants';
|
|
11
|
+
import context from '../../../../../context';
|
|
11
12
|
import './index.css';
|
|
12
13
|
const SearchReplacePopover = _ref => {
|
|
13
14
|
let {
|
|
14
15
|
editor,
|
|
15
|
-
closePopover
|
|
16
|
+
closePopover,
|
|
17
|
+
readonly
|
|
16
18
|
} = _ref;
|
|
17
19
|
const [searchContent, setSearchContent] = useState('');
|
|
18
20
|
const [replacementContent, setReplacementContent] = useState('');
|
|
@@ -44,6 +46,17 @@ const SearchReplacePopover = _ref => {
|
|
|
44
46
|
y: 95
|
|
45
47
|
});
|
|
46
48
|
}, []);
|
|
49
|
+
const isOwnReplacePermission = useMemo(() => {
|
|
50
|
+
if (readonly) return false;
|
|
51
|
+
const isFreezed = context.getSetting('isFreezed');
|
|
52
|
+
if (isFreezed) return false;
|
|
53
|
+
const isPublished = context.getSetting('isPublished');
|
|
54
|
+
const isSdocRevision = context.getSetting('isSdocRevision');
|
|
55
|
+
if (isSdocRevision && isPublished) return false;
|
|
56
|
+
const docPerm = context.getSetting('docPerm');
|
|
57
|
+
if (docPerm === 'rw') return true;
|
|
58
|
+
return false;
|
|
59
|
+
}, [readonly]);
|
|
47
60
|
const handleDrawHighlight = useCallback((editor, keyword) => {
|
|
48
61
|
const newHighlightInfos = getHighlightInfos(editor, keyword);
|
|
49
62
|
setHighlightInfos(newHighlightInfos);
|
|
@@ -193,11 +206,11 @@ const SearchReplacePopover = _ref => {
|
|
|
193
206
|
onClick: handleNext,
|
|
194
207
|
className: "btn btn-secondary"
|
|
195
208
|
}, t('Next')), /*#__PURE__*/React.createElement("button", {
|
|
196
|
-
disabled: !highlightInfos.length,
|
|
209
|
+
disabled: !highlightInfos.length || !isOwnReplacePermission,
|
|
197
210
|
onClick: handleReplace,
|
|
198
211
|
className: "btn btn-primary"
|
|
199
212
|
}, t('Replace')), /*#__PURE__*/React.createElement("button", {
|
|
200
|
-
disabled: !highlightInfos.length,
|
|
213
|
+
disabled: !highlightInfos.length || !isOwnReplacePermission,
|
|
201
214
|
onClick: handleOpenReplaceAllModal,
|
|
202
215
|
className: "btn btn-primary"
|
|
203
216
|
}, t('Replace_all'))))), /*#__PURE__*/React.createElement(ReplaceAllConfirmModal, {
|
|
@@ -38,4 +38,11 @@ export const TABLE_ALTERNATE_HIGHLIGHT_CLASS_MAP = {
|
|
|
38
38
|
'sdoc-table-header-0099f4': 'sdoc-table-body-0099f4'
|
|
39
39
|
};
|
|
40
40
|
export const INHERIT_CELL_STYLE_WHEN_SELECT_SINGLE = ['background_color'];
|
|
41
|
-
export const INHERIT_CELL_STYLE_WHEN_SELECT_MULTIPLE = ['background_color', 'text_align'];
|
|
41
|
+
export const INHERIT_CELL_STYLE_WHEN_SELECT_MULTIPLE = ['background_color', 'text_align'];
|
|
42
|
+
export const RESIZE_MASK_TOP = 'top';
|
|
43
|
+
export const RESIZE_MASK_RIGHT = 'right';
|
|
44
|
+
export const RESIZE_MASK_BOTTOM = 'bottom';
|
|
45
|
+
export const RESIZE_MASK_LEFT = 'left';
|
|
46
|
+
export const RESIZE_HANDLER_ROW = 'row';
|
|
47
|
+
export const RESIZE_HANDLER_COLUMN = 'column';
|
|
48
|
+
export const RESIZE_HANDLER_FIRST_COLUMN = 'first_column';
|
|
@@ -1249,6 +1249,25 @@ export const getRowHeight = (element, rowIndex) => {
|
|
|
1249
1249
|
const rowHeight = style[TABLE_ROW_STYLE.MIN_HEIGHT] || TABLE_ROW_MIN_HEIGHT;
|
|
1250
1250
|
return rowIndex === 0 ? rowHeight + 1 : rowHeight;
|
|
1251
1251
|
};
|
|
1252
|
+
export const getRowDomHeight = (editor, row) => {
|
|
1253
|
+
let height = 0;
|
|
1254
|
+
for (const cell of row.children) {
|
|
1255
|
+
const {
|
|
1256
|
+
is_combined,
|
|
1257
|
+
rowspan = 1
|
|
1258
|
+
} = cell;
|
|
1259
|
+
if (is_combined || rowspan > 1) continue;
|
|
1260
|
+
const cellDom = ReactEditor.toDOMNode(editor, cell);
|
|
1261
|
+
if (!cellDom) break;
|
|
1262
|
+
height = cellDom.getBoundingClientRect().height;
|
|
1263
|
+
break;
|
|
1264
|
+
}
|
|
1265
|
+
// if the row is empty, get the height from style
|
|
1266
|
+
if (!height) {
|
|
1267
|
+
height = row.style[TABLE_ROW_STYLE.MIN_HEIGHT] || TABLE_ROW_MIN_HEIGHT;
|
|
1268
|
+
}
|
|
1269
|
+
return height;
|
|
1270
|
+
};
|
|
1252
1271
|
const normalizeTableCell = (editor, cell) => {
|
|
1253
1272
|
if (!cell) return generateTableCell(editor);
|
|
1254
1273
|
let newCell = _objectSpread({
|
|
@@ -1398,96 +1417,78 @@ export const getCellHighlightClassName = (primaryColorClassName, rowIndex) => {
|
|
|
1398
1417
|
}
|
|
1399
1418
|
return className;
|
|
1400
1419
|
};
|
|
1401
|
-
export const
|
|
1402
|
-
const
|
|
1403
|
-
|
|
1404
|
-
rows.forEach(row => {
|
|
1405
|
-
let cellHeight;
|
|
1406
|
-
row.children.forEach(cell => {
|
|
1407
|
-
const currentCellHeight = ReactEditor.toDOMNode(editor, cell).getBoundingClientRect().height;
|
|
1408
|
-
if (!cellHeight || currentCellHeight < cellHeight) cellHeight = currentCellHeight;
|
|
1409
|
-
});
|
|
1410
|
-
bottomPosition += cellHeight;
|
|
1411
|
-
recorder.push(bottomPosition);
|
|
1412
|
-
});
|
|
1413
|
-
return recorder;
|
|
1420
|
+
export const focusClosestCellWhenJustifyCellSize = (editor, adjustingCell) => {
|
|
1421
|
+
const cellPath = ReactEditor.findPath(editor, adjustingCell);
|
|
1422
|
+
focusEditor(editor, Editor.end(editor, cellPath));
|
|
1414
1423
|
};
|
|
1415
|
-
|
|
1416
|
-
let {
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
positionY,
|
|
1436
|
-
positionX
|
|
1437
|
-
} = mouseDownInfo;
|
|
1438
|
-
const tableScrollWrapper = document.querySelector('.sdoc-table-scroll-wrapper');
|
|
1439
|
-
const scrollX = tableScrollWrapper.scrollLeft;
|
|
1440
|
-
const tableInnerX = positionX - left + scrollX;
|
|
1441
|
-
const tableInnerY = positionY - top;
|
|
1442
|
-
// Calculate columnIndex
|
|
1443
|
-
if (columnIndex === undefined) {
|
|
1444
|
-
let passedColumnsWidth = 0;
|
|
1445
|
-
columns.some((_ref2, index) => {
|
|
1446
|
-
let {
|
|
1447
|
-
width
|
|
1448
|
-
} = _ref2;
|
|
1449
|
-
passedColumnsWidth += width;
|
|
1450
|
-
if (passedColumnsWidth > tableInnerX) {
|
|
1451
|
-
columnIndex = index;
|
|
1452
|
-
return true;
|
|
1453
|
-
}
|
|
1454
|
-
return false;
|
|
1455
|
-
});
|
|
1424
|
+
const searchCombinedMainCell = (table, startRowIndex, startColIndex) => {
|
|
1425
|
+
for (let rowIndex = startRowIndex; rowIndex >= 0; rowIndex--) {
|
|
1426
|
+
const row = table.children[rowIndex];
|
|
1427
|
+
for (let cellIndex = startColIndex; cellIndex >= 0; cellIndex--) {
|
|
1428
|
+
const currentCell = row.children[cellIndex];
|
|
1429
|
+
const {
|
|
1430
|
+
colspan = 0,
|
|
1431
|
+
rowspan = 0
|
|
1432
|
+
} = currentCell;
|
|
1433
|
+
if (colspan <= 1 && rowspan <= 1) continue;
|
|
1434
|
+
const isInColRange = cellIndex + colspan >= startColIndex;
|
|
1435
|
+
const isInRowRange = rowIndex + rowspan >= startRowIndex;
|
|
1436
|
+
if (isInColRange && isInRowRange) {
|
|
1437
|
+
return {
|
|
1438
|
+
currentCell,
|
|
1439
|
+
rowIndex,
|
|
1440
|
+
cellIndex
|
|
1441
|
+
};
|
|
1442
|
+
} else break;
|
|
1443
|
+
}
|
|
1456
1444
|
}
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1445
|
+
};
|
|
1446
|
+
export const getResizeMaskCellInfo = (editor, table, rowIndex, cellIndex) => {
|
|
1447
|
+
// The cell shown cursor as resize (mouse is on this cell)
|
|
1448
|
+
const focusCellIndex = cellIndex;
|
|
1449
|
+
let focusCell = table.children[rowIndex].children[cellIndex];
|
|
1450
|
+
// The cell dominating resize handlers (the true cell to be resized)
|
|
1451
|
+
let cell = table.children[rowIndex].children[cellIndex];
|
|
1452
|
+
// Resolve combined cell
|
|
1453
|
+
if (cell.is_combined) {
|
|
1454
|
+
const targetCellInfo = searchCombinedMainCell(table, rowIndex, cellIndex);
|
|
1455
|
+
cellIndex = targetCellInfo.cellIndex;
|
|
1456
|
+
rowIndex = targetCellInfo.rowIndex;
|
|
1457
|
+
cell = targetCellInfo.currentCell;
|
|
1466
1458
|
}
|
|
1467
|
-
|
|
1468
|
-
const
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1459
|
+
const columns = table.columns;
|
|
1460
|
+
const focussedCell = ReactEditor.toDOMNode(editor, cell);
|
|
1461
|
+
const {
|
|
1462
|
+
colspan,
|
|
1463
|
+
rowspan
|
|
1464
|
+
} = focusCell;
|
|
1465
|
+
let width = columns[cellIndex].width;
|
|
1466
|
+
let height = focussedCell.getBoundingClientRect().height;
|
|
1467
|
+
// Calculate cell width and height
|
|
1468
|
+
if (colspan > 1) {
|
|
1469
|
+
let index = cellIndex + 1;
|
|
1470
|
+
while (index < cellIndex + colspan) {
|
|
1471
|
+
width += columns[index].width;
|
|
1472
|
+
index++;
|
|
1479
1473
|
}
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
}
|
|
1474
|
+
}
|
|
1475
|
+
if (rowspan > 1) {
|
|
1476
|
+
let index = rowIndex + 1;
|
|
1477
|
+
while (index < rowIndex + rowspan) {
|
|
1478
|
+
const currentCell = table.children[index].children[cellIndex];
|
|
1479
|
+
const currentHeight = ReactEditor.toDOMNode(editor, currentCell).getBoundingClientRect().height;
|
|
1480
|
+
height += currentHeight;
|
|
1481
|
+
index++;
|
|
1489
1482
|
}
|
|
1490
1483
|
}
|
|
1491
|
-
|
|
1492
|
-
|
|
1484
|
+
return {
|
|
1485
|
+
width,
|
|
1486
|
+
height,
|
|
1487
|
+
top: focussedCell.offsetTop,
|
|
1488
|
+
left: focussedCell.offsetLeft,
|
|
1489
|
+
rowIndex,
|
|
1490
|
+
cellIndex,
|
|
1491
|
+
cell,
|
|
1492
|
+
focusCellIndex
|
|
1493
|
+
};
|
|
1493
1494
|
};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
margin: 16px 0;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
.sdoc-table-wrapper
|
|
6
|
+
.sdoc-table-wrapper+.sdoc-table-wrapper {
|
|
7
7
|
margin-top: 32px;
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
bottom: -2.5px;
|
|
69
69
|
left: 0;
|
|
70
70
|
z-index: 1;
|
|
71
|
+
pointer-events: none;
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
.sdoc-table-wrapper .table-row-height-just:hover {
|
|
@@ -88,6 +89,7 @@
|
|
|
88
89
|
width: 5px;
|
|
89
90
|
top: 0;
|
|
90
91
|
z-index: 1;
|
|
92
|
+
pointer-events: none;
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
.sdoc-table-wrapper .table-cell-width-just:hover {
|
|
@@ -110,3 +112,47 @@
|
|
|
110
112
|
.sdoc-table-wrapper .sdoc-table-selected-range .table-cell *::selection {
|
|
111
113
|
background-color: unset;
|
|
112
114
|
}
|
|
115
|
+
|
|
116
|
+
.sdoc-table-resize-mask {
|
|
117
|
+
position: absolute;
|
|
118
|
+
top: 0;
|
|
119
|
+
left: 0;
|
|
120
|
+
user-select: none;
|
|
121
|
+
opacity: 0;
|
|
122
|
+
z-index: 2;
|
|
123
|
+
pointer-events: none;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.sdoc-table-resize-mask .sdoc-table-resize-top {
|
|
127
|
+
position: absolute;
|
|
128
|
+
top: 1px;
|
|
129
|
+
width: 100%;
|
|
130
|
+
height: 1px;
|
|
131
|
+
cursor: row-resize;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.sdoc-table-resize-mask>div {
|
|
135
|
+
position: absolute;
|
|
136
|
+
pointer-events: auto;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.sdoc-table-resize-mask .sdoc-table-resize-bottom {
|
|
140
|
+
bottom: 1px;
|
|
141
|
+
width: 100%;
|
|
142
|
+
height: 1px;
|
|
143
|
+
cursor: row-resize;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.sdoc-table-resize-mask .sdoc-table-resize-right {
|
|
147
|
+
right: -1px;
|
|
148
|
+
width: 1px;
|
|
149
|
+
height: 100%;
|
|
150
|
+
cursor: col-resize;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.sdoc-table-resize-mask .sdoc-table-resize-left {
|
|
154
|
+
left: -1px;
|
|
155
|
+
width: 1px;
|
|
156
|
+
height: 100%;
|
|
157
|
+
cursor: col-resize;
|
|
158
|
+
}
|
|
@@ -15,6 +15,7 @@ import { registerResizeEvents, unregisterResizeEvents } from '../../../../utils/
|
|
|
15
15
|
import TableRoot from './table-root';
|
|
16
16
|
import TableHeader from './table-header';
|
|
17
17
|
import { findPath } from '../../../core';
|
|
18
|
+
import ResizeMask from './resize-mask';
|
|
18
19
|
import './index.css';
|
|
19
20
|
import './alternate-color.css';
|
|
20
21
|
const Table = _ref => {
|
|
@@ -36,6 +37,9 @@ const Table = _ref => {
|
|
|
36
37
|
const oldColumns = getTableColumns(editor, element);
|
|
37
38
|
const [columns, setColumns] = useState(oldColumns);
|
|
38
39
|
const path = findPath(editor, element);
|
|
40
|
+
const [resizeCellMaskInfo, setResizeCellMaskInfo] = useState({});
|
|
41
|
+
const [isShowResizeHandlers, setIsShowResizeHandlers] = useState(false);
|
|
42
|
+
const [isDraggingResizeHandler, setIsDraggingResizeHandler] = useState(false);
|
|
39
43
|
const onMouseDown = useCallback(event => {
|
|
40
44
|
if (event.button !== 0) return; // right click not deal
|
|
41
45
|
setIsSettingSelectRange(true);
|
|
@@ -146,7 +150,6 @@ const Table = _ref => {
|
|
|
146
150
|
});
|
|
147
151
|
};
|
|
148
152
|
}
|
|
149
|
-
|
|
150
153
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
151
154
|
}, [element, isSettingSelectRange, selectedRange, element]);
|
|
152
155
|
const setRange = useCallback((table, range) => {
|
|
@@ -168,6 +171,17 @@ const Table = _ref => {
|
|
|
168
171
|
'sdoc-table-selected': isSelected,
|
|
169
172
|
'sdoc-table-selected-range': !ObjectUtils.isSameObject(selectedRange, EMPTY_SELECTED_RANGE)
|
|
170
173
|
});
|
|
174
|
+
const handleShowResizeHandler = useCallback(cellInfo => {
|
|
175
|
+
setResizeCellMaskInfo(cellInfo);
|
|
176
|
+
setIsShowResizeHandlers(true);
|
|
177
|
+
}, []);
|
|
178
|
+
const hideResizeHandlers = useCallback(() => {
|
|
179
|
+
setIsShowResizeHandlers(false);
|
|
180
|
+
setIsDraggingResizeHandler(false);
|
|
181
|
+
}, []);
|
|
182
|
+
const handlerStartDragging = useCallback(() => {
|
|
183
|
+
setIsDraggingResizeHandler(true);
|
|
184
|
+
}, []);
|
|
171
185
|
let style = element.style ? _objectSpread({}, element.style) : {};
|
|
172
186
|
const columnWidthList = columns.map(item => "".concat(item.width, "px"));
|
|
173
187
|
style.gridTemplateColumns = columnWidthList.join(' ');
|
|
@@ -191,8 +205,18 @@ const Table = _ref => {
|
|
|
191
205
|
onMouseDown: onMouseDown,
|
|
192
206
|
ref: table,
|
|
193
207
|
"data-id": element.id
|
|
194
|
-
}, children, !isSettingSelectRange && /*#__PURE__*/React.createElement(
|
|
195
|
-
|
|
208
|
+
}, children, !isSettingSelectRange && /*#__PURE__*/React.createElement(ResizeMask, {
|
|
209
|
+
editor: editor,
|
|
210
|
+
table: element,
|
|
211
|
+
handleShowResizeHandler: handleShowResizeHandler,
|
|
212
|
+
hideResizeHandlers: hideResizeHandlers,
|
|
213
|
+
handlerStartDragging: handlerStartDragging,
|
|
214
|
+
isDraggingResizeHandler: isDraggingResizeHandler
|
|
215
|
+
}), !isSettingSelectRange && isShowResizeHandlers && /*#__PURE__*/React.createElement(ResizeHandlers, {
|
|
216
|
+
hideResizeHandlers: hideResizeHandlers,
|
|
217
|
+
element: element,
|
|
218
|
+
resizeCellMaskInfo: resizeCellMaskInfo,
|
|
219
|
+
isDraggingResizeHandler: isDraggingResizeHandler
|
|
196
220
|
}))))));
|
|
197
221
|
};
|
|
198
222
|
function renderTable(props) {
|