@seafile/sdoc-editor 0.1.48 → 0.1.50
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/assets/css/layout.css +4 -0
- package/dist/basic-sdk/assets/css/sdoc-editor-plugins.css +9 -0
- package/dist/basic-sdk/cursor/helper.js +42 -0
- package/dist/basic-sdk/cursor/use-cursors.js +24 -0
- package/dist/basic-sdk/editor.js +113 -108
- package/dist/basic-sdk/extension/constants/index.js +1 -1
- package/dist/basic-sdk/extension/index.js +4 -3
- package/dist/basic-sdk/extension/menu/context-menu/index.css +1 -0
- package/dist/basic-sdk/extension/menu/context-menu/index.js +37 -0
- package/dist/basic-sdk/extension/menu/index.js +2 -1
- package/dist/basic-sdk/extension/plugins/table/index.js +3 -2
- package/dist/basic-sdk/extension/plugins/table/menu/context-menu/index.css +27 -0
- package/dist/basic-sdk/extension/plugins/table/menu/context-menu/index.js +124 -0
- package/dist/basic-sdk/extension/plugins/table/menu/context-menu/insert-table-element.js +93 -0
- package/dist/basic-sdk/extension/plugins/table/menu/index.js +2 -1
- package/dist/basic-sdk/extension/plugins/table/plugin.js +19 -12
- package/dist/basic-sdk/extension/plugins/table/render/render-table/index.css +8 -0
- package/dist/basic-sdk/extension/plugins/text-style/caret.js +49 -0
- package/dist/basic-sdk/extension/plugins/text-style/render-elem.js +11 -1
- package/dist/basic-sdk/extension/render/render-element.js +6 -1
- package/dist/basic-sdk/extension/render/render-leaf.js +7 -1
- package/dist/basic-sdk/socket/helpers.js +15 -4
- package/dist/basic-sdk/socket/socket-client.js +7 -4
- package/dist/basic-sdk/socket/socket-manager.js +12 -3
- package/dist/basic-sdk/socket/with-socket-io.js +5 -3
- package/dist/basic-sdk/utils/diff.js +1 -0
- package/dist/components/doc-operations/style.css +1 -0
- package/dist/components/modal-portal.js +41 -0
- package/dist/pages/simple-editor.js +2 -5
- package/package.json +4 -2
- package/public/locales/cs/sdoc-editor.json +1 -1
- package/public/locales/de/sdoc-editor.json +1 -1
- package/public/locales/en/sdoc-editor.json +8 -2
- package/public/locales/es/sdoc-editor.json +1 -1
- package/public/locales/es-AR/sdoc-editor.json +1 -1
- package/public/locales/es-MX/sdoc-editor.json +1 -1
- package/public/locales/fr/sdoc-editor.json +1 -1
- package/public/locales/it/sdoc-editor.json +1 -1
- package/public/locales/ru/sdoc-editor.json +1 -1
- package/public/locales/zh-CN/sdoc-editor.json +8 -2
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
|
+
import randomColor from 'randomcolor';
|
|
3
|
+
|
|
4
|
+
// selection: { anchor, focus }
|
|
5
|
+
// cursor: { anchor, focus }
|
|
6
|
+
|
|
7
|
+
export var setCursor = function setCursor(editor, operations, user, selection, cursorData) {
|
|
8
|
+
var clientId = user.username;
|
|
9
|
+
var cursorOps = operations.filter(function (operation) {
|
|
10
|
+
return operation.type === 'set_selection';
|
|
11
|
+
});
|
|
12
|
+
if (!editor.cursors) editor.cursors = {};
|
|
13
|
+
var oldCursor = editor.cursors[clientId] ? editor.cursors[clientId] : {};
|
|
14
|
+
var lastCursorOp = cursorOps[cursorOps.length - 1];
|
|
15
|
+
if (selection) {
|
|
16
|
+
var newCursor = lastCursorOp && lastCursorOp.newProperties || {};
|
|
17
|
+
var newCursorData = _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, oldCursor), newCursor), selection), cursorData);
|
|
18
|
+
editor.cursors[clientId] = newCursorData;
|
|
19
|
+
} else {
|
|
20
|
+
delete editor.cursors[clientId];
|
|
21
|
+
}
|
|
22
|
+
editor.cursors = _objectSpread({}, editor.cursors);
|
|
23
|
+
return editor;
|
|
24
|
+
};
|
|
25
|
+
export var deleteCursor = function deleteCursor(editor, username) {
|
|
26
|
+
delete editor.cursors[username];
|
|
27
|
+
editor.cursors = _objectSpread({}, editor.cursors);
|
|
28
|
+
return editor;
|
|
29
|
+
};
|
|
30
|
+
export var generateCursorData = function generateCursorData(config) {
|
|
31
|
+
var user = config.user;
|
|
32
|
+
var options = {
|
|
33
|
+
luminosity: 'dark',
|
|
34
|
+
format: 'rgba',
|
|
35
|
+
alpha: 1
|
|
36
|
+
};
|
|
37
|
+
var color = randomColor(options);
|
|
38
|
+
return {
|
|
39
|
+
name: user.name,
|
|
40
|
+
color: color
|
|
41
|
+
};
|
|
42
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
export var useCursors = function useCursors(editor) {
|
|
4
|
+
var _useState = useState([]),
|
|
5
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
6
|
+
cursors = _useState2[0],
|
|
7
|
+
setCursors = _useState2[1];
|
|
8
|
+
useEffect(function () {
|
|
9
|
+
var cursors = Object.values(editor.cursors) || [];
|
|
10
|
+
setCursors(cursors);
|
|
11
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
12
|
+
}, []);
|
|
13
|
+
useEffect(function () {
|
|
14
|
+
editor.onCursor = function (editorCursors) {
|
|
15
|
+
var cursors = Object.values(editorCursors) || [];
|
|
16
|
+
setCursors(cursors);
|
|
17
|
+
};
|
|
18
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
19
|
+
}, []);
|
|
20
|
+
return {
|
|
21
|
+
cursors: cursors,
|
|
22
|
+
setCursors: setCursors
|
|
23
|
+
};
|
|
24
|
+
};
|
package/dist/basic-sdk/editor.js
CHANGED
|
@@ -1,122 +1,127 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
|
1
2
|
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import _inherits from "@babel/runtime/helpers/esm/inherits";
|
|
5
|
-
import _createSuper from "@babel/runtime/helpers/esm/createSuper";
|
|
6
|
-
import React from 'react';
|
|
7
|
-
import { Node } from '@seafile/slate';
|
|
3
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
4
|
+
import { Node, Editor } from '@seafile/slate';
|
|
8
5
|
import { Editable, Slate, ReactEditor } from '@seafile/slate-react';
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
6
|
+
import defaultEditor, { renderLeaf, renderElement, Toolbar, ContextMenu } from './extension';
|
|
7
|
+
import { focusEditor } from './extension/core';
|
|
11
8
|
import { withSocketIO } from './socket';
|
|
12
9
|
import withNodeId from './node-id';
|
|
13
10
|
import SDocOutline from './outline';
|
|
14
11
|
import EventProxy from './utils/event-handler';
|
|
15
|
-
import {
|
|
12
|
+
import { useCursors } from './cursor/use-cursors';
|
|
16
13
|
import './assets/css/layout.css';
|
|
17
14
|
import './assets/css/sdoc-editor-plugins.css';
|
|
18
|
-
var SDocEditor =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
slateValue: _toConsumableArray(slateValue)
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
var children = props.document.children;
|
|
49
|
-
_this.state = {
|
|
50
|
-
slateValue: children,
|
|
51
|
-
isLoading: true
|
|
52
|
-
};
|
|
53
|
-
_this.socketManager = null;
|
|
54
|
-
_this.editor = withNodeId(editor);
|
|
55
|
-
if (props.isOpenSocket) {
|
|
56
|
-
var document = props.document,
|
|
57
|
-
config = props.config;
|
|
58
|
-
_this.editor = withSocketIO(_this.editor, {
|
|
59
|
-
document: document,
|
|
60
|
-
config: config
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
_this.eventProxy = new EventProxy(_this.editor);
|
|
64
|
-
_this.renderElement = function (props) {
|
|
65
|
-
return renderElement(props, _this.editor);
|
|
66
|
-
};
|
|
67
|
-
_this.renderLeaf = function (props) {
|
|
68
|
-
return renderLeaf(props, _this.editor);
|
|
15
|
+
var SDocEditor = function SDocEditor(_ref) {
|
|
16
|
+
var document = _ref.document,
|
|
17
|
+
config = _ref.config;
|
|
18
|
+
// init editor
|
|
19
|
+
var editor = useMemo(function () {
|
|
20
|
+
var newEditor = withNodeId(withSocketIO(defaultEditor, {
|
|
21
|
+
document: document,
|
|
22
|
+
config: config
|
|
23
|
+
}));
|
|
24
|
+
var cursors = document.cursors;
|
|
25
|
+
newEditor.cursors = cursors || {};
|
|
26
|
+
return newEditor;
|
|
27
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
28
|
+
}, []);
|
|
29
|
+
|
|
30
|
+
// init eventHandler
|
|
31
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
32
|
+
var eventProxy = useMemo(function () {
|
|
33
|
+
return new EventProxy(editor);
|
|
34
|
+
}, []);
|
|
35
|
+
|
|
36
|
+
// useMount: init socket connection
|
|
37
|
+
useEffect(function () {
|
|
38
|
+
editor.openConnection();
|
|
39
|
+
return function () {
|
|
40
|
+
editor.closeConnection();
|
|
69
41
|
};
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
focusEditor(this.editor, firstNodePath);
|
|
79
|
-
}
|
|
42
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
43
|
+
}, []);
|
|
44
|
+
|
|
45
|
+
// useMount: focus editor
|
|
46
|
+
useEffect(function () {
|
|
47
|
+
if (Node.string(editor) === '') {
|
|
48
|
+
var firstNodePath = ReactEditor.findPath(editor, editor.children[0]);
|
|
49
|
+
focusEditor(editor, firstNodePath);
|
|
80
50
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
51
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
52
|
+
}, []);
|
|
53
|
+
|
|
54
|
+
// handle placeholder
|
|
55
|
+
var onDOMBeforeInput = useCallback(function (e) {
|
|
56
|
+
if (e.data && e.data !== '') {
|
|
57
|
+
var _node$;
|
|
58
|
+
var node = Editor.parent(editor, editor.selection);
|
|
59
|
+
editor.onDOMBeforeInputId = (_node$ = node[0]) === null || _node$ === void 0 ? void 0 : _node$.id;
|
|
60
|
+
setSlateValue(_toConsumableArray(slateValue));
|
|
61
|
+
} else {
|
|
62
|
+
editor.onDOMBeforeInputId = null;
|
|
63
|
+
setSlateValue(_toConsumableArray(slateValue));
|
|
85
64
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
value: slateValue,
|
|
106
|
-
onChange: this.onChange
|
|
107
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
108
|
-
className: "article"
|
|
109
|
-
}, /*#__PURE__*/React.createElement(Editable, {
|
|
110
|
-
renderElement: this.renderElement,
|
|
111
|
-
renderLeaf: this.renderLeaf,
|
|
112
|
-
onKeyDown: this.eventProxy.onKeyDown,
|
|
113
|
-
onDOMBeforeInput: this.onDOMBeforeInput
|
|
114
|
-
}))))));
|
|
65
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
66
|
+
}, []);
|
|
67
|
+
var _useState = useState(false),
|
|
68
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
69
|
+
isShowContextMenu = _useState2[0],
|
|
70
|
+
setContextMenu = _useState2[1];
|
|
71
|
+
var _useState3 = useState({}),
|
|
72
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
73
|
+
menuPosition = _useState4[0],
|
|
74
|
+
setMenuPosition = _useState4[1];
|
|
75
|
+
var onContextMenu = useCallback(function (event) {
|
|
76
|
+
if (editor.isAllInTable()) {
|
|
77
|
+
event.preventDefault();
|
|
78
|
+
var contextMenuPosition = {
|
|
79
|
+
left: event.clientX,
|
|
80
|
+
top: event.clientY
|
|
81
|
+
};
|
|
82
|
+
setContextMenu(true);
|
|
83
|
+
setMenuPosition(contextMenuPosition);
|
|
115
84
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
85
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
86
|
+
}, []);
|
|
87
|
+
var _useState5 = useState(document.children),
|
|
88
|
+
_useState6 = _slicedToArray(_useState5, 2),
|
|
89
|
+
slateValue = _useState6[0],
|
|
90
|
+
setSlateValue = _useState6[1];
|
|
91
|
+
var onChange = useCallback(function (slateValue) {
|
|
92
|
+
setSlateValue(slateValue);
|
|
93
|
+
setContextMenu(false);
|
|
94
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
95
|
+
}, []);
|
|
96
|
+
var _useCursors = useCursors(editor),
|
|
97
|
+
cursors = _useCursors.cursors;
|
|
98
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
|
99
|
+
className: "sdoc-editor-container"
|
|
100
|
+
}, /*#__PURE__*/React.createElement(Toolbar, {
|
|
101
|
+
editor: editor
|
|
102
|
+
}), /*#__PURE__*/React.createElement("div", {
|
|
103
|
+
className: "sdoc-editor-content"
|
|
104
|
+
}, /*#__PURE__*/React.createElement(SDocOutline, {
|
|
105
|
+
doc: slateValue,
|
|
106
|
+
docUuid: config.docUuid
|
|
107
|
+
}), /*#__PURE__*/React.createElement("div", {
|
|
108
|
+
className: "flex-fill o-auto"
|
|
109
|
+
}, /*#__PURE__*/React.createElement(Slate, {
|
|
110
|
+
editor: editor,
|
|
111
|
+
value: slateValue,
|
|
112
|
+
onChange: onChange
|
|
113
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
114
|
+
className: "article"
|
|
115
|
+
}, /*#__PURE__*/React.createElement(Editable, {
|
|
116
|
+
renderElement: renderElement,
|
|
117
|
+
renderLeaf: renderLeaf,
|
|
118
|
+
onKeyDown: eventProxy.onKeyDown,
|
|
119
|
+
onDOMBeforeInput: onDOMBeforeInput,
|
|
120
|
+
cursors: cursors,
|
|
121
|
+
onContextMenu: onContextMenu
|
|
122
|
+
})))))), isShowContextMenu && /*#__PURE__*/React.createElement(ContextMenu, {
|
|
123
|
+
editor: editor,
|
|
124
|
+
contextMenuPosition: menuPosition
|
|
125
|
+
}));
|
|
121
126
|
};
|
|
122
127
|
export default SDocEditor;
|
|
@@ -48,7 +48,7 @@ export var MENUS_CONFIG_MAP = (_MENUS_CONFIG_MAP = {}, _defineProperty(_MENUS_CO
|
|
|
48
48
|
}), _defineProperty(_MENUS_CONFIG_MAP, REMOVE_TABLE, {
|
|
49
49
|
id: "sdoc_".concat(REMOVE_TABLE),
|
|
50
50
|
iconClass: 'sdocfont sdoc-delete-table',
|
|
51
|
-
text: '
|
|
51
|
+
text: 'Remove_table'
|
|
52
52
|
}), _defineProperty(_MENUS_CONFIG_MAP, TEXT_STYLE, [{
|
|
53
53
|
id: ITALIC,
|
|
54
54
|
iconClass: 'sdocfont sdoc-italic',
|
|
@@ -5,13 +5,14 @@ import Plugins from './plugins';
|
|
|
5
5
|
import renderElement from './render/render-element';
|
|
6
6
|
import renderLeaf from './render/render-leaf';
|
|
7
7
|
import Toolbar from './toolbar';
|
|
8
|
+
import { ContextMenu } from './menu';
|
|
8
9
|
var baseEditor = withHistory(withReact(createEditor()));
|
|
9
|
-
var
|
|
10
|
+
var defaultEditor = Plugins.reduce(function (editor, pluginItem) {
|
|
10
11
|
var withPlugin = pluginItem.editorPlugin;
|
|
11
12
|
if (withPlugin) {
|
|
12
13
|
return withPlugin(editor);
|
|
13
14
|
}
|
|
14
15
|
return editor;
|
|
15
16
|
}, baseEditor);
|
|
16
|
-
export default
|
|
17
|
-
export { renderLeaf, renderElement, Toolbar };
|
|
17
|
+
export default defaultEditor;
|
|
18
|
+
export { renderLeaf, renderElement, Toolbar, ContextMenu };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
|
|
2
|
+
import _createClass from "@babel/runtime/helpers/esm/createClass";
|
|
3
|
+
import _inherits from "@babel/runtime/helpers/esm/inherits";
|
|
4
|
+
import _createSuper from "@babel/runtime/helpers/esm/createSuper";
|
|
5
|
+
import React, { Component } from 'react';
|
|
6
|
+
import ModalPortal from '../../../../components/modal-portal';
|
|
7
|
+
import { TablePlugin } from '../../plugins';
|
|
8
|
+
var ContextMenu = /*#__PURE__*/function (_Component) {
|
|
9
|
+
_inherits(ContextMenu, _Component);
|
|
10
|
+
var _super = _createSuper(ContextMenu);
|
|
11
|
+
function ContextMenu() {
|
|
12
|
+
var _this;
|
|
13
|
+
_classCallCheck(this, ContextMenu);
|
|
14
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
15
|
+
args[_key] = arguments[_key];
|
|
16
|
+
}
|
|
17
|
+
_this = _super.call.apply(_super, [this].concat(args));
|
|
18
|
+
_this.renderContextMenu = function () {
|
|
19
|
+
var editor = _this.props.editor;
|
|
20
|
+
if (editor.isAllInTable()) {
|
|
21
|
+
var ContextMenuComponent = TablePlugin.contextMenu;
|
|
22
|
+
return /*#__PURE__*/React.createElement(ContextMenuComponent, _this.props);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
return _this;
|
|
26
|
+
}
|
|
27
|
+
_createClass(ContextMenu, [{
|
|
28
|
+
key: "render",
|
|
29
|
+
value: function render() {
|
|
30
|
+
return /*#__PURE__*/React.createElement(ModalPortal, {
|
|
31
|
+
className: "sdoc-context-menu"
|
|
32
|
+
}, this.renderContextMenu());
|
|
33
|
+
}
|
|
34
|
+
}]);
|
|
35
|
+
return ContextMenu;
|
|
36
|
+
}(Component);
|
|
37
|
+
export default ContextMenu;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TABLE } from '../../constants';
|
|
2
|
-
import { TableMenu } from './menu';
|
|
2
|
+
import { TableMenu, ContextMenu } from './menu';
|
|
3
3
|
import Table from './model';
|
|
4
4
|
import withTable from './plugin';
|
|
5
5
|
import { renderTable, renderTableRow, renderTableCell } from './render-elem';
|
|
@@ -9,6 +9,7 @@ var TablePlugin = {
|
|
|
9
9
|
model: Table,
|
|
10
10
|
editorMenus: [TableMenu],
|
|
11
11
|
editorPlugin: withTable,
|
|
12
|
-
renderElements: [renderTable, renderTableRow, renderTableCell]
|
|
12
|
+
renderElements: [renderTable, renderTableRow, renderTableCell],
|
|
13
|
+
contextMenu: ContextMenu
|
|
13
14
|
};
|
|
14
15
|
export default TablePlugin;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
.sdoc-context-menu .sdoc-table-context-menu {
|
|
2
|
+
display: block;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.sdoc-table-context-menu .insert-number {
|
|
6
|
+
margin-left: 50px;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.sdoc-table-context-menu .insert-number-input {
|
|
10
|
+
width: 36px;
|
|
11
|
+
height: 20px;
|
|
12
|
+
margin-right: .25rem;
|
|
13
|
+
padding-left: 4px;
|
|
14
|
+
padding-right: 4px;
|
|
15
|
+
text-align: center;
|
|
16
|
+
transition: none;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.sdoc-table-context-menu .dropdown-item:hover .insert-number-input {
|
|
20
|
+
background-color: transparent;
|
|
21
|
+
border: 1px solid #fff;
|
|
22
|
+
color: #fff;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.sdoc-table-context-menu .dropdown-item:disabled .insert-number-input {
|
|
26
|
+
color: #adb5bd;
|
|
27
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
|
|
2
|
+
import _createClass from "@babel/runtime/helpers/esm/createClass";
|
|
3
|
+
import _assertThisInitialized from "@babel/runtime/helpers/esm/assertThisInitialized";
|
|
4
|
+
import _inherits from "@babel/runtime/helpers/esm/inherits";
|
|
5
|
+
import _createSuper from "@babel/runtime/helpers/esm/createSuper";
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { withTranslation } from 'react-i18next';
|
|
8
|
+
import ObjectUtils from '../../../../../utils/object-utils';
|
|
9
|
+
import { TABLE_ELEMENT, TABLE_ELEMENT_POSITION, ELEMENT_TYPE } from '../../../../constants';
|
|
10
|
+
import InsertTableElement from './insert-table-element';
|
|
11
|
+
import { getSelectedNodeByType } from '../../../../core';
|
|
12
|
+
import './index.css';
|
|
13
|
+
var ContextMenu = /*#__PURE__*/function (_React$Component) {
|
|
14
|
+
_inherits(ContextMenu, _React$Component);
|
|
15
|
+
var _super = _createSuper(ContextMenu);
|
|
16
|
+
function ContextMenu(props) {
|
|
17
|
+
var _this;
|
|
18
|
+
_classCallCheck(this, ContextMenu);
|
|
19
|
+
_this = _super.call(this, props);
|
|
20
|
+
_this.updateMenuPosition = function () {
|
|
21
|
+
var menuHeight = _this.menu.offsetHeight;
|
|
22
|
+
|
|
23
|
+
// get height of context menu when the menu is drawing completed in this page
|
|
24
|
+
// if (menuHeight === 0) {
|
|
25
|
+
// requestAnimationFrame(this.updateMenuPosition);
|
|
26
|
+
// }
|
|
27
|
+
var top = 0;
|
|
28
|
+
if (_this.position.top + menuHeight > document.body.clientHeight) {
|
|
29
|
+
top = document.body.clientHeight - menuHeight - 5;
|
|
30
|
+
} else {
|
|
31
|
+
top = _this.position.top;
|
|
32
|
+
}
|
|
33
|
+
var left = _this.position.left + 3;
|
|
34
|
+
_this.setState({
|
|
35
|
+
contextStyle: {
|
|
36
|
+
top: top,
|
|
37
|
+
left: left
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
_this.insertTableElement = function (type, position, count) {
|
|
42
|
+
var editor = _this.props.editor;
|
|
43
|
+
editor.insertTableElement(type, position, count);
|
|
44
|
+
};
|
|
45
|
+
_this.removeTableElement = function (type) {
|
|
46
|
+
var editor = _this.props.editor;
|
|
47
|
+
editor.removeTableElement(type);
|
|
48
|
+
};
|
|
49
|
+
_this.renderRemoveBtn = function (type, title) {
|
|
50
|
+
return /*#__PURE__*/React.createElement("button", {
|
|
51
|
+
onMouseDown: _this.removeTableElement.bind(_assertThisInitialized(_this), type),
|
|
52
|
+
className: "dropdown-item"
|
|
53
|
+
}, _this.props.t(title));
|
|
54
|
+
};
|
|
55
|
+
_this.state = {
|
|
56
|
+
contextStyle: {}
|
|
57
|
+
};
|
|
58
|
+
_this.position = null;
|
|
59
|
+
return _this;
|
|
60
|
+
}
|
|
61
|
+
_createClass(ContextMenu, [{
|
|
62
|
+
key: "componentDidMount",
|
|
63
|
+
value: function componentDidMount() {
|
|
64
|
+
this.position = this.props.contextMenuPosition;
|
|
65
|
+
this.updateMenuPosition();
|
|
66
|
+
}
|
|
67
|
+
}, {
|
|
68
|
+
key: "UNSAFE_componentWillReceiveProps",
|
|
69
|
+
value: function UNSAFE_componentWillReceiveProps(nextProps) {
|
|
70
|
+
var nextContextMenuPosition = nextProps.contextMenuPosition;
|
|
71
|
+
if (!ObjectUtils.isSameObject(nextContextMenuPosition, this.props.contextMenuPosition)) {
|
|
72
|
+
this.position = nextContextMenuPosition;
|
|
73
|
+
this.updateMenuPosition();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}, {
|
|
77
|
+
key: "componentWillUnmount",
|
|
78
|
+
value: function componentWillUnmount() {
|
|
79
|
+
this.menu = null;
|
|
80
|
+
}
|
|
81
|
+
}, {
|
|
82
|
+
key: "render",
|
|
83
|
+
value: function render() {
|
|
84
|
+
var _this2 = this;
|
|
85
|
+
var contextStyle = this.state.contextStyle;
|
|
86
|
+
var editor = this.props.editor;
|
|
87
|
+
var currentTable = getSelectedNodeByType(editor, ELEMENT_TYPE.TABLE);
|
|
88
|
+
var currentRow = getSelectedNodeByType(editor, ELEMENT_TYPE.TABLE_ROW);
|
|
89
|
+
var currentRowsCount = currentTable.children.length;
|
|
90
|
+
var currentColumnsCount = currentRow.children.length;
|
|
91
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
92
|
+
style: contextStyle,
|
|
93
|
+
ref: function ref(_ref) {
|
|
94
|
+
return _this2.menu = _ref;
|
|
95
|
+
},
|
|
96
|
+
className: "sdoc-table-context-menu dropdown-menu"
|
|
97
|
+
}, /*#__PURE__*/React.createElement(InsertTableElement, {
|
|
98
|
+
type: TABLE_ELEMENT.ROW,
|
|
99
|
+
currentCount: currentRowsCount,
|
|
100
|
+
position: TABLE_ELEMENT_POSITION.BEFORE,
|
|
101
|
+
insertTableElement: this.insertTableElement
|
|
102
|
+
}), /*#__PURE__*/React.createElement(InsertTableElement, {
|
|
103
|
+
type: TABLE_ELEMENT.ROW,
|
|
104
|
+
currentCount: currentRowsCount,
|
|
105
|
+
position: TABLE_ELEMENT_POSITION.AFTER,
|
|
106
|
+
insertTableElement: this.insertTableElement
|
|
107
|
+
}), /*#__PURE__*/React.createElement(InsertTableElement, {
|
|
108
|
+
type: TABLE_ELEMENT.COLUMN,
|
|
109
|
+
currentCount: currentColumnsCount,
|
|
110
|
+
position: TABLE_ELEMENT_POSITION.BEFORE,
|
|
111
|
+
insertTableElement: this.insertTableElement
|
|
112
|
+
}), /*#__PURE__*/React.createElement(InsertTableElement, {
|
|
113
|
+
type: TABLE_ELEMENT.COLUMN,
|
|
114
|
+
currentCount: currentColumnsCount,
|
|
115
|
+
position: TABLE_ELEMENT_POSITION.AFTER,
|
|
116
|
+
insertTableElement: this.insertTableElement
|
|
117
|
+
}), /*#__PURE__*/React.createElement("div", {
|
|
118
|
+
className: 'seafile-divider dropdown-divider'
|
|
119
|
+
}), this.renderRemoveBtn(TABLE_ELEMENT.ROW, 'Remove_Row'), this.renderRemoveBtn(TABLE_ELEMENT.COLUMN, 'Remove_Column'), this.renderRemoveBtn(TABLE_ELEMENT.TABLE, 'Remove_table'));
|
|
120
|
+
}
|
|
121
|
+
}]);
|
|
122
|
+
return ContextMenu;
|
|
123
|
+
}(React.Component);
|
|
124
|
+
export default withTranslation('sdoc-editor')(ContextMenu);
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
|
|
2
|
+
import _createClass from "@babel/runtime/helpers/esm/createClass";
|
|
3
|
+
import _inherits from "@babel/runtime/helpers/esm/inherits";
|
|
4
|
+
import _createSuper from "@babel/runtime/helpers/esm/createSuper";
|
|
5
|
+
import React, { Component } from 'react';
|
|
6
|
+
import { withTranslation } from 'react-i18next';
|
|
7
|
+
import { Input } from 'reactstrap';
|
|
8
|
+
import isHotkey from 'is-hotkey';
|
|
9
|
+
import { TABLE_ELEMENT, TABLE_ELEMENT_POSITION } from '../../../../constants';
|
|
10
|
+
import { TABLE_MAX_COLUMNS, TABLE_MAX_ROWS } from '../../constants';
|
|
11
|
+
var InsertTableElement = /*#__PURE__*/function (_Component) {
|
|
12
|
+
_inherits(InsertTableElement, _Component);
|
|
13
|
+
var _super = _createSuper(InsertTableElement);
|
|
14
|
+
function InsertTableElement(props) {
|
|
15
|
+
var _this;
|
|
16
|
+
_classCallCheck(this, InsertTableElement);
|
|
17
|
+
_this = _super.call(this, props);
|
|
18
|
+
_this.insertTableElement = function () {
|
|
19
|
+
var _this$props = _this.props,
|
|
20
|
+
type = _this$props.type,
|
|
21
|
+
position = _this$props.position;
|
|
22
|
+
var count = _this.state.count;
|
|
23
|
+
_this.props.insertTableElement(type, position, count);
|
|
24
|
+
};
|
|
25
|
+
_this.getTip = function () {
|
|
26
|
+
var _this$props2 = _this.props,
|
|
27
|
+
type = _this$props2.type,
|
|
28
|
+
position = _this$props2.position,
|
|
29
|
+
t = _this$props2.t;
|
|
30
|
+
if (type === TABLE_ELEMENT.ROW) {
|
|
31
|
+
return position === TABLE_ELEMENT_POSITION.AFTER ? t('Insert_below') : t('Insert_above');
|
|
32
|
+
}
|
|
33
|
+
return position === TABLE_ELEMENT_POSITION.AFTER ? t('Insert_on_the_right') : t('Insert_on_the_left');
|
|
34
|
+
};
|
|
35
|
+
_this.onKeyDown = function (event) {
|
|
36
|
+
if (isHotkey('enter', event)) {
|
|
37
|
+
event.preventDefault();
|
|
38
|
+
_this.insertTableElement();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
_this.onChange = function (event) {
|
|
43
|
+
var value = event.target.value || '0';
|
|
44
|
+
var newValue = value ? value.replace(/[^\d,]/g, '') : value;
|
|
45
|
+
if (newValue === _this.state.count) return;
|
|
46
|
+
var currentCount = _this.props.currentCount;
|
|
47
|
+
var numberValue = parseInt(newValue);
|
|
48
|
+
if (currentCount + numberValue > _this.maxCount) {
|
|
49
|
+
_this.setState({
|
|
50
|
+
count: _this.maxCount - currentCount
|
|
51
|
+
});
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
_this.setState({
|
|
55
|
+
count: numberValue
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
_this.state = {
|
|
59
|
+
count: 1
|
|
60
|
+
};
|
|
61
|
+
_this.maxCount = props.type === TABLE_ELEMENT.ROW ? TABLE_MAX_ROWS : TABLE_MAX_COLUMNS;
|
|
62
|
+
return _this;
|
|
63
|
+
}
|
|
64
|
+
_createClass(InsertTableElement, [{
|
|
65
|
+
key: "render",
|
|
66
|
+
value: function render() {
|
|
67
|
+
var count = this.state.count;
|
|
68
|
+
var _this$props3 = this.props,
|
|
69
|
+
t = _this$props3.t,
|
|
70
|
+
type = _this$props3.type,
|
|
71
|
+
currentCount = _this$props3.currentCount;
|
|
72
|
+
var isDisabled = currentCount >= this.maxCount;
|
|
73
|
+
return /*#__PURE__*/React.createElement("button", {
|
|
74
|
+
onMouseDown: this.insertTableElement,
|
|
75
|
+
className: "dropdown-item d-flex align-items-center justify-content-between",
|
|
76
|
+
disabled: isDisabled
|
|
77
|
+
}, this.getTip(), /*#__PURE__*/React.createElement("div", {
|
|
78
|
+
className: "insert-number d-flex align-items-center"
|
|
79
|
+
}, /*#__PURE__*/React.createElement(Input, {
|
|
80
|
+
disabled: isDisabled,
|
|
81
|
+
className: "insert-number-input",
|
|
82
|
+
onMouseDown: function onMouseDown(e) {
|
|
83
|
+
e.stopPropagation();
|
|
84
|
+
},
|
|
85
|
+
onKeyDown: this.onKeyDown,
|
|
86
|
+
value: count,
|
|
87
|
+
onChange: this.onChange
|
|
88
|
+
}), /*#__PURE__*/React.createElement("span", null, type === TABLE_ELEMENT.ROW ? t('row(s)') : t('column(s)'))));
|
|
89
|
+
}
|
|
90
|
+
}]);
|
|
91
|
+
return InsertTableElement;
|
|
92
|
+
}(Component);
|
|
93
|
+
export default withTranslation('sdoc-editor')(InsertTableElement);
|
|
@@ -489,31 +489,38 @@ var withTable = function withTable(editor) {
|
|
|
489
489
|
};
|
|
490
490
|
newEditor.insertTableElement = function (type) {
|
|
491
491
|
var position = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : TABLE_ELEMENT_POSITION.AFTER;
|
|
492
|
+
var count = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
|
|
492
493
|
var _getSelectedInfo7 = getSelectedInfo(newEditor),
|
|
493
494
|
tablePath = _getSelectedInfo7.tablePath,
|
|
494
495
|
tableSize = _getSelectedInfo7.tableSize,
|
|
495
496
|
rowIndex = _getSelectedInfo7.rowIndex,
|
|
496
497
|
cellIndex = _getSelectedInfo7.cellIndex;
|
|
497
498
|
if (type === TABLE_ELEMENT.ROW) {
|
|
498
|
-
if (tableSize[0]
|
|
499
|
+
if (tableSize[0] >= TABLE_MAX_ROWS) return;
|
|
499
500
|
var targetPath = position === TABLE_ELEMENT_POSITION.AFTER ? [].concat(_toConsumableArray(tablePath), [rowIndex + 1]) : [].concat(_toConsumableArray(tablePath), [rowIndex]);
|
|
500
|
-
var
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
501
|
+
var validCount = Math.min(TABLE_MAX_ROWS - tableSize[0], count);
|
|
502
|
+
for (var i = 0; i < validCount; i++) {
|
|
503
|
+
var row = generateTableRow(tableSize[1]);
|
|
504
|
+
Transforms.insertNodes(editor, row, {
|
|
505
|
+
at: targetPath
|
|
506
|
+
});
|
|
507
|
+
}
|
|
504
508
|
var focusPath = [].concat(_toConsumableArray(targetPath), [cellIndex]);
|
|
505
509
|
focusEditor(newEditor, focusPath);
|
|
506
510
|
return;
|
|
507
511
|
}
|
|
508
512
|
if (type === TABLE_ELEMENT.COLUMN) {
|
|
509
|
-
if (tableSize[1]
|
|
513
|
+
if (tableSize[1] >= TABLE_MAX_COLUMNS) return;
|
|
510
514
|
var newCellIndex = position === TABLE_ELEMENT_POSITION.AFTER ? cellIndex + 1 : cellIndex;
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
var
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
515
|
+
var _validCount = Math.min(TABLE_MAX_COLUMNS - tableSize[1], count);
|
|
516
|
+
for (var j = 0; j < _validCount; j++) {
|
|
517
|
+
for (var _i = 0; _i < tableSize[0]; _i++) {
|
|
518
|
+
var newCellPath = [].concat(_toConsumableArray(tablePath), [_i, newCellIndex]);
|
|
519
|
+
var newCell = generateTableCell();
|
|
520
|
+
Transforms.insertNodes(editor, newCell, {
|
|
521
|
+
at: newCellPath
|
|
522
|
+
});
|
|
523
|
+
}
|
|
517
524
|
}
|
|
518
525
|
var _focusPath = [].concat(_toConsumableArray(tablePath), [rowIndex, cellIndex + 1, 0]);
|
|
519
526
|
focusEditor(newEditor, _focusPath);
|
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
border-bottom: none;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
.sdoc-table-wrapper {
|
|
25
|
+
overflow: scroll;
|
|
26
|
+
}
|
|
27
|
+
|
|
24
28
|
.sdoc-table-wrapper tr:first-child {
|
|
25
29
|
font-weight: unset;
|
|
26
30
|
}
|
|
@@ -28,3 +32,7 @@
|
|
|
28
32
|
.sdoc-table-wrapper tr:nth-child(2n+1) {
|
|
29
33
|
background-color: unset;
|
|
30
34
|
}
|
|
35
|
+
|
|
36
|
+
.article .sdoc-table-wrapper td {
|
|
37
|
+
min-width: 35px;
|
|
38
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
var cursorStyleBase = {
|
|
4
|
+
position: 'absolute',
|
|
5
|
+
top: -2,
|
|
6
|
+
pointerEvents: 'none',
|
|
7
|
+
userSelect: 'none',
|
|
8
|
+
transform: 'translateY(-100%)',
|
|
9
|
+
fontSize: 10,
|
|
10
|
+
color: 'white',
|
|
11
|
+
background: 'palevioletred',
|
|
12
|
+
whiteSpace: 'nowrap'
|
|
13
|
+
};
|
|
14
|
+
var caretStyleBase = {
|
|
15
|
+
position: 'absolute',
|
|
16
|
+
// pointerEvents: 'none',
|
|
17
|
+
userSelect: 'none',
|
|
18
|
+
height: '1.2em',
|
|
19
|
+
width: 2,
|
|
20
|
+
background: 'palevioletred'
|
|
21
|
+
};
|
|
22
|
+
var Caret = function Caret(_ref) {
|
|
23
|
+
var color = _ref.color,
|
|
24
|
+
name = _ref.name;
|
|
25
|
+
var cursorStyles = _objectSpread(_objectSpread({}, cursorStyleBase), {}, {
|
|
26
|
+
background: color,
|
|
27
|
+
left: '0%',
|
|
28
|
+
cursor: 'default'
|
|
29
|
+
});
|
|
30
|
+
var caretStyles = _objectSpread(_objectSpread({}, caretStyleBase), {}, {
|
|
31
|
+
background: color,
|
|
32
|
+
left: '0%'
|
|
33
|
+
});
|
|
34
|
+
caretStyles['top'] = 1;
|
|
35
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", {
|
|
36
|
+
className: "caret-item",
|
|
37
|
+
contentEditable: false,
|
|
38
|
+
style: caretStyles
|
|
39
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
40
|
+
style: {
|
|
41
|
+
position: 'relative'
|
|
42
|
+
}
|
|
43
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
44
|
+
className: "caret-name",
|
|
45
|
+
contentEditable: false,
|
|
46
|
+
style: cursorStyles
|
|
47
|
+
}, name))));
|
|
48
|
+
};
|
|
49
|
+
export default Caret;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import Caret from './caret';
|
|
2
3
|
var renderText = function renderText(props, editor) {
|
|
3
4
|
var attributes = props.attributes,
|
|
4
5
|
children = props.children,
|
|
@@ -38,8 +39,17 @@ var renderText = function renderText(props, editor) {
|
|
|
38
39
|
className: "token ".concat(leaf.type)
|
|
39
40
|
}, markedChildren);
|
|
40
41
|
}
|
|
42
|
+
var style = {
|
|
43
|
+
position: 'relative'
|
|
44
|
+
};
|
|
45
|
+
if (leaf.isCaret) {
|
|
46
|
+
style['display'] = 'inline-block';
|
|
47
|
+
style['minWidth'] = '2px';
|
|
48
|
+
}
|
|
41
49
|
return /*#__PURE__*/React.createElement("span", Object.assign({
|
|
42
50
|
"data-id": leaf.id
|
|
43
|
-
}, attributes
|
|
51
|
+
}, attributes, {
|
|
52
|
+
style: style
|
|
53
|
+
}), leaf.isCaret ? /*#__PURE__*/React.createElement(Caret, leaf) : null, markedChildren);
|
|
44
54
|
};
|
|
45
55
|
export default renderText;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Node, Editor } from '@seafile/slate';
|
|
4
|
+
import { useSlateStatic } from '@seafile/slate-react';
|
|
4
5
|
import { BLOCKQUOTE, LINK, CHECK_LIST_ITEM, HEADER1, HEADER2, HEADER3, HEADER4, HEADER5, HEADER6, LIST_ITEM, LIST_LIC, ORDERED_LIST, PARAGRAPH, UNORDERED_LIST, CODE_BLOCK, IMAGE, ELEMENT_TYPE } from '../constants';
|
|
5
6
|
import { BlockquotePlugin, LinkPlugin, CheckListPlugin, HeaderPlugin, ListPlugin, CodeBlockPlugin, ImagePlugin, TablePlugin } from '../plugins';
|
|
6
7
|
import { Placeholder, findNode } from '../core';
|
|
7
|
-
var
|
|
8
|
+
var CustomElement = function CustomElement(props) {
|
|
9
|
+
var editor = useSlateStatic();
|
|
8
10
|
var attributes = props.attributes,
|
|
9
11
|
children = props.children,
|
|
10
12
|
element = props.element;
|
|
@@ -127,4 +129,7 @@ var renderElement = function renderElement(props, editor) {
|
|
|
127
129
|
}
|
|
128
130
|
}
|
|
129
131
|
};
|
|
132
|
+
var renderElement = function renderElement(props) {
|
|
133
|
+
return /*#__PURE__*/React.createElement(CustomElement, props);
|
|
134
|
+
};
|
|
130
135
|
export default renderElement;
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useSlateStatic } from '@seafile/slate-react';
|
|
2
4
|
import { TextPlugin } from '../plugins';
|
|
3
|
-
var
|
|
5
|
+
var CustomLeaf = function CustomLeaf(props) {
|
|
6
|
+
var editor = useSlateStatic();
|
|
4
7
|
var _TextPlugin$renderEle = _slicedToArray(TextPlugin.renderElements, 1),
|
|
5
8
|
renderText = _TextPlugin$renderEle[0];
|
|
6
9
|
return renderText(props, editor);
|
|
7
10
|
};
|
|
11
|
+
var renderLeaf = function renderLeaf(props) {
|
|
12
|
+
return /*#__PURE__*/React.createElement(CustomLeaf, props);
|
|
13
|
+
};
|
|
8
14
|
export default renderLeaf;
|
|
@@ -3,6 +3,7 @@ import deepCopy from 'deep-copy';
|
|
|
3
3
|
import { Editor, Operation } from '@seafile/slate';
|
|
4
4
|
import { getNode } from '../extension/core';
|
|
5
5
|
import * as OPERATION from '../node-id/constants';
|
|
6
|
+
import { setCursor } from '../cursor/helper';
|
|
6
7
|
export var getNodePathById = function getNodePathById(rootNode, nodeId) {
|
|
7
8
|
var path = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
|
|
8
9
|
if (rootNode.id === nodeId) return path;
|
|
@@ -250,11 +251,21 @@ export var reExecRevertOperationList = function reExecRevertOperationList(editor
|
|
|
250
251
|
_loop2();
|
|
251
252
|
}
|
|
252
253
|
};
|
|
253
|
-
export var syncRemoteOperations = function syncRemoteOperations(editor, remoteOperations) {
|
|
254
|
+
export var syncRemoteOperations = function syncRemoteOperations(editor, remoteOperations, user, selection, cursorData) {
|
|
254
255
|
if (remoteOperations.length === 0) return;
|
|
255
256
|
Editor.withoutNormalizing(editor, function () {
|
|
256
|
-
remoteOperations.
|
|
257
|
-
|
|
258
|
-
|
|
257
|
+
for (var i = 0; i < remoteOperations.length; i++) {
|
|
258
|
+
var op = remoteOperations[i];
|
|
259
|
+
if (op.type === 'set_selection') {
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
editor.apply(op);
|
|
263
|
+
}
|
|
264
|
+
var currentUser = editor.user;
|
|
265
|
+
if (user && user.username !== currentUser.username) {
|
|
266
|
+
setCursor(editor, remoteOperations, user, selection, cursorData);
|
|
267
|
+
// sync cursor position
|
|
268
|
+
editor.onCursor && editor.onCursor(editor.cursors);
|
|
269
|
+
}
|
|
259
270
|
});
|
|
260
271
|
};
|
|
@@ -11,10 +11,12 @@ var SocketClient = /*#__PURE__*/_createClass(function SocketClient(config) {
|
|
|
11
11
|
var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
12
12
|
var _this$config = _this.config,
|
|
13
13
|
docUuid = _this$config.docUuid,
|
|
14
|
-
user = _this$config.user
|
|
14
|
+
user = _this$config.user,
|
|
15
|
+
cursorData = _this$config.cursorData;
|
|
15
16
|
return _objectSpread({
|
|
16
17
|
doc_uuid: docUuid,
|
|
17
|
-
user: user
|
|
18
|
+
user: user,
|
|
19
|
+
cursor_data: cursorData
|
|
18
20
|
}, params);
|
|
19
21
|
};
|
|
20
22
|
this.onConnected = function () {
|
|
@@ -76,13 +78,14 @@ var SocketClient = /*#__PURE__*/_createClass(function SocketClient(config) {
|
|
|
76
78
|
var socketManager = SocketManager.getInstance();
|
|
77
79
|
socketManager.dispatchConnectState('leave-room', username);
|
|
78
80
|
};
|
|
79
|
-
this.sendOperations = function (operations, version, callback) {
|
|
81
|
+
this.sendOperations = function (operations, version, selection, callback) {
|
|
80
82
|
debug('=========== send operations ==========');
|
|
81
83
|
debug('%O', operations);
|
|
82
84
|
debug('======================================');
|
|
83
85
|
_this.socket.emit('update-document', _this.getParams({
|
|
84
86
|
operations: operations,
|
|
85
|
-
version: version
|
|
87
|
+
version: version,
|
|
88
|
+
selection: selection
|
|
86
89
|
}), function (result) {
|
|
87
90
|
callback && callback(result);
|
|
88
91
|
});
|
|
@@ -4,6 +4,7 @@ import EventBus from '../utils/event-bus';
|
|
|
4
4
|
import { syncRemoteOperations, reExecRevertOperationList, revertOperationList } from './helpers';
|
|
5
5
|
import SocketClient from './socket-client';
|
|
6
6
|
import debug from '../utils/debug';
|
|
7
|
+
import { deleteCursor } from '../cursor/helper';
|
|
7
8
|
var SocketManager = /*#__PURE__*/_createClass(function SocketManager(editor, document, config) {
|
|
8
9
|
var _this = this;
|
|
9
10
|
_classCallCheck(this, SocketManager);
|
|
@@ -28,7 +29,8 @@ var SocketManager = /*#__PURE__*/_createClass(function SocketManager(editor, doc
|
|
|
28
29
|
_this.dispatchConnectState('is-saving');
|
|
29
30
|
var version = _this.document.version;
|
|
30
31
|
var operations = _this.pendingOperationList.shift();
|
|
31
|
-
|
|
32
|
+
var selection = _this.editor.selection;
|
|
33
|
+
_this.socketClient.sendOperations(operations, version, selection, _this.sendOperationsCallback);
|
|
32
34
|
};
|
|
33
35
|
this.sendOperationsCallback = function (result) {
|
|
34
36
|
if (result && result.success) {
|
|
@@ -83,10 +85,13 @@ var SocketManager = /*#__PURE__*/_createClass(function SocketManager(editor, doc
|
|
|
83
85
|
}
|
|
84
86
|
|
|
85
87
|
// 2. execute operations
|
|
86
|
-
var operations = params.operations
|
|
88
|
+
var operations = params.operations,
|
|
89
|
+
user = params.user,
|
|
90
|
+
selection = params.selection,
|
|
91
|
+
cursorData = params.cursor_data;
|
|
87
92
|
// 2.1 Update content & version
|
|
88
93
|
debug('execute remote operations: %O', operations);
|
|
89
|
-
syncRemoteOperations(_this.editor, operations);
|
|
94
|
+
syncRemoteOperations(_this.editor, operations, user, selection, cursorData);
|
|
90
95
|
|
|
91
96
|
// 2.2 Update document
|
|
92
97
|
_this.document.version = serverVersion;
|
|
@@ -157,6 +162,10 @@ var SocketManager = /*#__PURE__*/_createClass(function SocketManager(editor, doc
|
|
|
157
162
|
});
|
|
158
163
|
};
|
|
159
164
|
this.dispatchConnectState = function (type, message) {
|
|
165
|
+
if (type === 'leave-room') {
|
|
166
|
+
deleteCursor(_this.editor, message);
|
|
167
|
+
_this.editor.onCursor && _this.editor.onCursor(_this.editor.cursors);
|
|
168
|
+
}
|
|
160
169
|
_this.eventBus.dispatch(type, message);
|
|
161
170
|
};
|
|
162
171
|
this.closeSocketConnect = function () {
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
var _this = this;
|
|
2
|
+
import { generateCursorData } from '../cursor/helper';
|
|
2
3
|
import SocketManager from './socket-manager';
|
|
3
4
|
var withSocketIO = function withSocketIO(editor, options) {
|
|
4
5
|
var onChange = editor.onChange;
|
|
5
6
|
var newEditor = editor;
|
|
6
7
|
var socketManager = null;
|
|
8
|
+
var user = options.config.user;
|
|
9
|
+
newEditor.user = user;
|
|
7
10
|
newEditor.openConnection = function () {
|
|
8
11
|
var document = options.document,
|
|
9
12
|
config = options.config;
|
|
13
|
+
var cursorData = generateCursorData(options.config);
|
|
14
|
+
config['cursorData'] = cursorData;
|
|
10
15
|
socketManager = SocketManager.getInstance(newEditor, document, config);
|
|
11
16
|
};
|
|
12
17
|
newEditor.closeConnection = function () {
|
|
@@ -14,9 +19,6 @@ var withSocketIO = function withSocketIO(editor, options) {
|
|
|
14
19
|
};
|
|
15
20
|
newEditor.onChange = function () {
|
|
16
21
|
var operations = newEditor.operations;
|
|
17
|
-
operations = operations.filter(function (item) {
|
|
18
|
-
return item.type !== 'set_selection';
|
|
19
|
-
});
|
|
20
22
|
if (!newEditor.isRemote && operations.length > 0) {
|
|
21
23
|
var _socketManager = SocketManager.getInstance();
|
|
22
24
|
_socketManager.addOperations && _socketManager.addOperations(operations);
|
|
@@ -3,6 +3,7 @@ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
|
3
3
|
import { DIFF_TYPE, ELEMENT_TYPE } from '../../basic-sdk/extension/constants';
|
|
4
4
|
import ObjectUtils from './object-utils';
|
|
5
5
|
var getElementIndexInDiffDocument = function getElementIndexInDiffDocument(diffValue, element) {
|
|
6
|
+
if (!diffValue || !element) return -1;
|
|
6
7
|
return diffValue.findIndex(function (item) {
|
|
7
8
|
return item.id === element.id;
|
|
8
9
|
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
|
|
2
|
+
import _createClass from "@babel/runtime/helpers/esm/createClass";
|
|
3
|
+
import _inherits from "@babel/runtime/helpers/esm/inherits";
|
|
4
|
+
import _createSuper from "@babel/runtime/helpers/esm/createSuper";
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import ReactDOM from 'react-dom';
|
|
7
|
+
var ModalPortal = /*#__PURE__*/function (_React$Component) {
|
|
8
|
+
_inherits(ModalPortal, _React$Component);
|
|
9
|
+
var _super = _createSuper(ModalPortal);
|
|
10
|
+
function ModalPortal(props) {
|
|
11
|
+
var _this;
|
|
12
|
+
_classCallCheck(this, ModalPortal);
|
|
13
|
+
_this = _super.call(this, props);
|
|
14
|
+
_this.state = {
|
|
15
|
+
isMounted: false
|
|
16
|
+
};
|
|
17
|
+
_this.el = document.createElement('div');
|
|
18
|
+
if (props.className) {
|
|
19
|
+
_this.el.className = props.className;
|
|
20
|
+
}
|
|
21
|
+
return _this;
|
|
22
|
+
}
|
|
23
|
+
_createClass(ModalPortal, [{
|
|
24
|
+
key: "componentDidMount",
|
|
25
|
+
value: function componentDidMount() {
|
|
26
|
+
document.body.appendChild(this.el);
|
|
27
|
+
}
|
|
28
|
+
}, {
|
|
29
|
+
key: "componentWillUnmount",
|
|
30
|
+
value: function componentWillUnmount() {
|
|
31
|
+
document.body.removeChild(this.el);
|
|
32
|
+
}
|
|
33
|
+
}, {
|
|
34
|
+
key: "render",
|
|
35
|
+
value: function render() {
|
|
36
|
+
return ReactDOM.createPortal(this.props.children, this.el);
|
|
37
|
+
}
|
|
38
|
+
}]);
|
|
39
|
+
return ModalPortal;
|
|
40
|
+
}(React.Component);
|
|
41
|
+
export default ModalPortal;
|
|
@@ -37,9 +37,6 @@ var SimpleEditor = /*#__PURE__*/function (_React$Component) {
|
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
|
-
_this.setEditorRef = function (ref) {
|
|
41
|
-
_this.editorRef = ref;
|
|
42
|
-
};
|
|
43
40
|
_this.state = {
|
|
44
41
|
isContextInit: false,
|
|
45
42
|
errorMessage: null,
|
|
@@ -68,7 +65,8 @@ var SimpleEditor = /*#__PURE__*/function (_React$Component) {
|
|
|
68
65
|
if (result && !result.children) {
|
|
69
66
|
result = {
|
|
70
67
|
version: 0,
|
|
71
|
-
children: result.content
|
|
68
|
+
children: result.content,
|
|
69
|
+
cursors: result.cursors || {}
|
|
72
70
|
};
|
|
73
71
|
}
|
|
74
72
|
this.setState({
|
|
@@ -115,7 +113,6 @@ var SimpleEditor = /*#__PURE__*/function (_React$Component) {
|
|
|
115
113
|
}
|
|
116
114
|
var isOpenSocket = context.getSetting('isOpenSocket');
|
|
117
115
|
return /*#__PURE__*/React.createElement(Layout, null, /*#__PURE__*/React.createElement(Header, null, /*#__PURE__*/React.createElement(DocInfo, null), /*#__PURE__*/React.createElement(DocOperations, null)), /*#__PURE__*/React.createElement(Content, null, /*#__PURE__*/React.createElement(SDocEditor, {
|
|
118
|
-
ref: this.setEditorRef,
|
|
119
116
|
config: context.getEditorConfig(),
|
|
120
117
|
document: document,
|
|
121
118
|
isOpenSocket: isOpenSocket,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seafile/sdoc-editor",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.50",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "This is a sdoc editor",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,11 +9,13 @@
|
|
|
9
9
|
"@seafile/slate": "0.91.8",
|
|
10
10
|
"@seafile/slate-history": "0.86.2",
|
|
11
11
|
"@seafile/slate-hyperscript": "0.81.7",
|
|
12
|
-
"@seafile/slate-react": "0.92.
|
|
12
|
+
"@seafile/slate-react": "0.92.5",
|
|
13
|
+
"ahooks": "3.7.7",
|
|
13
14
|
"classnames": "2.3.2",
|
|
14
15
|
"deep-copy": "1.4.2",
|
|
15
16
|
"is-hotkey": "0.2.0",
|
|
16
17
|
"is-url": "^1.2.4",
|
|
18
|
+
"randomcolor": "0.6.2",
|
|
17
19
|
"react-cookies": "0.1.1",
|
|
18
20
|
"reactstrap": "8.9.0",
|
|
19
21
|
"slugid": "3.2.0",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"switch_to_rich_text_editor": "Přepnout do rozšířeného textového editoru",
|
|
30
30
|
"switch_to_viewer": "Přepnout do značkovacího prohlížeče",
|
|
31
31
|
"help": "Pomoc",
|
|
32
|
-
"
|
|
32
|
+
"Remove_table": "Odebrat tabulku",
|
|
33
33
|
"column": "Sloupec",
|
|
34
34
|
"row": "Řádek",
|
|
35
35
|
"set_align": "Nastavit zarovnání",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"switch_to_rich_text_editor": "Zum Editor mit Formatierungen wechseln",
|
|
30
30
|
"switch_to_viewer": "Zur Markdown-Vorschau wechseln",
|
|
31
31
|
"help": "Hilfe",
|
|
32
|
-
"
|
|
32
|
+
"Remove_table": "Tabelle entfernen",
|
|
33
33
|
"column": "Spalte",
|
|
34
34
|
"row": "Zeile",
|
|
35
35
|
"set_align": "Ausrichtung festlegen",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"switch_to_rich_text_editor": "Switch to Rich Text Editor",
|
|
35
35
|
"switch_to_viewer": "Switch to Markdown Viewer",
|
|
36
36
|
"help": "Help",
|
|
37
|
-
"
|
|
37
|
+
"Remove_table": "Remove table",
|
|
38
38
|
"column": "Column",
|
|
39
39
|
"row": "Row",
|
|
40
40
|
"Insert_Row_Before": "Insert Row Before",
|
|
@@ -246,5 +246,11 @@
|
|
|
246
246
|
"Rows": "Rows",
|
|
247
247
|
"Columns": "Columns",
|
|
248
248
|
"Please_enter_title": "Please enter title",
|
|
249
|
-
"Please_enter_text": "Please enter text"
|
|
249
|
+
"Please_enter_text": "Please enter text",
|
|
250
|
+
"row(s)": "row(s)",
|
|
251
|
+
"column(s)": "column(s)",
|
|
252
|
+
"Insert_below": "Insert below",
|
|
253
|
+
"Insert_above": "Insert above",
|
|
254
|
+
"Insert_on_the_right": "Insert on the right",
|
|
255
|
+
"Insert_on_the_left": "Insert on the left"
|
|
250
256
|
}
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"switch_to_rich_text_editor": "Cambiar a editor de texto enriquecido",
|
|
30
30
|
"switch_to_viewer": "Cambiar a visualizador Markdown",
|
|
31
31
|
"help": "Ayuda",
|
|
32
|
-
"
|
|
32
|
+
"Remove_table": "Eliminar tabla",
|
|
33
33
|
"column": "Columna",
|
|
34
34
|
"row": "Fila",
|
|
35
35
|
"set_align": "Establecer alineación",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"switch_to_rich_text_editor": "Cambiar a editor de texto enriquecido",
|
|
30
30
|
"switch_to_viewer": "Cambiar a visualizador Markdown",
|
|
31
31
|
"help": "Ayuda",
|
|
32
|
-
"
|
|
32
|
+
"Remove_table": "Eliminar tabla",
|
|
33
33
|
"column": "Columna",
|
|
34
34
|
"row": "Fila",
|
|
35
35
|
"set_align": "Establecer alineación",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"switch_to_rich_text_editor": "Cambiar a editor de texto enriquecido",
|
|
30
30
|
"switch_to_viewer": "Cambiar a visualizador Markdown",
|
|
31
31
|
"help": "Ayuda",
|
|
32
|
-
"
|
|
32
|
+
"Remove_table": "Eliminar tabla",
|
|
33
33
|
"column": "Columna",
|
|
34
34
|
"row": "Fila",
|
|
35
35
|
"set_align": "Establecer alineación",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"switch_to_rich_text_editor": "Basculer en éditeur de texte riche",
|
|
30
30
|
"switch_to_viewer": "Basculer en visualiseur Markdown",
|
|
31
31
|
"help": "Aide",
|
|
32
|
-
"
|
|
32
|
+
"Remove_table": "Supprimer la table",
|
|
33
33
|
"column": "Colonne",
|
|
34
34
|
"row": "Ligne",
|
|
35
35
|
"set_align": "Ajuster l'alignement",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"switch_to_rich_text_editor": "Passa all'Editor di testo formattato",
|
|
30
30
|
"switch_to_viewer": "Passa alla vista di tipo Markdown",
|
|
31
31
|
"help": "Aiuto",
|
|
32
|
-
"
|
|
32
|
+
"Remove_table": "Rimuovere Tabella",
|
|
33
33
|
"column": "Colonna",
|
|
34
34
|
"row": "Riga",
|
|
35
35
|
"set_align": "Imposta allineamento",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"switch_to_rich_text_editor": "Переключиться на визуальный редактор",
|
|
30
30
|
"switch_to_viewer": "Переключиться на просмотр Markdown",
|
|
31
31
|
"help": "Помощь",
|
|
32
|
-
"
|
|
32
|
+
"Remove_table": "Удалить таблицу",
|
|
33
33
|
"column": "Столбец",
|
|
34
34
|
"row": "Строка",
|
|
35
35
|
"set_align": "Установить выравнивание",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"switch_to_rich_text_editor": "切换至富文本编辑器",
|
|
33
33
|
"switch_to_viewer": "切换到只读模式",
|
|
34
34
|
"help": "帮助",
|
|
35
|
-
"
|
|
35
|
+
"Remove_table": "删除表格",
|
|
36
36
|
"column": "列",
|
|
37
37
|
"row": "行",
|
|
38
38
|
"Insert_Row_Before": "上方插入行",
|
|
@@ -238,5 +238,11 @@
|
|
|
238
238
|
"Rows": "行数",
|
|
239
239
|
"Columns": "列数",
|
|
240
240
|
"Please_enter_title": "请输入标题",
|
|
241
|
-
"Please_enter_text": "请输入正文"
|
|
241
|
+
"Please_enter_text": "请输入正文",
|
|
242
|
+
"row(s)": "行",
|
|
243
|
+
"column(s)": "列",
|
|
244
|
+
"Insert_above": "在上方插入",
|
|
245
|
+
"Insert_below": "在下方插入",
|
|
246
|
+
"Insert_on_the_right": "在右侧插入",
|
|
247
|
+
"Insert_on_the_left": "在左侧插入"
|
|
242
248
|
}
|