@textbus/collaborate 2.0.0-alpha.37 → 2.0.0-alpha.38

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,4 @@
1
+ export * from './collaborate-cursor';
1
2
  export * from './collaborate-history';
2
3
  export * from './local-to-remote';
3
4
  export * from './remote-to-local';
@@ -1,3 +1,4 @@
1
+ export * from './collaborate-cursor';
1
2
  export * from './collaborate-history';
2
3
  export * from './local-to-remote';
3
4
  export * from './remote-to-local';
@@ -1 +1 @@
1
- {"version":3,"file":"_api.js","sourceRoot":"","sources":["../../src/collab/_api.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA"}
1
+ {"version":3,"file":"_api.js","sourceRoot":"","sources":["../../src/collab/_api.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA"}
@@ -0,0 +1,25 @@
1
+ import { SelectionBridge } from '@textbus/browser';
2
+ import { Selection, SelectionPaths } from '@textbus/core';
3
+ export interface RemoteSelection {
4
+ color: string;
5
+ username: string;
6
+ paths: SelectionPaths;
7
+ }
8
+ export interface SelectionRect {
9
+ x: number;
10
+ y: number;
11
+ width: number;
12
+ height: number;
13
+ color: string;
14
+ }
15
+ export declare class CollaborateCursor {
16
+ private container;
17
+ private document;
18
+ private nativeSelection;
19
+ private selection;
20
+ private canvas;
21
+ private context;
22
+ private onRectChange;
23
+ constructor(container: HTMLElement, document: Document, nativeSelection: SelectionBridge, selection: Selection);
24
+ draw(paths: RemoteSelection[]): void;
25
+ }
@@ -0,0 +1,108 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { Inject, Injectable } from '@tanbo/di';
14
+ import { createElement, EDITABLE_DOCUMENT, EDITOR_CONTAINER, SelectionBridge } from '@textbus/browser';
15
+ import { Selection } from '@textbus/core';
16
+ import { Subject } from '@tanbo/stream';
17
+ let CollaborateCursor = class CollaborateCursor {
18
+ constructor(container, document, nativeSelection, selection) {
19
+ this.container = container;
20
+ this.document = document;
21
+ this.nativeSelection = nativeSelection;
22
+ this.selection = selection;
23
+ this.canvas = createElement('canvas', {
24
+ styles: {
25
+ position: 'absolute',
26
+ opacity: 0.5,
27
+ left: 0,
28
+ top: 0,
29
+ width: '100%',
30
+ height: '100%',
31
+ pointerEvents: 'none'
32
+ }
33
+ });
34
+ this.context = this.canvas.getContext('2d');
35
+ this.onRectChange = new Subject();
36
+ container.appendChild(this.canvas);
37
+ this.onRectChange.subscribe(rect => {
38
+ this.context.fillStyle = rect.color;
39
+ this.context.beginPath();
40
+ this.context.rect(Math.ceil(rect.x), Math.ceil(rect.y), Math.ceil(rect.width), Math.ceil(rect.height));
41
+ this.context.fill();
42
+ this.context.closePath();
43
+ });
44
+ }
45
+ draw(paths) {
46
+ this.canvas.width = this.container.offsetWidth;
47
+ this.canvas.height = this.container.offsetHeight;
48
+ this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
49
+ paths.filter(i => {
50
+ return i.paths.start.length && i.paths.end.length;
51
+ }).forEach(item => {
52
+ const startOffset = item.paths.start.pop();
53
+ const startSlot = this.selection.findSlotByPaths(item.paths.start);
54
+ const endOffset = item.paths.end.pop();
55
+ const endSlot = this.selection.findSlotByPaths(item.paths.end);
56
+ if (startSlot && endSlot) {
57
+ const position = this.nativeSelection.getPositionByRange({
58
+ startOffset,
59
+ endOffset,
60
+ startSlot,
61
+ endSlot
62
+ });
63
+ if (position.start && position.end) {
64
+ const nativeRange = this.document.createRange();
65
+ nativeRange.setStart(position.start.node, position.start.offset);
66
+ nativeRange.setEnd(position.end.node, position.end.offset);
67
+ const rects = nativeRange.getClientRects();
68
+ let prev = {};
69
+ for (let i = rects.length - 1; i >= 0; i--) {
70
+ const rect = rects[i];
71
+ if (prev.y === rect.y) {
72
+ continue;
73
+ }
74
+ prev = rect;
75
+ this.onRectChange.next({
76
+ x: rect.x,
77
+ y: rect.y,
78
+ width: rect.width,
79
+ height: rect.height,
80
+ color: item.color
81
+ });
82
+ }
83
+ if (rects.length === 0) {
84
+ const rect = nativeRange.getBoundingClientRect();
85
+ this.onRectChange.next({
86
+ x: rect.x,
87
+ y: rect.y,
88
+ width: 1,
89
+ height: rect.height,
90
+ color: item.color
91
+ });
92
+ }
93
+ }
94
+ }
95
+ });
96
+ }
97
+ };
98
+ CollaborateCursor = __decorate([
99
+ Injectable(),
100
+ __param(0, Inject(EDITOR_CONTAINER)),
101
+ __param(1, Inject(EDITABLE_DOCUMENT)),
102
+ __metadata("design:paramtypes", [HTMLElement,
103
+ Document,
104
+ SelectionBridge,
105
+ Selection])
106
+ ], CollaborateCursor);
107
+ export { CollaborateCursor };
108
+ //# sourceMappingURL=collaborate-cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collaborate-cursor.js","sourceRoot":"","sources":["../../src/collab/collaborate-cursor.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC9C,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AACtG,OAAO,EAAE,SAAS,EAAkB,MAAM,eAAe,CAAA;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAiBvC,IAAa,iBAAiB,GAA9B,MAAa,iBAAiB;IAgB5B,YAA8C,SAAsB,EACrB,QAAkB,EAC7C,eAAgC,EAChC,SAAoB;QAHM,cAAS,GAAT,SAAS,CAAa;QACrB,aAAQ,GAAR,QAAQ,CAAU;QAC7C,oBAAe,GAAf,eAAe,CAAiB;QAChC,cAAS,GAAT,SAAS,CAAW;QAlBhC,WAAM,GAAG,aAAa,CAAC,QAAQ,EAAE;YACvC,MAAM,EAAE;gBACN,QAAQ,EAAE,UAAU;gBACpB,OAAO,EAAE,GAAG;gBACZ,IAAI,EAAE,CAAC;gBACP,GAAG,EAAE,CAAC;gBACN,KAAK,EAAE,MAAM;gBACb,MAAM,EAAE,MAAM;gBACd,aAAa,EAAE,MAAM;aACtB;SACF,CAAsB,CAAA;QACf,YAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAE,CAAA;QAEvC,iBAAY,GAAG,IAAI,OAAO,EAAiB,CAAA;QAMjD,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAClC,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;YACjC,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAA;YACnC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAA;YACxB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;YACtG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;YACnB,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAA;QAC1B,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,IAAI,CAAC,KAAwB;QAC3B,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAA;QAC9C,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAA;QAChD,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QAEnE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;YACf,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAA;QACnD,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;YAChB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAG,CAAA;YAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YAClE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAG,CAAA;YACvC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YAE9D,IAAI,SAAS,IAAI,OAAO,EAAE;gBACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,kBAAkB,CAAC;oBACvD,WAAW;oBACX,SAAS;oBACT,SAAS;oBACT,OAAO;iBACR,CAAC,CAAA;gBACF,IAAI,QAAQ,CAAC,KAAK,IAAI,QAAQ,CAAC,GAAG,EAAE;oBAClC,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAA;oBAC/C,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;oBAChE,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;oBAE1D,MAAM,KAAK,GAAG,WAAW,CAAC,cAAc,EAAE,CAAA;oBAC1C,IAAI,IAAI,GAAQ,EAAE,CAAA;oBAClB,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;wBAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;wBACrB,IAAI,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE;4BACrB,SAAQ;yBACT;wBACD,IAAI,GAAG,IAAI,CAAA;wBACX,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;4BACrB,CAAC,EAAE,IAAI,CAAC,CAAC;4BACT,CAAC,EAAE,IAAI,CAAC,CAAC;4BACT,KAAK,EAAE,IAAI,CAAC,KAAK;4BACjB,MAAM,EAAE,IAAI,CAAC,MAAM;4BACnB,KAAK,EAAE,IAAI,CAAC,KAAK;yBAClB,CAAC,CAAA;qBACH;oBAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;wBACtB,MAAM,IAAI,GAAG,WAAW,CAAC,qBAAqB,EAAE,CAAA;wBAChD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;4BACrB,CAAC,EAAE,IAAI,CAAC,CAAC;4BACT,CAAC,EAAE,IAAI,CAAC,CAAC;4BACT,KAAK,EAAE,CAAC;4BACR,MAAM,EAAE,IAAI,CAAC,MAAM;4BACnB,KAAK,EAAE,IAAI,CAAC,KAAK;yBAClB,CAAC,CAAA;qBACH;iBACF;aACF;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;CACF,CAAA;AAtFY,iBAAiB;IAD7B,UAAU,EAAE;IAiBE,WAAA,MAAM,CAAC,gBAAgB,CAAC,CAAA;IACxB,WAAA,MAAM,CAAC,iBAAiB,CAAC,CAAA;qCADmB,WAAW;QACX,QAAQ;QAC5B,eAAe;QACrB,SAAS;GAnB7B,iBAAiB,CAsF7B;SAtFY,iBAAiB"}
@@ -1,18 +1,23 @@
1
- import { RootComponentRef, Starter, Translator, Registry } from '@textbus/core';
1
+ import { Observable } from '@tanbo/stream';
2
+ import { RootComponentRef, Starter, Translator, Registry, Selection, SelectionPaths } from '@textbus/core';
2
3
  import { Doc as YDoc } from 'yjs';
3
- import { Awareness } from 'y-protocols/awareness';
4
- import { CollaborateHistory } from './collab/_api';
4
+ import { CollaborateHistory, CollaborateCursor, RemoteSelection } from './collab/_api';
5
5
  export declare class Collaborate {
6
6
  private rootComponentRef;
7
+ private collaborateCursor;
7
8
  private translator;
8
9
  private registry;
10
+ private selection;
9
11
  private collaborateHistory;
10
12
  private starter;
13
+ onSelectionChange: Observable<SelectionPaths>;
11
14
  yDoc: YDoc;
12
15
  private subscriptions;
13
16
  private updateFromSelf;
14
- constructor(rootComponentRef: RootComponentRef, translator: Translator, registry: Registry, collaborateHistory: CollaborateHistory, starter: Starter);
15
- setup(awareness: Awareness): void;
17
+ private selectionChangeEvent;
18
+ constructor(rootComponentRef: RootComponentRef, collaborateCursor: CollaborateCursor, translator: Translator, registry: Registry, selection: Selection, collaborateHistory: CollaborateHistory, starter: Starter);
19
+ setup(): void;
20
+ updateRemoteSelection(paths: RemoteSelection[]): void;
16
21
  destroy(): void;
17
22
  private listen;
18
23
  }
@@ -8,37 +8,37 @@ var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
10
  import { Injectable } from '@tanbo/di';
11
- import { debounceTime, filter, tap } from '@tanbo/stream';
12
- import { RootComponentRef, Starter, Translator, Registry } from '@textbus/core';
11
+ import { debounceTime, filter, Subject, tap } from '@tanbo/stream';
12
+ import { RootComponentRef, Starter, Translator, Registry, Selection } from '@textbus/core';
13
13
  import { Doc as YDoc } from 'yjs';
14
14
  import { localToRemote } from './collab/local-to-remote';
15
15
  import { remoteToLocal } from './collab/remote-to-local';
16
- import { CollaborateHistory } from './collab/_api';
17
- // const collaborateErrorFn = makeError('Collaborate')
16
+ import { CollaborateHistory, CollaborateCursor } from './collab/_api';
18
17
  let Collaborate = class Collaborate {
19
- constructor(rootComponentRef, translator, registry, collaborateHistory, starter) {
18
+ constructor(rootComponentRef, collaborateCursor, translator, registry, selection, collaborateHistory, starter) {
20
19
  this.rootComponentRef = rootComponentRef;
20
+ this.collaborateCursor = collaborateCursor;
21
21
  this.translator = translator;
22
22
  this.registry = registry;
23
+ this.selection = selection;
23
24
  this.collaborateHistory = collaborateHistory;
24
25
  this.starter = starter;
25
26
  this.yDoc = new YDoc();
26
27
  this.subscriptions = [];
27
28
  this.updateFromSelf = true;
29
+ this.selectionChangeEvent = new Subject();
30
+ this.onSelectionChange = this.selectionChangeEvent.asObservable();
28
31
  }
29
- setup(awareness) {
32
+ setup() {
30
33
  this.subscriptions.push(this.starter.onReady.subscribe(() => {
31
34
  this.listen();
35
+ }), this.selection.onChange.subscribe(() => {
36
+ const paths = this.selection.getPaths();
37
+ this.selectionChangeEvent.next(paths);
32
38
  }));
33
- awareness.on('update', () => {
34
- const users = [];
35
- awareness.getStates().forEach(state => {
36
- if (state.user) {
37
- users.push(state.user);
38
- }
39
- });
40
- console.log(users);
41
- });
39
+ }
40
+ updateRemoteSelection(paths) {
41
+ this.collaborateCursor.draw(paths);
42
42
  }
43
43
  destroy() {
44
44
  this.subscriptions.forEach(i => i.unsubscribe());
@@ -73,8 +73,10 @@ let Collaborate = class Collaborate {
73
73
  Collaborate = __decorate([
74
74
  Injectable(),
75
75
  __metadata("design:paramtypes", [RootComponentRef,
76
+ CollaborateCursor,
76
77
  Translator,
77
78
  Registry,
79
+ Selection,
78
80
  CollaborateHistory,
79
81
  Starter])
80
82
  ], Collaborate);
@@ -1 +1 @@
1
- {"version":3,"file":"collaborate.js","sourceRoot":"","sources":["../src/collaborate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"collaborate.js","sourceRoot":"","sources":["../src/collaborate.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@textbus/collaborate",
3
- "version": "2.0.0-alpha.37",
3
+ "version": "2.0.0-alpha.38",
4
4
  "description": "TextBus is a rich text editor and framework that is highly customizable and extensible to achieve rich wysiwyg effects.",
5
5
  "main": "./bundles/public-api.js",
6
6
  "module": "./bundles/public-api.js",
@@ -26,8 +26,9 @@
26
26
  ],
27
27
  "dependencies": {
28
28
  "@tanbo/di": "^1.0.5",
29
- "@tanbo/stream": "^0.0.11",
30
- "@textbus/core": "^2.0.0-alpha.37",
29
+ "@tanbo/stream": "^0.0.12",
30
+ "@textbus/browser": "^2.0.0-alpha.38",
31
+ "@textbus/core": "^2.0.0-alpha.38",
31
32
  "reflect-metadata": "^0.1.13",
32
33
  "y-protocols": "^1.0.5",
33
34
  "yjs": "^13.5.27"
@@ -43,5 +44,5 @@
43
44
  "bugs": {
44
45
  "url": "https://github.com/textbus/textbus.git/issues"
45
46
  },
46
- "gitHead": "fca1880bd4a9fb21d4c28a76c492a6b98ba6dd8d"
47
+ "gitHead": "ee9175a3ad0ecf1e3470bd36faa5a2b336df2cea"
47
48
  }
@@ -1,3 +1,4 @@
1
+ export * from './collaborate-cursor'
1
2
  export * from './collaborate-history'
2
3
  export * from './local-to-remote'
3
4
  export * from './remote-to-local'
@@ -0,0 +1,107 @@
1
+ import { Inject, Injectable } from '@tanbo/di'
2
+ import { createElement, EDITABLE_DOCUMENT, EDITOR_CONTAINER, SelectionBridge } from '@textbus/browser'
3
+ import { Selection, SelectionPaths } from '@textbus/core'
4
+ import { Subject } from '@tanbo/stream'
5
+
6
+ export interface RemoteSelection {
7
+ color: string
8
+ username: string
9
+ paths: SelectionPaths
10
+ }
11
+
12
+ export interface SelectionRect {
13
+ x: number
14
+ y: number
15
+ width: number
16
+ height: number
17
+ color: string
18
+ }
19
+
20
+ @Injectable()
21
+ export class CollaborateCursor {
22
+ private canvas = createElement('canvas', {
23
+ styles: {
24
+ position: 'absolute',
25
+ opacity: 0.5,
26
+ left: 0,
27
+ top: 0,
28
+ width: '100%',
29
+ height: '100%',
30
+ pointerEvents: 'none'
31
+ }
32
+ }) as HTMLCanvasElement
33
+ private context = this.canvas.getContext('2d')!
34
+
35
+ private onRectChange = new Subject<SelectionRect>()
36
+
37
+ constructor(@Inject(EDITOR_CONTAINER) private container: HTMLElement,
38
+ @Inject(EDITABLE_DOCUMENT) private document: Document,
39
+ private nativeSelection: SelectionBridge,
40
+ private selection: Selection) {
41
+ container.appendChild(this.canvas)
42
+ this.onRectChange.subscribe(rect => {
43
+ this.context.fillStyle = rect.color
44
+ this.context.beginPath()
45
+ this.context.rect(Math.ceil(rect.x), Math.ceil(rect.y), Math.ceil(rect.width), Math.ceil(rect.height))
46
+ this.context.fill()
47
+ this.context.closePath()
48
+ })
49
+ }
50
+
51
+ draw(paths: RemoteSelection[]) {
52
+ this.canvas.width = this.container.offsetWidth
53
+ this.canvas.height = this.container.offsetHeight
54
+ this.context.clearRect(0, 0, this.canvas.width, this.canvas.height)
55
+
56
+ paths.filter(i => {
57
+ return i.paths.start.length && i.paths.end.length
58
+ }).forEach(item => {
59
+ const startOffset = item.paths.start.pop()!
60
+ const startSlot = this.selection.findSlotByPaths(item.paths.start)
61
+ const endOffset = item.paths.end.pop()!
62
+ const endSlot = this.selection.findSlotByPaths(item.paths.end)
63
+
64
+ if (startSlot && endSlot) {
65
+ const position = this.nativeSelection.getPositionByRange({
66
+ startOffset,
67
+ endOffset,
68
+ startSlot,
69
+ endSlot
70
+ })
71
+ if (position.start && position.end) {
72
+ const nativeRange = this.document.createRange()
73
+ nativeRange.setStart(position.start.node, position.start.offset)
74
+ nativeRange.setEnd(position.end.node, position.end.offset)
75
+
76
+ const rects = nativeRange.getClientRects()
77
+ let prev: any = {}
78
+ for (let i = rects.length - 1; i >= 0; i--) {
79
+ const rect = rects[i]
80
+ if (prev.y === rect.y) {
81
+ continue
82
+ }
83
+ prev = rect
84
+ this.onRectChange.next({
85
+ x: rect.x,
86
+ y: rect.y,
87
+ width: rect.width,
88
+ height: rect.height,
89
+ color: item.color
90
+ })
91
+ }
92
+
93
+ if (rects.length === 0) {
94
+ const rect = nativeRange.getBoundingClientRect()
95
+ this.onRectChange.next({
96
+ x: rect.x,
97
+ y: rect.y,
98
+ width: 1,
99
+ height: rect.height,
100
+ color: item.color
101
+ })
102
+ }
103
+ }
104
+ }
105
+ })
106
+ }
107
+ }
@@ -1,49 +1,53 @@
1
1
  import { Injectable } from '@tanbo/di'
2
- import { debounceTime, filter, Subscription, tap } from '@tanbo/stream'
2
+ import { debounceTime, filter, Observable, Subject, Subscription, tap } from '@tanbo/stream'
3
3
  import {
4
4
  RootComponentRef,
5
5
  Starter,
6
6
  Operation,
7
7
  Translator,
8
- Registry
8
+ Registry,
9
+ Selection,
10
+ SelectionPaths
9
11
  } from '@textbus/core'
10
12
  import { Doc as YDoc } from 'yjs'
11
- import { Awareness } from 'y-protocols/awareness'
12
13
  import { localToRemote } from './collab/local-to-remote'
13
14
  import { remoteToLocal } from './collab/remote-to-local'
14
- import { CollaborateHistory } from './collab/_api'
15
-
16
- // const collaborateErrorFn = makeError('Collaborate')
15
+ import { CollaborateHistory, CollaborateCursor, RemoteSelection } from './collab/_api'
17
16
 
18
17
  @Injectable()
19
18
  export class Collaborate {
19
+ onSelectionChange: Observable<SelectionPaths>
20
20
  yDoc = new YDoc()
21
21
 
22
22
  private subscriptions: Subscription[] = []
23
23
  private updateFromSelf = true
24
24
 
25
+ private selectionChangeEvent = new Subject<SelectionPaths>()
26
+
25
27
  constructor(private rootComponentRef: RootComponentRef,
28
+ private collaborateCursor: CollaborateCursor,
26
29
  private translator: Translator,
27
30
  private registry: Registry,
31
+ private selection: Selection,
28
32
  private collaborateHistory: CollaborateHistory,
29
33
  private starter: Starter) {
34
+ this.onSelectionChange = this.selectionChangeEvent.asObservable()
30
35
  }
31
36
 
32
- setup(awareness: Awareness) {
37
+ setup() {
33
38
  this.subscriptions.push(
34
39
  this.starter.onReady.subscribe(() => {
35
40
  this.listen()
41
+ }),
42
+ this.selection.onChange.subscribe(() => {
43
+ const paths = this.selection.getPaths()
44
+ this.selectionChangeEvent.next(paths)
36
45
  })
37
46
  )
38
- awareness.on('update', () => {
39
- const users: any[] = []
40
- awareness.getStates().forEach(state => {
41
- if (state.user) {
42
- users.push(state.user)
43
- }
44
- })
45
- console.log(users)
46
- })
47
+ }
48
+
49
+ updateRemoteSelection(paths: RemoteSelection[]) {
50
+ this.collaborateCursor.draw(paths)
47
51
  }
48
52
 
49
53
  destroy() {