@textbus/collaborate 4.0.0-alpha.27 → 4.0.0-alpha.29
Sign up to get free protection for your applications and to get access to all the features.
- package/bundles/collaborate-module.d.ts +10 -1
- package/bundles/index.esm.js +114 -54
- package/bundles/index.js +109 -49
- package/bundles/public-api.d.ts +1 -0
- package/bundles/user-activity.d.ts +23 -0
- package/package.json +5 -5
@@ -1,5 +1,14 @@
|
|
1
|
-
import { Module } from '@textbus/core';
|
1
|
+
import { Module, Textbus } from '@textbus/core';
|
2
2
|
import { Provider } from '@viewfly/core';
|
3
|
+
import { UserInfo } from './user-activity';
|
4
|
+
export interface CollaborateConfig {
|
5
|
+
url: string;
|
6
|
+
roomName: string;
|
7
|
+
userinfo: UserInfo;
|
8
|
+
}
|
3
9
|
export declare class CollaborateModule implements Module {
|
10
|
+
config: CollaborateConfig;
|
4
11
|
providers: Provider[];
|
12
|
+
constructor(config: CollaborateConfig);
|
13
|
+
setup(textbus: Textbus): Promise<(() => void) | void> | (() => void) | void;
|
5
14
|
}
|
package/bundles/index.esm.js
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
import { Injectable, Inject, Optional } from '@viewfly/core';
|
2
|
-
import { Subject, map, filter } from '@tanbo/stream';
|
3
|
-
import { makeError, HISTORY_STACK_SIZE, ChangeOrigin,
|
4
|
-
import { Doc, UndoManager, Map, Array, Text, createAbsolutePositionFromRelativePosition, createRelativePositionFromTypeIndex } from 'yjs';
|
2
|
+
import { Subject, map, filter, Subscription } from '@tanbo/stream';
|
3
|
+
import { makeError, HISTORY_STACK_SIZE, ChangeOrigin, createObjectProxy, createArrayProxy, Slot, RootComponentRef, Scheduler, Registry, Selection, History } from '@textbus/core';
|
4
|
+
import { Doc, UndoManager, Map, Array as Array$1, Text, createAbsolutePositionFromRelativePosition, createRelativePositionFromTypeIndex } from 'yjs';
|
5
|
+
import { WebsocketProvider } from 'y-websocket';
|
5
6
|
|
6
7
|
/******************************************************************************
|
7
8
|
Copyright (c) Microsoft Corporation.
|
@@ -269,25 +270,23 @@ let Collaborate = class Collaborate {
|
|
269
270
|
}
|
270
271
|
syncSharedMapToLocalMap(sharedMap, localMap, parent) {
|
271
272
|
sharedMap.forEach((value, key) => {
|
272
|
-
localMap
|
273
|
+
localMap[key] = this.createLocalModelBySharedByModel(value, parent);
|
273
274
|
});
|
274
275
|
this.syncObject(sharedMap, localMap, parent);
|
275
276
|
}
|
276
277
|
createLocalMapBySharedMap(sharedMap, parent) {
|
277
|
-
const localMap =
|
278
|
+
const localMap = createObjectProxy({}, parent);
|
278
279
|
this.syncSharedMapToLocalMap(sharedMap, localMap, parent);
|
279
280
|
return localMap;
|
280
281
|
}
|
281
282
|
createLocalArrayBySharedArray(sharedArray, parent) {
|
282
|
-
const localArray =
|
283
|
-
sharedArray.
|
284
|
-
localArray.insert(this.createLocalModelBySharedByModel(item, parent));
|
285
|
-
});
|
283
|
+
const localArray = createArrayProxy([], parent);
|
284
|
+
localArray.push(...sharedArray.map(item => this.createLocalModelBySharedByModel(item, parent)));
|
286
285
|
this.syncArray(sharedArray, localArray, parent);
|
287
286
|
return localArray;
|
288
287
|
}
|
289
288
|
syncLocalMapToSharedMap(localMap, sharedMap, parent) {
|
290
|
-
localMap.forEach((
|
289
|
+
Object.entries(localMap).forEach(([key, value]) => {
|
291
290
|
sharedMap.set(key, this.createSharedModelByLocalModel(value, parent));
|
292
291
|
});
|
293
292
|
this.syncObject(sharedMap, localMap, parent);
|
@@ -298,7 +297,7 @@ let Collaborate = class Collaborate {
|
|
298
297
|
return sharedMap;
|
299
298
|
}
|
300
299
|
createSharedArrayByLocalArray(localArray, parent) {
|
301
|
-
const sharedArray = new Array();
|
300
|
+
const sharedArray = new Array$1();
|
302
301
|
localArray.forEach(value => {
|
303
302
|
sharedArray.push([this.createSharedModelByLocalModel(value, parent)]);
|
304
303
|
});
|
@@ -363,37 +362,29 @@ let Collaborate = class Collaborate {
|
|
363
362
|
this.syncSlot(sharedSlot, localSlot);
|
364
363
|
return localSlot;
|
365
364
|
}
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
// private createSharedModelByLocalModel(sharedModel: any, parent: Component<any>): any
|
370
|
-
createSharedModelByLocalModel(sharedModel, parent) {
|
371
|
-
if (sharedModel instanceof MapModel) {
|
372
|
-
return this.createSharedMapByLocalMap(sharedModel, parent);
|
365
|
+
createSharedModelByLocalModel(localModel, parent) {
|
366
|
+
if (localModel instanceof Slot) {
|
367
|
+
return this.createSharedSlotByLocalSlot(localModel);
|
373
368
|
}
|
374
|
-
if (
|
375
|
-
return this.createSharedArrayByLocalArray(
|
369
|
+
if (Array.isArray(localModel)) {
|
370
|
+
return this.createSharedArrayByLocalArray(localModel, parent);
|
376
371
|
}
|
377
|
-
if (
|
378
|
-
return this.
|
372
|
+
if (typeof localModel === 'object' && localModel !== null) {
|
373
|
+
return this.createSharedMapByLocalMap(localModel, parent);
|
379
374
|
}
|
380
|
-
return
|
375
|
+
return localModel;
|
381
376
|
}
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
// private createLocalModelBySharedByModel(localModel: any, parent: Component<any>): any
|
386
|
-
createLocalModelBySharedByModel(localModel, parent) {
|
387
|
-
if (localModel instanceof Map) {
|
388
|
-
return this.createLocalMapBySharedMap(localModel, parent);
|
377
|
+
createLocalModelBySharedByModel(sharedModel, parent) {
|
378
|
+
if (sharedModel instanceof Map) {
|
379
|
+
return this.createLocalMapBySharedMap(sharedModel, parent);
|
389
380
|
}
|
390
|
-
if (
|
391
|
-
return this.createLocalArrayBySharedArray(
|
381
|
+
if (sharedModel instanceof Array$1) {
|
382
|
+
return this.createLocalArrayBySharedArray(sharedModel, parent);
|
392
383
|
}
|
393
|
-
if (
|
394
|
-
return this.createLocalSlotBySharedSlot(
|
384
|
+
if (sharedModel instanceof Text) {
|
385
|
+
return this.createLocalSlotBySharedSlot(sharedModel);
|
395
386
|
}
|
396
|
-
return
|
387
|
+
return sharedModel;
|
397
388
|
}
|
398
389
|
getAbstractSelection(position) {
|
399
390
|
const anchorPosition = createAbsolutePositionFromRelativePosition(position.anchor, this.yDoc);
|
@@ -567,7 +558,7 @@ let Collaborate = class Collaborate {
|
|
567
558
|
});
|
568
559
|
});
|
569
560
|
this.slotMap.set(localSlot, sharedSlot);
|
570
|
-
localSlot.destroyCallbacks.push(() => {
|
561
|
+
localSlot.changeMarker.destroyCallbacks.push(() => {
|
571
562
|
this.slotMap.delete(localSlot);
|
572
563
|
sharedSlot.unobserve(syncRemote);
|
573
564
|
sub.unsubscribe();
|
@@ -599,23 +590,29 @@ let Collaborate = class Collaborate {
|
|
599
590
|
* @private
|
600
591
|
*/
|
601
592
|
syncArray(sharedArray, localArray, parent) {
|
602
|
-
const sub = localArray.
|
593
|
+
const sub = localArray.__changeMarker__.onSelfChange.subscribe((actions) => {
|
603
594
|
this.runLocalUpdate(() => {
|
604
595
|
let index = 0;
|
605
|
-
for (const action of
|
596
|
+
for (const action of actions) {
|
606
597
|
switch (action.type) {
|
607
598
|
case 'retain':
|
608
599
|
index = action.offset;
|
609
600
|
break;
|
610
601
|
case 'insert':
|
611
602
|
{
|
612
|
-
const data =
|
603
|
+
const data = action.ref.map(item => {
|
604
|
+
return this.createSharedModelByLocalModel(item, parent);
|
605
|
+
});
|
613
606
|
sharedArray.insert(index, [data]);
|
614
607
|
}
|
615
608
|
break;
|
616
609
|
case 'delete':
|
617
610
|
sharedArray.delete(index, 1);
|
618
611
|
break;
|
612
|
+
case 'setIndex':
|
613
|
+
sharedArray.delete(action.index, 1);
|
614
|
+
sharedArray.insert(action.index, this.createSharedModelByLocalModel(action.ref, parent));
|
615
|
+
break;
|
619
616
|
}
|
620
617
|
}
|
621
618
|
});
|
@@ -623,28 +620,25 @@ let Collaborate = class Collaborate {
|
|
623
620
|
const syncRemote = (ev, tr) => {
|
624
621
|
this.runRemoteUpdate(tr, () => {
|
625
622
|
let index = 0;
|
626
|
-
localArray.retain(index);
|
627
623
|
ev.delta.forEach((action) => {
|
628
624
|
if (Reflect.has(action, 'retain')) {
|
629
625
|
index += action.retain;
|
630
|
-
localArray.retain(index);
|
631
626
|
}
|
632
627
|
else if (action.insert) {
|
633
|
-
action.insert.
|
634
|
-
|
635
|
-
localArray.insert(value);
|
636
|
-
index++;
|
628
|
+
const data = action.insert.map((item) => {
|
629
|
+
return this.createLocalModelBySharedByModel(item, parent);
|
637
630
|
});
|
631
|
+
localArray.splice(index, 0, ...data);
|
632
|
+
index += data.length;
|
638
633
|
}
|
639
634
|
else if (action.delete) {
|
640
|
-
localArray.
|
641
|
-
localArray.delete(action.delete);
|
635
|
+
localArray.splice(index, action.delete);
|
642
636
|
}
|
643
637
|
});
|
644
638
|
});
|
645
639
|
};
|
646
640
|
sharedArray.observe(syncRemote);
|
647
|
-
localArray.destroyCallbacks.push(() => {
|
641
|
+
localArray.__changeMarker__.destroyCallbacks.push(() => {
|
648
642
|
sub.unsubscribe();
|
649
643
|
sharedArray.unobserve(syncRemote);
|
650
644
|
});
|
@@ -662,18 +656,18 @@ let Collaborate = class Collaborate {
|
|
662
656
|
ev.changes.keys.forEach((item, key) => {
|
663
657
|
if (item.action === 'add' || item.action === 'update') {
|
664
658
|
const value = sharedObject.get(key);
|
665
|
-
localObject
|
659
|
+
localObject[key] = this.createLocalModelBySharedByModel(value, parent);
|
666
660
|
}
|
667
661
|
else {
|
668
|
-
|
662
|
+
Reflect.deleteProperty(localObject, key);
|
669
663
|
}
|
670
664
|
});
|
671
665
|
});
|
672
666
|
};
|
673
667
|
sharedObject.observe(syncRemote);
|
674
|
-
const sub = localObject.
|
668
|
+
const sub = localObject.__changeMarker__.onSelfChange.subscribe((actions) => {
|
675
669
|
this.runLocalUpdate(() => {
|
676
|
-
for (const action of
|
670
|
+
for (const action of actions) {
|
677
671
|
switch (action.type) {
|
678
672
|
case 'propSet':
|
679
673
|
sharedObject.set(action.key, this.createSharedModelByLocalModel(action.value, parent));
|
@@ -736,16 +730,82 @@ function remoteFormatsToLocal(registry, attrs) {
|
|
736
730
|
return formats;
|
737
731
|
}
|
738
732
|
|
733
|
+
let UserActivity = class UserActivity {
|
734
|
+
constructor(websocketProvider, selection) {
|
735
|
+
this.websocketProvider = websocketProvider;
|
736
|
+
this.selection = selection;
|
737
|
+
this.stateChangeEvent = new Subject();
|
738
|
+
this.userChangeEvent = new Subject();
|
739
|
+
this.subscription = new Subscription();
|
740
|
+
this.onStateChange = this.stateChangeEvent.asObservable();
|
741
|
+
this.onUserChange = this.userChangeEvent.asObservable();
|
742
|
+
}
|
743
|
+
init(userinfo) {
|
744
|
+
const provide = this.websocketProvider;
|
745
|
+
provide.awareness.setLocalStateField('user', userinfo);
|
746
|
+
this.subscription.add(this.selection.onChange.subscribe(() => {
|
747
|
+
const selection = this.selection.getPaths();
|
748
|
+
provide.awareness.setLocalStateField('selection', Object.assign(Object.assign({}, userinfo), { selection }));
|
749
|
+
}));
|
750
|
+
provide.awareness.on('update', () => {
|
751
|
+
const users = [];
|
752
|
+
const remoteSelections = [];
|
753
|
+
provide.awareness.getStates().forEach(state => {
|
754
|
+
if (state.user) {
|
755
|
+
users.push(state.user);
|
756
|
+
}
|
757
|
+
if (state.selection) {
|
758
|
+
remoteSelections.push(state.selection);
|
759
|
+
}
|
760
|
+
});
|
761
|
+
const selections = remoteSelections.filter(i => i.id !== userinfo.id);
|
762
|
+
this.userChangeEvent.next(users);
|
763
|
+
this.stateChangeEvent.next(selections);
|
764
|
+
});
|
765
|
+
}
|
766
|
+
destroy() {
|
767
|
+
this.subscription.unsubscribe();
|
768
|
+
}
|
769
|
+
};
|
770
|
+
UserActivity = __decorate([
|
771
|
+
Injectable(),
|
772
|
+
__metadata("design:paramtypes", [WebsocketProvider,
|
773
|
+
Selection])
|
774
|
+
], UserActivity);
|
775
|
+
|
739
776
|
class CollaborateModule {
|
740
|
-
constructor() {
|
777
|
+
constructor(config) {
|
778
|
+
this.config = config;
|
741
779
|
this.providers = [
|
742
780
|
Collaborate,
|
781
|
+
UserActivity,
|
743
782
|
{
|
744
783
|
provide: History,
|
745
784
|
useExisting: Collaborate
|
785
|
+
}, {
|
786
|
+
provide: WebsocketProvider,
|
787
|
+
useFactory: (collab) => {
|
788
|
+
return new WebsocketProvider(this.config.url, this.config.roomName, collab.yDoc);
|
789
|
+
},
|
790
|
+
deps: [Collaborate]
|
746
791
|
}
|
747
792
|
];
|
748
793
|
}
|
794
|
+
setup(textbus) {
|
795
|
+
const provide = textbus.get(WebsocketProvider);
|
796
|
+
const userActivity = textbus.get(UserActivity);
|
797
|
+
userActivity.init(this.config.userinfo);
|
798
|
+
return new Promise((resolve) => {
|
799
|
+
provide.on('sync', (is) => {
|
800
|
+
if (is) {
|
801
|
+
resolve(() => {
|
802
|
+
provide.disconnect();
|
803
|
+
userActivity.destroy();
|
804
|
+
});
|
805
|
+
}
|
806
|
+
});
|
807
|
+
});
|
808
|
+
}
|
749
809
|
}
|
750
810
|
|
751
|
-
export { Collaborate, CollaborateModule, CustomUndoManagerConfig };
|
811
|
+
export { Collaborate, CollaborateModule, CustomUndoManagerConfig, UserActivity };
|
package/bundles/index.js
CHANGED
@@ -4,6 +4,7 @@ var core$1 = require('@viewfly/core');
|
|
4
4
|
var stream = require('@tanbo/stream');
|
5
5
|
var core = require('@textbus/core');
|
6
6
|
var yjs = require('yjs');
|
7
|
+
var yWebsocket = require('y-websocket');
|
7
8
|
|
8
9
|
/******************************************************************************
|
9
10
|
Copyright (c) Microsoft Corporation.
|
@@ -271,25 +272,23 @@ exports.Collaborate = class Collaborate {
|
|
271
272
|
}
|
272
273
|
syncSharedMapToLocalMap(sharedMap, localMap, parent) {
|
273
274
|
sharedMap.forEach((value, key) => {
|
274
|
-
localMap
|
275
|
+
localMap[key] = this.createLocalModelBySharedByModel(value, parent);
|
275
276
|
});
|
276
277
|
this.syncObject(sharedMap, localMap, parent);
|
277
278
|
}
|
278
279
|
createLocalMapBySharedMap(sharedMap, parent) {
|
279
|
-
const localMap =
|
280
|
+
const localMap = core.createObjectProxy({}, parent);
|
280
281
|
this.syncSharedMapToLocalMap(sharedMap, localMap, parent);
|
281
282
|
return localMap;
|
282
283
|
}
|
283
284
|
createLocalArrayBySharedArray(sharedArray, parent) {
|
284
|
-
const localArray =
|
285
|
-
sharedArray.
|
286
|
-
localArray.insert(this.createLocalModelBySharedByModel(item, parent));
|
287
|
-
});
|
285
|
+
const localArray = core.createArrayProxy([], parent);
|
286
|
+
localArray.push(...sharedArray.map(item => this.createLocalModelBySharedByModel(item, parent)));
|
288
287
|
this.syncArray(sharedArray, localArray, parent);
|
289
288
|
return localArray;
|
290
289
|
}
|
291
290
|
syncLocalMapToSharedMap(localMap, sharedMap, parent) {
|
292
|
-
localMap.forEach((
|
291
|
+
Object.entries(localMap).forEach(([key, value]) => {
|
293
292
|
sharedMap.set(key, this.createSharedModelByLocalModel(value, parent));
|
294
293
|
});
|
295
294
|
this.syncObject(sharedMap, localMap, parent);
|
@@ -365,37 +364,29 @@ exports.Collaborate = class Collaborate {
|
|
365
364
|
this.syncSlot(sharedSlot, localSlot);
|
366
365
|
return localSlot;
|
367
366
|
}
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
// private createSharedModelByLocalModel(sharedModel: any, parent: Component<any>): any
|
372
|
-
createSharedModelByLocalModel(sharedModel, parent) {
|
373
|
-
if (sharedModel instanceof core.MapModel) {
|
374
|
-
return this.createSharedMapByLocalMap(sharedModel, parent);
|
367
|
+
createSharedModelByLocalModel(localModel, parent) {
|
368
|
+
if (localModel instanceof core.Slot) {
|
369
|
+
return this.createSharedSlotByLocalSlot(localModel);
|
375
370
|
}
|
376
|
-
if (
|
377
|
-
return this.createSharedArrayByLocalArray(
|
371
|
+
if (Array.isArray(localModel)) {
|
372
|
+
return this.createSharedArrayByLocalArray(localModel, parent);
|
378
373
|
}
|
379
|
-
if (
|
380
|
-
return this.
|
374
|
+
if (typeof localModel === 'object' && localModel !== null) {
|
375
|
+
return this.createSharedMapByLocalMap(localModel, parent);
|
381
376
|
}
|
382
|
-
return
|
377
|
+
return localModel;
|
383
378
|
}
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
// private createLocalModelBySharedByModel(localModel: any, parent: Component<any>): any
|
388
|
-
createLocalModelBySharedByModel(localModel, parent) {
|
389
|
-
if (localModel instanceof yjs.Map) {
|
390
|
-
return this.createLocalMapBySharedMap(localModel, parent);
|
379
|
+
createLocalModelBySharedByModel(sharedModel, parent) {
|
380
|
+
if (sharedModel instanceof yjs.Map) {
|
381
|
+
return this.createLocalMapBySharedMap(sharedModel, parent);
|
391
382
|
}
|
392
|
-
if (
|
393
|
-
return this.createLocalArrayBySharedArray(
|
383
|
+
if (sharedModel instanceof yjs.Array) {
|
384
|
+
return this.createLocalArrayBySharedArray(sharedModel, parent);
|
394
385
|
}
|
395
|
-
if (
|
396
|
-
return this.createLocalSlotBySharedSlot(
|
386
|
+
if (sharedModel instanceof yjs.Text) {
|
387
|
+
return this.createLocalSlotBySharedSlot(sharedModel);
|
397
388
|
}
|
398
|
-
return
|
389
|
+
return sharedModel;
|
399
390
|
}
|
400
391
|
getAbstractSelection(position) {
|
401
392
|
const anchorPosition = yjs.createAbsolutePositionFromRelativePosition(position.anchor, this.yDoc);
|
@@ -569,7 +560,7 @@ exports.Collaborate = class Collaborate {
|
|
569
560
|
});
|
570
561
|
});
|
571
562
|
this.slotMap.set(localSlot, sharedSlot);
|
572
|
-
localSlot.destroyCallbacks.push(() => {
|
563
|
+
localSlot.changeMarker.destroyCallbacks.push(() => {
|
573
564
|
this.slotMap.delete(localSlot);
|
574
565
|
sharedSlot.unobserve(syncRemote);
|
575
566
|
sub.unsubscribe();
|
@@ -601,23 +592,29 @@ exports.Collaborate = class Collaborate {
|
|
601
592
|
* @private
|
602
593
|
*/
|
603
594
|
syncArray(sharedArray, localArray, parent) {
|
604
|
-
const sub = localArray.
|
595
|
+
const sub = localArray.__changeMarker__.onSelfChange.subscribe((actions) => {
|
605
596
|
this.runLocalUpdate(() => {
|
606
597
|
let index = 0;
|
607
|
-
for (const action of
|
598
|
+
for (const action of actions) {
|
608
599
|
switch (action.type) {
|
609
600
|
case 'retain':
|
610
601
|
index = action.offset;
|
611
602
|
break;
|
612
603
|
case 'insert':
|
613
604
|
{
|
614
|
-
const data =
|
605
|
+
const data = action.ref.map(item => {
|
606
|
+
return this.createSharedModelByLocalModel(item, parent);
|
607
|
+
});
|
615
608
|
sharedArray.insert(index, [data]);
|
616
609
|
}
|
617
610
|
break;
|
618
611
|
case 'delete':
|
619
612
|
sharedArray.delete(index, 1);
|
620
613
|
break;
|
614
|
+
case 'setIndex':
|
615
|
+
sharedArray.delete(action.index, 1);
|
616
|
+
sharedArray.insert(action.index, this.createSharedModelByLocalModel(action.ref, parent));
|
617
|
+
break;
|
621
618
|
}
|
622
619
|
}
|
623
620
|
});
|
@@ -625,28 +622,25 @@ exports.Collaborate = class Collaborate {
|
|
625
622
|
const syncRemote = (ev, tr) => {
|
626
623
|
this.runRemoteUpdate(tr, () => {
|
627
624
|
let index = 0;
|
628
|
-
localArray.retain(index);
|
629
625
|
ev.delta.forEach((action) => {
|
630
626
|
if (Reflect.has(action, 'retain')) {
|
631
627
|
index += action.retain;
|
632
|
-
localArray.retain(index);
|
633
628
|
}
|
634
629
|
else if (action.insert) {
|
635
|
-
action.insert.
|
636
|
-
|
637
|
-
localArray.insert(value);
|
638
|
-
index++;
|
630
|
+
const data = action.insert.map((item) => {
|
631
|
+
return this.createLocalModelBySharedByModel(item, parent);
|
639
632
|
});
|
633
|
+
localArray.splice(index, 0, ...data);
|
634
|
+
index += data.length;
|
640
635
|
}
|
641
636
|
else if (action.delete) {
|
642
|
-
localArray.
|
643
|
-
localArray.delete(action.delete);
|
637
|
+
localArray.splice(index, action.delete);
|
644
638
|
}
|
645
639
|
});
|
646
640
|
});
|
647
641
|
};
|
648
642
|
sharedArray.observe(syncRemote);
|
649
|
-
localArray.destroyCallbacks.push(() => {
|
643
|
+
localArray.__changeMarker__.destroyCallbacks.push(() => {
|
650
644
|
sub.unsubscribe();
|
651
645
|
sharedArray.unobserve(syncRemote);
|
652
646
|
});
|
@@ -664,18 +658,18 @@ exports.Collaborate = class Collaborate {
|
|
664
658
|
ev.changes.keys.forEach((item, key) => {
|
665
659
|
if (item.action === 'add' || item.action === 'update') {
|
666
660
|
const value = sharedObject.get(key);
|
667
|
-
localObject
|
661
|
+
localObject[key] = this.createLocalModelBySharedByModel(value, parent);
|
668
662
|
}
|
669
663
|
else {
|
670
|
-
|
664
|
+
Reflect.deleteProperty(localObject, key);
|
671
665
|
}
|
672
666
|
});
|
673
667
|
});
|
674
668
|
};
|
675
669
|
sharedObject.observe(syncRemote);
|
676
|
-
const sub = localObject.
|
670
|
+
const sub = localObject.__changeMarker__.onSelfChange.subscribe((actions) => {
|
677
671
|
this.runLocalUpdate(() => {
|
678
|
-
for (const action of
|
672
|
+
for (const action of actions) {
|
679
673
|
switch (action.type) {
|
680
674
|
case 'propSet':
|
681
675
|
sharedObject.set(action.key, this.createSharedModelByLocalModel(action.value, parent));
|
@@ -738,16 +732,82 @@ function remoteFormatsToLocal(registry, attrs) {
|
|
738
732
|
return formats;
|
739
733
|
}
|
740
734
|
|
735
|
+
exports.UserActivity = class UserActivity {
|
736
|
+
constructor(websocketProvider, selection) {
|
737
|
+
this.websocketProvider = websocketProvider;
|
738
|
+
this.selection = selection;
|
739
|
+
this.stateChangeEvent = new stream.Subject();
|
740
|
+
this.userChangeEvent = new stream.Subject();
|
741
|
+
this.subscription = new stream.Subscription();
|
742
|
+
this.onStateChange = this.stateChangeEvent.asObservable();
|
743
|
+
this.onUserChange = this.userChangeEvent.asObservable();
|
744
|
+
}
|
745
|
+
init(userinfo) {
|
746
|
+
const provide = this.websocketProvider;
|
747
|
+
provide.awareness.setLocalStateField('user', userinfo);
|
748
|
+
this.subscription.add(this.selection.onChange.subscribe(() => {
|
749
|
+
const selection = this.selection.getPaths();
|
750
|
+
provide.awareness.setLocalStateField('selection', Object.assign(Object.assign({}, userinfo), { selection }));
|
751
|
+
}));
|
752
|
+
provide.awareness.on('update', () => {
|
753
|
+
const users = [];
|
754
|
+
const remoteSelections = [];
|
755
|
+
provide.awareness.getStates().forEach(state => {
|
756
|
+
if (state.user) {
|
757
|
+
users.push(state.user);
|
758
|
+
}
|
759
|
+
if (state.selection) {
|
760
|
+
remoteSelections.push(state.selection);
|
761
|
+
}
|
762
|
+
});
|
763
|
+
const selections = remoteSelections.filter(i => i.id !== userinfo.id);
|
764
|
+
this.userChangeEvent.next(users);
|
765
|
+
this.stateChangeEvent.next(selections);
|
766
|
+
});
|
767
|
+
}
|
768
|
+
destroy() {
|
769
|
+
this.subscription.unsubscribe();
|
770
|
+
}
|
771
|
+
};
|
772
|
+
exports.UserActivity = __decorate([
|
773
|
+
core$1.Injectable(),
|
774
|
+
__metadata("design:paramtypes", [yWebsocket.WebsocketProvider,
|
775
|
+
core.Selection])
|
776
|
+
], exports.UserActivity);
|
777
|
+
|
741
778
|
class CollaborateModule {
|
742
|
-
constructor() {
|
779
|
+
constructor(config) {
|
780
|
+
this.config = config;
|
743
781
|
this.providers = [
|
744
782
|
exports.Collaborate,
|
783
|
+
exports.UserActivity,
|
745
784
|
{
|
746
785
|
provide: core.History,
|
747
786
|
useExisting: exports.Collaborate
|
787
|
+
}, {
|
788
|
+
provide: yWebsocket.WebsocketProvider,
|
789
|
+
useFactory: (collab) => {
|
790
|
+
return new yWebsocket.WebsocketProvider(this.config.url, this.config.roomName, collab.yDoc);
|
791
|
+
},
|
792
|
+
deps: [exports.Collaborate]
|
748
793
|
}
|
749
794
|
];
|
750
795
|
}
|
796
|
+
setup(textbus) {
|
797
|
+
const provide = textbus.get(yWebsocket.WebsocketProvider);
|
798
|
+
const userActivity = textbus.get(exports.UserActivity);
|
799
|
+
userActivity.init(this.config.userinfo);
|
800
|
+
return new Promise((resolve) => {
|
801
|
+
provide.on('sync', (is) => {
|
802
|
+
if (is) {
|
803
|
+
resolve(() => {
|
804
|
+
provide.disconnect();
|
805
|
+
userActivity.destroy();
|
806
|
+
});
|
807
|
+
}
|
808
|
+
});
|
809
|
+
});
|
810
|
+
}
|
751
811
|
}
|
752
812
|
|
753
813
|
exports.CollaborateModule = CollaborateModule;
|
package/bundles/public-api.d.ts
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
import { Observable } from '@tanbo/stream';
|
2
|
+
import { Selection, SelectionPaths } from '@textbus/core';
|
3
|
+
import { WebsocketProvider } from 'y-websocket';
|
4
|
+
export interface UserInfo {
|
5
|
+
username: string;
|
6
|
+
color: string;
|
7
|
+
id: string;
|
8
|
+
}
|
9
|
+
export interface ActivityInfo extends UserInfo {
|
10
|
+
selection: SelectionPaths;
|
11
|
+
}
|
12
|
+
export declare class UserActivity {
|
13
|
+
private websocketProvider;
|
14
|
+
private selection;
|
15
|
+
onStateChange: Observable<ActivityInfo[]>;
|
16
|
+
onUserChange: Observable<UserInfo[]>;
|
17
|
+
private stateChangeEvent;
|
18
|
+
private userChangeEvent;
|
19
|
+
private subscription;
|
20
|
+
constructor(websocketProvider: WebsocketProvider, selection: Selection);
|
21
|
+
init(userinfo: UserInfo): void;
|
22
|
+
destroy(): void;
|
23
|
+
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@textbus/collaborate",
|
3
|
-
"version": "4.0.0-alpha.
|
3
|
+
"version": "4.0.0-alpha.29",
|
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/index.js",
|
6
6
|
"module": "./bundles/index.esm.js",
|
@@ -26,11 +26,11 @@
|
|
26
26
|
],
|
27
27
|
"dependencies": {
|
28
28
|
"@tanbo/stream": "^1.2.3",
|
29
|
-
"@textbus/core": "^4.0.0-alpha.
|
29
|
+
"@textbus/core": "^4.0.0-alpha.29",
|
30
30
|
"@viewfly/core": "^0.6.0",
|
31
31
|
"reflect-metadata": "^0.1.13",
|
32
|
-
"y-
|
33
|
-
"yjs": "^13.6.
|
32
|
+
"y-websocket": "^1.4.3",
|
33
|
+
"yjs": "^13.6.14"
|
34
34
|
},
|
35
35
|
"devDependencies": {
|
36
36
|
"@rollup/plugin-commonjs": "^23.0.2",
|
@@ -50,5 +50,5 @@
|
|
50
50
|
"bugs": {
|
51
51
|
"url": "https://github.com/textbus/textbus.git/issues"
|
52
52
|
},
|
53
|
-
"gitHead": "
|
53
|
+
"gitHead": "005a72f3cbc2c642fef5cdb584b690bbc8f8caf0"
|
54
54
|
}
|