@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.
@@ -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
  }
@@ -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, MapModel, ArrayModel, Slot, RootComponentRef, Scheduler, Registry, Selection, History } from '@textbus/core';
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.set(key, this.createLocalModelBySharedByModel(value, parent));
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 = new MapModel(parent);
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 = new ArrayModel(parent);
283
- sharedArray.forEach(item => {
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((value, key) => {
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
- // private createSharedModelByLocalModel(sharedModel: YMap<any>, parent: Component<any>): MapModel<any>
367
- // private createSharedModelByLocalModel(sharedModel: YArray<any>, parent: Component<any>): ArrayModel<any>
368
- // private createSharedModelByLocalModel(sharedModel: YText, parent: Component<any>): Slot
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 (sharedModel instanceof ArrayModel) {
375
- return this.createSharedArrayByLocalArray(sharedModel, parent);
369
+ if (Array.isArray(localModel)) {
370
+ return this.createSharedArrayByLocalArray(localModel, parent);
376
371
  }
377
- if (sharedModel instanceof Slot) {
378
- return this.createSharedSlotByLocalSlot(sharedModel);
372
+ if (typeof localModel === 'object' && localModel !== null) {
373
+ return this.createSharedMapByLocalMap(localModel, parent);
379
374
  }
380
- return sharedModel;
375
+ return localModel;
381
376
  }
382
- // private createLocalModelBySharedByModel(localModel: MapModel<any>, parent: Component<any>): MapModel<any>
383
- // private createLocalModelBySharedByModel(localModel: ArrayModel<any>, parent: Component<any>): YArray<any>
384
- // private createLocalModelBySharedByModel(localModel: Slot, parent: Component<any>): YText
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 (localModel instanceof Array) {
391
- return this.createLocalArrayBySharedArray(localModel, parent);
381
+ if (sharedModel instanceof Array$1) {
382
+ return this.createLocalArrayBySharedArray(sharedModel, parent);
392
383
  }
393
- if (localModel instanceof Text) {
394
- return this.createLocalSlotBySharedSlot(localModel);
384
+ if (sharedModel instanceof Text) {
385
+ return this.createLocalSlotBySharedSlot(sharedModel);
395
386
  }
396
- return localModel;
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.changeMarker.onChange.subscribe((op) => {
593
+ const sub = localArray.__changeMarker__.onSelfChange.subscribe((actions) => {
603
594
  this.runLocalUpdate(() => {
604
595
  let index = 0;
605
- for (const action of op.apply) {
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 = this.createSharedModelByLocalModel(action.ref, parent);
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.forEach((item) => {
634
- const value = this.createLocalModelBySharedByModel(item, parent);
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.retain(index);
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.set(key, this.createLocalModelBySharedByModel(value, parent));
659
+ localObject[key] = this.createLocalModelBySharedByModel(value, parent);
666
660
  }
667
661
  else {
668
- localObject.remove(key);
662
+ Reflect.deleteProperty(localObject, key);
669
663
  }
670
664
  });
671
665
  });
672
666
  };
673
667
  sharedObject.observe(syncRemote);
674
- const sub = localObject.changeMarker.onChange.subscribe((op) => {
668
+ const sub = localObject.__changeMarker__.onSelfChange.subscribe((actions) => {
675
669
  this.runLocalUpdate(() => {
676
- for (const action of op.apply) {
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.set(key, this.createLocalModelBySharedByModel(value, parent));
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 = new core.MapModel(parent);
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 = new core.ArrayModel(parent);
285
- sharedArray.forEach(item => {
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((value, key) => {
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
- // private createSharedModelByLocalModel(sharedModel: YMap<any>, parent: Component<any>): MapModel<any>
369
- // private createSharedModelByLocalModel(sharedModel: YArray<any>, parent: Component<any>): ArrayModel<any>
370
- // private createSharedModelByLocalModel(sharedModel: YText, parent: Component<any>): Slot
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 (sharedModel instanceof core.ArrayModel) {
377
- return this.createSharedArrayByLocalArray(sharedModel, parent);
371
+ if (Array.isArray(localModel)) {
372
+ return this.createSharedArrayByLocalArray(localModel, parent);
378
373
  }
379
- if (sharedModel instanceof core.Slot) {
380
- return this.createSharedSlotByLocalSlot(sharedModel);
374
+ if (typeof localModel === 'object' && localModel !== null) {
375
+ return this.createSharedMapByLocalMap(localModel, parent);
381
376
  }
382
- return sharedModel;
377
+ return localModel;
383
378
  }
384
- // private createLocalModelBySharedByModel(localModel: MapModel<any>, parent: Component<any>): MapModel<any>
385
- // private createLocalModelBySharedByModel(localModel: ArrayModel<any>, parent: Component<any>): YArray<any>
386
- // private createLocalModelBySharedByModel(localModel: Slot, parent: Component<any>): YText
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 (localModel instanceof yjs.Array) {
393
- return this.createLocalArrayBySharedArray(localModel, parent);
383
+ if (sharedModel instanceof yjs.Array) {
384
+ return this.createLocalArrayBySharedArray(sharedModel, parent);
394
385
  }
395
- if (localModel instanceof yjs.Text) {
396
- return this.createLocalSlotBySharedSlot(localModel);
386
+ if (sharedModel instanceof yjs.Text) {
387
+ return this.createLocalSlotBySharedSlot(sharedModel);
397
388
  }
398
- return localModel;
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.changeMarker.onChange.subscribe((op) => {
595
+ const sub = localArray.__changeMarker__.onSelfChange.subscribe((actions) => {
605
596
  this.runLocalUpdate(() => {
606
597
  let index = 0;
607
- for (const action of op.apply) {
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 = this.createSharedModelByLocalModel(action.ref, parent);
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.forEach((item) => {
636
- const value = this.createLocalModelBySharedByModel(item, parent);
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.retain(index);
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.set(key, this.createLocalModelBySharedByModel(value, parent));
661
+ localObject[key] = this.createLocalModelBySharedByModel(value, parent);
668
662
  }
669
663
  else {
670
- localObject.remove(key);
664
+ Reflect.deleteProperty(localObject, key);
671
665
  }
672
666
  });
673
667
  });
674
668
  };
675
669
  sharedObject.observe(syncRemote);
676
- const sub = localObject.changeMarker.onChange.subscribe((op) => {
670
+ const sub = localObject.__changeMarker__.onSelfChange.subscribe((actions) => {
677
671
  this.runLocalUpdate(() => {
678
- for (const action of op.apply) {
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;
@@ -1,2 +1,3 @@
1
1
  export * from './collaborate';
2
2
  export * from './collaborate-module';
3
+ export * from './user-activity';
@@ -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.27",
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.27",
29
+ "@textbus/core": "^4.0.0-alpha.29",
30
30
  "@viewfly/core": "^0.6.0",
31
31
  "reflect-metadata": "^0.1.13",
32
- "y-protocols": "^1.0.5",
33
- "yjs": "^13.6.7"
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": "cf4fd289b73bc777124a32fe42bb58eba05a34f1"
53
+ "gitHead": "005a72f3cbc2c642fef5cdb584b690bbc8f8caf0"
54
54
  }