@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.
- package/bundles/collab/_api.d.ts +1 -0
- package/bundles/collab/_api.js +1 -0
- package/bundles/collab/_api.js.map +1 -1
- package/bundles/collab/collaborate-cursor.d.ts +25 -0
- package/bundles/collab/collaborate-cursor.js +108 -0
- package/bundles/collab/collaborate-cursor.js.map +1 -0
- package/bundles/collaborate.d.ts +10 -5
- package/bundles/collaborate.js +17 -15
- package/bundles/collaborate.js.map +1 -1
- package/package.json +5 -4
- package/src/collab/_api.ts +1 -0
- package/src/collab/collaborate-cursor.ts +107 -0
- package/src/collaborate.ts +20 -16
package/bundles/collab/_api.d.ts
CHANGED
package/bundles/collab/_api.js
CHANGED
@@ -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":"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"}
|
package/bundles/collaborate.d.ts
CHANGED
@@ -1,18 +1,23 @@
|
|
1
|
-
import {
|
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 {
|
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
|
-
|
15
|
-
|
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
|
}
|
package/bundles/collaborate.js
CHANGED
@@ -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(
|
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
|
-
|
34
|
-
|
35
|
-
|
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":";;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,EAAgB,GAAG,EAAE,MAAM,eAAe,CAAA;
|
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.
|
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.
|
30
|
-
"@textbus/
|
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": "
|
47
|
+
"gitHead": "ee9175a3ad0ecf1e3470bd36faa5a2b336df2cea"
|
47
48
|
}
|
package/src/collab/_api.ts
CHANGED
@@ -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
|
+
}
|
package/src/collaborate.ts
CHANGED
@@ -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(
|
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
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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() {
|