@seafile/sdoc-editor 0.1.50 → 0.1.52

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.
@@ -4,17 +4,12 @@ import randomColor from 'randomcolor';
4
4
  // selection: { anchor, focus }
5
5
  // cursor: { anchor, focus }
6
6
 
7
- export var setCursor = function setCursor(editor, operations, user, selection, cursorData) {
7
+ export var setCursor = function setCursor(editor, user, location, cursorData) {
8
8
  var clientId = user.username;
9
- var cursorOps = operations.filter(function (operation) {
10
- return operation.type === 'set_selection';
11
- });
12
9
  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);
10
+ if (location) {
11
+ var oldCursor = editor.cursors[clientId] ? editor.cursors[clientId] : {};
12
+ var newCursorData = _objectSpread(_objectSpread(_objectSpread({}, oldCursor), location), cursorData);
18
13
  editor.cursors[clientId] = newCursorData;
19
14
  } else {
20
15
  delete editor.cursors[clientId];
@@ -1,7 +1,6 @@
1
1
  import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
2
- import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
3
2
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
4
- import { Node, Editor } from '@seafile/slate';
3
+ import { Node } from '@seafile/slate';
5
4
  import { Editable, Slate, ReactEditor } from '@seafile/slate-react';
6
5
  import defaultEditor, { renderLeaf, renderElement, Toolbar, ContextMenu } from './extension';
7
6
  import { focusEditor } from './extension/core';
@@ -26,6 +25,20 @@ var SDocEditor = function SDocEditor(_ref) {
26
25
  return newEditor;
27
26
  // eslint-disable-next-line react-hooks/exhaustive-deps
28
27
  }, []);
28
+ var _useState = useState(document.children),
29
+ _useState2 = _slicedToArray(_useState, 2),
30
+ slateValue = _useState2[0],
31
+ setSlateValue = _useState2[1];
32
+ var _useState3 = useState(false),
33
+ _useState4 = _slicedToArray(_useState3, 2),
34
+ isShowContextMenu = _useState4[0],
35
+ setContextMenu = _useState4[1];
36
+ var _useState5 = useState({}),
37
+ _useState6 = _slicedToArray(_useState5, 2),
38
+ menuPosition = _useState6[0],
39
+ setMenuPosition = _useState6[1];
40
+ var _useCursors = useCursors(editor),
41
+ cursors = _useCursors.cursors;
29
42
 
30
43
  // init eventHandler
31
44
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -50,28 +63,6 @@ var SDocEditor = function SDocEditor(_ref) {
50
63
  }
51
64
  // eslint-disable-next-line react-hooks/exhaustive-deps
52
65
  }, []);
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));
64
- }
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
66
  var onContextMenu = useCallback(function (event) {
76
67
  if (editor.isAllInTable()) {
77
68
  event.preventDefault();
@@ -84,17 +75,11 @@ var SDocEditor = function SDocEditor(_ref) {
84
75
  }
85
76
  // eslint-disable-next-line react-hooks/exhaustive-deps
86
77
  }, []);
87
- var _useState5 = useState(document.children),
88
- _useState6 = _slicedToArray(_useState5, 2),
89
- slateValue = _useState6[0],
90
- setSlateValue = _useState6[1];
91
78
  var onChange = useCallback(function (slateValue) {
92
79
  setSlateValue(slateValue);
93
80
  setContextMenu(false);
94
81
  // eslint-disable-next-line react-hooks/exhaustive-deps
95
82
  }, []);
96
- var _useCursors = useCursors(editor),
97
- cursors = _useCursors.cursors;
98
83
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
99
84
  className: "sdoc-editor-container"
100
85
  }, /*#__PURE__*/React.createElement(Toolbar, {
@@ -116,7 +101,6 @@ var SDocEditor = function SDocEditor(_ref) {
116
101
  renderElement: renderElement,
117
102
  renderLeaf: renderLeaf,
118
103
  onKeyDown: eventProxy.onKeyDown,
119
- onDOMBeforeInput: onDOMBeforeInput,
120
104
  cursors: cursors,
121
105
  onContextMenu: onContextMenu
122
106
  })))))), isShowContextMenu && /*#__PURE__*/React.createElement(ContextMenu, {
@@ -4,13 +4,14 @@ import { Placeholder } from '../../core';
4
4
  var renderHeader = function renderHeader(props, editor) {
5
5
  var element = props.element,
6
6
  attributes = props.attributes,
7
- children = props.children;
7
+ children = props.children,
8
+ isComposing = props.isComposing;
8
9
  var type = element.type;
9
10
  var level = type.split('header')[1];
10
11
  var Tag = "h".concat(level);
11
12
  var isShowPlaceHolder = false;
12
13
  var firstChild = editor.children[0];
13
- if (firstChild.id === element.id && Node.string(element) === '' && (editor === null || editor === void 0 ? void 0 : editor.onDOMBeforeInputId) !== (element === null || element === void 0 ? void 0 : element.id)) {
14
+ if (firstChild.id === element.id && Node.string(element) === '' && !isComposing) {
14
15
  isShowPlaceHolder = true;
15
16
  }
16
17
  return /*#__PURE__*/React.createElement(Tag, Object.assign({
@@ -1,10 +1,10 @@
1
1
  import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
2
2
  import React from 'react';
3
- import { Node, Editor } from '@seafile/slate';
3
+ import { Node } from '@seafile/slate';
4
4
  import { useSlateStatic } from '@seafile/slate-react';
5
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';
6
6
  import { BlockquotePlugin, LinkPlugin, CheckListPlugin, HeaderPlugin, ListPlugin, CodeBlockPlugin, ImagePlugin, TablePlugin } from '../plugins';
7
- import { Placeholder, findNode } from '../core';
7
+ import { Placeholder } from '../core';
8
8
  var CustomElement = function CustomElement(props) {
9
9
  var editor = useSlateStatic();
10
10
  var attributes = props.attributes,
@@ -14,22 +14,13 @@ var CustomElement = function CustomElement(props) {
14
14
  case PARAGRAPH:
15
15
  {
16
16
  var isShowPlaceHolder = false;
17
- if (editor.children.length < 3) {
18
- var firstParagraphNode = findNode(editor, {
19
- at: [],
20
- match: function match(node) {
21
- return node.type === 'paragraph';
22
- }
23
- });
24
- if (firstParagraphNode) {
25
- var _firstParagraphNode = _slicedToArray(firstParagraphNode, 2),
26
- node = _firstParagraphNode[0],
27
- path = _firstParagraphNode[1];
28
- var nextNode = Editor.next(editor, {
29
- at: path
30
- });
31
- isShowPlaceHolder = (node === null || node === void 0 ? void 0 : node.id) === (element === null || element === void 0 ? void 0 : element.id) && Node.string(element) === '' && !nextNode && (editor === null || editor === void 0 ? void 0 : editor.onDOMBeforeInputId) !== (element === null || element === void 0 ? void 0 : element.id);
32
- }
17
+ var isComposing = props.isComposing;
18
+ if (editor.children.length === 1) {
19
+ isShowPlaceHolder = Node.string(element) === '' && !isComposing;
20
+ }
21
+ if (editor.children.length === 2 && editor.children[0].type.startsWith('header')) {
22
+ var node = editor.children[1];
23
+ isShowPlaceHolder = Node.string(element) === '' && (node === null || node === void 0 ? void 0 : node.id) === (element === null || element === void 0 ? void 0 : element.id) && !isComposing;
33
24
  }
34
25
  return /*#__PURE__*/React.createElement("p", Object.assign({
35
26
  "data-id": element.id
@@ -251,7 +251,7 @@ export var reExecRevertOperationList = function reExecRevertOperationList(editor
251
251
  _loop2();
252
252
  }
253
253
  };
254
- export var syncRemoteOperations = function syncRemoteOperations(editor, remoteOperations, user, selection, cursorData) {
254
+ export var syncRemoteOperations = function syncRemoteOperations(editor, remoteOperations) {
255
255
  if (remoteOperations.length === 0) return;
256
256
  Editor.withoutNormalizing(editor, function () {
257
257
  for (var i = 0; i < remoteOperations.length; i++) {
@@ -261,11 +261,14 @@ export var syncRemoteOperations = function syncRemoteOperations(editor, remoteOp
261
261
  }
262
262
  editor.apply(op);
263
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
- }
270
264
  });
265
+ };
266
+ export var syncRemoteCursorLocation = function syncRemoteCursorLocation(editor, user, location, cursorData) {
267
+ var currentUser = editor.user;
268
+ if (user && user.username !== currentUser.username) {
269
+ setCursor(editor, user, location, cursorData);
270
+
271
+ // sync cursor position
272
+ editor.onCursor && editor.onCursor(editor.cursors);
273
+ }
271
274
  };
@@ -11,12 +11,10 @@ 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,
15
- cursorData = _this$config.cursorData;
14
+ user = _this$config.user;
16
15
  return _objectSpread({
17
16
  doc_uuid: docUuid,
18
- user: user,
19
- cursor_data: cursorData
17
+ user: user
20
18
  }, params);
21
19
  };
22
20
  this.onConnected = function () {
@@ -114,6 +112,17 @@ var SocketClient = /*#__PURE__*/_createClass(function SocketClient(config) {
114
112
  }
115
113
  });
116
114
  };
115
+ this.sendCursorLocation = function (location) {
116
+ var cursor_data = _this.config.cursorData;
117
+ _this.socket.emit('update-cursor', _this.getParams({
118
+ location: location,
119
+ cursor_data: cursor_data
120
+ }));
121
+ };
122
+ this.receiveCursorLocation = function (params) {
123
+ var socketManager = SocketManager.getInstance();
124
+ socketManager.receiveCursorLocation(params);
125
+ };
117
126
  this.disconnectWithServer = function () {
118
127
  _this.socket.disconnect();
119
128
  };
@@ -131,6 +140,7 @@ var SocketClient = /*#__PURE__*/_createClass(function SocketClient(config) {
131
140
  this.socket.on('join-room', this.onJoinRoom);
132
141
  this.socket.on('leave-room', this.onLeaveRoom);
133
142
  this.socket.on('update-document', this.receiveOperations);
143
+ this.socket.on('update-cursor', this.receiveCursorLocation);
134
144
  this.socket.io.on('reconnect', this.onReconnect);
135
145
  this.socket.io.on('reconnect_attempt', this.onReconnectAttempt);
136
146
  this.socket.io.on('reconnect_error', this.onReconnectError);
@@ -1,7 +1,7 @@
1
1
  import _createClass from "@babel/runtime/helpers/esm/createClass";
2
2
  import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
3
3
  import EventBus from '../utils/event-bus';
4
- import { syncRemoteOperations, reExecRevertOperationList, revertOperationList } from './helpers';
4
+ import { syncRemoteOperations, reExecRevertOperationList, revertOperationList, syncRemoteCursorLocation } from './helpers';
5
5
  import SocketClient from './socket-client';
6
6
  import debug from '../utils/debug';
7
7
  import { deleteCursor } from '../cursor/helper';
@@ -85,13 +85,10 @@ var SocketManager = /*#__PURE__*/_createClass(function SocketManager(editor, doc
85
85
  }
86
86
 
87
87
  // 2. execute operations
88
- var operations = params.operations,
89
- user = params.user,
90
- selection = params.selection,
91
- cursorData = params.cursor_data;
88
+ var operations = params.operations;
92
89
  // 2.1 Update content & version
93
90
  debug('execute remote operations: %O', operations);
94
- syncRemoteOperations(_this.editor, operations, user, selection, cursorData);
91
+ syncRemoteOperations(_this.editor, operations);
95
92
 
96
93
  // 2.2 Update document
97
94
  _this.document.version = serverVersion;
@@ -161,6 +158,16 @@ var SocketManager = /*#__PURE__*/_createClass(function SocketManager(editor, doc
161
158
  _this.editor.isRemote = false;
162
159
  });
163
160
  };
161
+ this.sendCursorLocation = function (location) {
162
+ _this.socketClient.sendCursorLocation(location);
163
+ };
164
+ this.receiveCursorLocation = function (params) {
165
+ var user = params.user,
166
+ location = params.location,
167
+ cursorData = params.cursor_data;
168
+ syncRemoteCursorLocation(_this.editor, user, location, cursorData);
169
+ return;
170
+ };
164
171
  this.dispatchConnectState = function (type, message) {
165
172
  if (type === 'leave-room') {
166
173
  deleteCursor(_this.editor, message);
@@ -20,8 +20,18 @@ var withSocketIO = function withSocketIO(editor, options) {
20
20
  newEditor.onChange = function () {
21
21
  var operations = newEditor.operations;
22
22
  if (!newEditor.isRemote && operations.length > 0) {
23
+ var isAllSetSelection = operations.every(function (operation) {
24
+ return operation.type === 'set_selection';
25
+ });
23
26
  var _socketManager = SocketManager.getInstance();
24
- _socketManager.addOperations && _socketManager.addOperations(operations);
27
+ if (!isAllSetSelection) {
28
+ // get update content value operations
29
+ var updateOperations = operations.filter(function (operation) {
30
+ return operation.type !== 'set_selection';
31
+ });
32
+ _socketManager.addOperations && _socketManager.addOperations(updateOperations);
33
+ }
34
+ _socketManager.sendCursorLocation(editor.selection);
25
35
  }
26
36
  onChange();
27
37
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seafile/sdoc-editor",
3
- "version": "0.1.50",
3
+ "version": "0.1.52",
4
4
  "private": false,
5
5
  "description": "This is a sdoc editor",
6
6
  "main": "dist/index.js",
@@ -9,7 +9,7 @@
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.5",
12
+ "@seafile/slate-react": "0.92.6",
13
13
  "ahooks": "3.7.7",
14
14
  "classnames": "2.3.2",
15
15
  "deep-copy": "1.4.2",