@textbus/collaborate 3.0.0 → 3.1.2

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.
@@ -33,743 +33,743 @@ function __metadata(metadataKey, metadataValue) {
33
33
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
34
34
  }
35
35
 
36
- const collaborateErrorFn = makeError('Collaborate');
37
- class ContentMap {
38
- constructor() {
39
- this.slotAndYTextMap = new WeakMap();
40
- this.yTextAndSLotMap = new WeakMap();
41
- }
42
- set(key, value) {
43
- if (key instanceof Slot) {
44
- this.slotAndYTextMap.set(key, value);
45
- this.yTextAndSLotMap.set(value, key);
46
- }
47
- else {
48
- this.slotAndYTextMap.set(value, key);
49
- this.yTextAndSLotMap.set(key, value);
50
- }
51
- }
52
- get(key) {
53
- if (key instanceof Slot) {
54
- return this.slotAndYTextMap.get(key) || null;
55
- }
56
- return this.yTextAndSLotMap.get(key) || null;
57
- }
58
- delete(key) {
59
- if (key instanceof Slot) {
60
- const v = this.slotAndYTextMap.get(key);
61
- this.slotAndYTextMap.delete(key);
62
- if (v) {
63
- this.yTextAndSLotMap.delete(v);
64
- }
65
- }
66
- else {
67
- const v = this.yTextAndSLotMap.get(key);
68
- this.yTextAndSLotMap.delete(key);
69
- if (v) {
70
- this.slotAndYTextMap.delete(v);
71
- }
72
- }
73
- }
74
- }
75
- class CustomUndoManagerConfig {
76
- }
77
- let Collaborate = class Collaborate {
78
- get canBack() {
79
- var _a;
80
- return ((_a = this.manager) === null || _a === void 0 ? void 0 : _a.canUndo()) || false;
81
- }
82
- get canForward() {
83
- var _a;
84
- return ((_a = this.manager) === null || _a === void 0 ? void 0 : _a.canRedo()) || false;
85
- }
86
- constructor(stackSize, rootComponentRef, controller, scheduler, registry, selection, starter, undoManagerConfig) {
87
- this.stackSize = stackSize;
88
- this.rootComponentRef = rootComponentRef;
89
- this.controller = controller;
90
- this.scheduler = scheduler;
91
- this.registry = registry;
92
- this.selection = selection;
93
- this.starter = starter;
94
- this.undoManagerConfig = undoManagerConfig;
95
- this.yDoc = new Doc();
96
- this.backEvent = new Subject();
97
- this.forwardEvent = new Subject();
98
- this.changeEvent = new Subject();
99
- this.pushEvent = new Subject();
100
- this.manager = null;
101
- this.subscriptions = [];
102
- this.updateFromRemote = false;
103
- this.contentSyncCaches = new WeakMap();
104
- this.slotStateSyncCaches = new WeakMap();
105
- this.slotsSyncCaches = new WeakMap();
106
- this.componentStateSyncCaches = new WeakMap();
107
- this.localChangesAppliedEvent = new Subject();
108
- this.selectionChangeEvent = new Subject();
109
- this.contentMap = new ContentMap();
110
- this.updateRemoteActions = [];
111
- this.noRecord = {};
112
- this.historyItems = [];
113
- this.index = 0;
114
- this.onBack = this.backEvent.asObservable();
115
- this.onForward = this.forwardEvent.asObservable();
116
- this.onChange = this.changeEvent.asObservable();
117
- this.onPush = this.pushEvent.asObservable();
118
- this.onLocalChangesApplied = this.localChangesAppliedEvent.asObservable();
119
- }
120
- listen() {
121
- const root = this.yDoc.getMap('RootComponent');
122
- const rootComponent = this.rootComponentRef.component;
123
- const undoManagerConfig = this.undoManagerConfig || {};
124
- const manager = new UndoManager(root, {
125
- trackedOrigins: new Set([this.yDoc]),
126
- captureTransaction(arg) {
127
- if (undoManagerConfig.captureTransaction) {
128
- return undoManagerConfig.captureTransaction(arg);
129
- }
130
- return true;
131
- },
132
- deleteFilter(item) {
133
- if (undoManagerConfig.deleteFilter) {
134
- return undoManagerConfig.deleteFilter(item);
135
- }
136
- return true;
137
- }
138
- });
139
- this.manager = manager;
140
- manager.on('stack-item-added', event => {
141
- if (event.type === 'undo') {
142
- if (event.origin === manager) {
143
- this.index++;
144
- }
145
- else {
146
- this.historyItems.length = this.index;
147
- this.historyItems.push(this.getRelativeCursorLocation());
148
- this.index++;
149
- }
150
- }
151
- else {
152
- this.index--;
153
- }
154
- if (manager.undoStack.length > this.stackSize) {
155
- this.historyItems.shift();
156
- manager.undoStack.shift();
157
- }
158
- if (event.origin === this.yDoc) {
159
- this.pushEvent.next();
160
- }
161
- this.changeEvent.next();
162
- });
163
- manager.on('stack-item-popped', () => {
164
- const position = this.historyItems[this.index - 1];
165
- if (position) {
166
- const selection = this.getAbstractSelection(position);
167
- if (selection) {
168
- this.selection.setBaseAndExtent(selection.anchorSlot, selection.anchorOffset, selection.focusSlot, selection.focusOffset);
169
- return;
170
- }
171
- }
172
- this.selection.unSelect();
173
- });
174
- this.subscriptions.push(this.selection.onChange.subscribe(() => {
175
- const paths = this.selection.getPaths();
176
- this.selectionChangeEvent.next(paths);
177
- }), this.scheduler.onDocChanged.pipe(map(item => {
178
- return item.filter(i => {
179
- return i.from !== ChangeOrigin.Remote;
180
- });
181
- }), filter(item => {
182
- return item.length;
183
- })).subscribe(() => {
184
- const updates = [];
185
- let update = null;
186
- for (const item of this.updateRemoteActions) {
187
- if (!update) {
188
- update = {
189
- record: item.record,
190
- actions: []
191
- };
192
- updates.push(update);
193
- }
194
- if (update.record === item.record) {
195
- update.actions.push(item.action);
196
- }
197
- else {
198
- update = {
199
- record: item.record,
200
- actions: [item.action]
201
- };
202
- updates.push(update);
203
- }
204
- }
205
- this.updateRemoteActions = [];
206
- for (const item of updates) {
207
- this.yDoc.transact(() => {
208
- item.actions.forEach(fn => {
209
- fn();
210
- });
211
- }, item.record ? this.yDoc : this.noRecord);
212
- }
213
- this.localChangesAppliedEvent.next();
214
- }));
215
- this.syncRootComponent(root, rootComponent);
216
- }
217
- back() {
218
- var _a;
219
- if (this.canBack) {
220
- (_a = this.manager) === null || _a === void 0 ? void 0 : _a.undo();
221
- this.backEvent.next();
222
- }
223
- }
224
- forward() {
225
- var _a;
226
- if (this.canForward) {
227
- (_a = this.manager) === null || _a === void 0 ? void 0 : _a.redo();
228
- this.forwardEvent.next();
229
- }
230
- }
231
- clear() {
232
- var _a;
233
- this.index = 0;
234
- this.historyItems = [];
235
- (_a = this.manager) === null || _a === void 0 ? void 0 : _a.clear();
236
- this.changeEvent.next();
237
- }
238
- destroy() {
239
- var _a;
240
- this.index = 0;
241
- this.historyItems = [];
242
- this.subscriptions.forEach(i => i.unsubscribe());
243
- (_a = this.manager) === null || _a === void 0 ? void 0 : _a.destroy();
244
- }
245
- syncRootComponent(root, rootComponent) {
246
- let slots = root.get('slots');
247
- if (!slots) {
248
- slots = new Array();
249
- rootComponent.slots.toArray().forEach(i => {
250
- const sharedSlot = this.createSharedSlotBySlot(i);
251
- slots.push([sharedSlot]);
252
- });
253
- this.yDoc.transact(() => {
254
- root.set('state', rootComponent.state);
255
- root.set('slots', slots);
256
- });
257
- }
258
- else if (slots.length === 0) {
259
- rootComponent.updateState(() => {
260
- return root.get('state');
261
- });
262
- this.yDoc.transact(() => {
263
- rootComponent.slots.toArray().forEach(i => {
264
- const sharedSlot = this.createSharedSlotBySlot(i);
265
- slots.push([sharedSlot]);
266
- });
267
- });
268
- }
269
- else {
270
- rootComponent.updateState(() => {
271
- return root.get('state');
272
- });
273
- rootComponent.slots.clean();
274
- slots.forEach(sharedSlot => {
275
- const slot = this.createSlotBySharedSlot(sharedSlot);
276
- this.syncSlotContent(sharedSlot.get('content'), slot);
277
- this.syncSlotState(sharedSlot, slot);
278
- rootComponent.slots.insert(slot);
279
- });
280
- }
281
- this.syncComponentState(root, rootComponent);
282
- this.syncComponentSlots(slots, rootComponent);
283
- }
284
- getAbstractSelection(position) {
285
- const anchorPosition = createAbsolutePositionFromRelativePosition(position.anchor, this.yDoc);
286
- const focusPosition = createAbsolutePositionFromRelativePosition(position.focus, this.yDoc);
287
- if (anchorPosition && focusPosition) {
288
- const focusSlot = this.contentMap.get(focusPosition.type);
289
- const anchorSlot = this.contentMap.get(anchorPosition.type);
290
- if (focusSlot && anchorSlot) {
291
- return {
292
- anchorSlot,
293
- anchorOffset: anchorPosition.index,
294
- focusSlot,
295
- focusOffset: focusPosition.index
296
- };
297
- }
298
- }
299
- return null;
300
- }
301
- getRelativeCursorLocation() {
302
- const { anchorSlot, anchorOffset, focusSlot, focusOffset } = this.selection;
303
- if (anchorSlot) {
304
- const anchorYText = this.contentMap.get(anchorSlot);
305
- if (anchorYText) {
306
- const anchorPosition = createRelativePositionFromTypeIndex(anchorYText, anchorOffset);
307
- if (focusSlot) {
308
- const focusYText = this.contentMap.get(focusSlot);
309
- if (focusYText) {
310
- const focusPosition = createRelativePositionFromTypeIndex(focusYText, focusOffset);
311
- return {
312
- focus: focusPosition,
313
- anchor: anchorPosition
314
- };
315
- }
316
- }
317
- }
318
- }
319
- return null;
320
- }
321
- syncSlotContent(content, slot) {
322
- this.contentMap.set(slot, content);
323
- const syncRemote = (ev, tr) => {
324
- this.runRemoteUpdate(tr, () => {
325
- slot.retain(0);
326
- ev.keysChanged.forEach(key => {
327
- const change = ev.keys.get(key);
328
- if (!change) {
329
- return;
330
- }
331
- const updateType = change.action;
332
- if (updateType === 'update' || updateType === 'add') {
333
- const attribute = this.registry.getAttribute(key);
334
- if (attribute) {
335
- slot.setAttribute(attribute, content.getAttribute(key));
336
- }
337
- }
338
- else if (updateType === 'delete') {
339
- const attribute = this.registry.getAttribute(key);
340
- if (attribute) {
341
- slot.removeAttribute(attribute);
342
- }
343
- }
344
- });
345
- ev.delta.forEach(action => {
346
- if (Reflect.has(action, 'retain')) {
347
- if (action.attributes) {
348
- const formats = remoteFormatsToLocal(this.registry, action.attributes);
349
- if (formats.length) {
350
- slot.retain(action.retain, formats);
351
- }
352
- slot.retain(slot.index + action.retain);
353
- }
354
- else {
355
- slot.retain(action.retain);
356
- }
357
- }
358
- else if (action.insert) {
359
- const index = slot.index;
360
- let length = 1;
361
- if (typeof action.insert === 'string') {
362
- length = action.insert.length;
363
- slot.insert(action.insert, remoteFormatsToLocal(this.registry, action.attributes));
364
- }
365
- else {
366
- const sharedComponent = action.insert;
367
- const component = this.createComponentBySharedComponent(sharedComponent);
368
- this.syncComponentSlots(sharedComponent.get('slots'), component);
369
- this.syncComponentState(sharedComponent, component);
370
- slot.insert(component);
371
- }
372
- if (this.selection.isSelected && tr.origin !== this.manager) {
373
- if (slot === this.selection.anchorSlot && this.selection.anchorOffset > index) {
374
- this.selection.setAnchor(slot, this.selection.anchorOffset + length);
375
- }
376
- if (slot === this.selection.focusSlot && this.selection.focusOffset > index) {
377
- this.selection.setFocus(slot, this.selection.focusOffset + length);
378
- }
379
- }
380
- }
381
- else if (action.delete) {
382
- const index = slot.index;
383
- slot.delete(action.delete);
384
- if (this.selection.isSelected && tr.origin !== this.manager) {
385
- if (slot === this.selection.anchorSlot && this.selection.anchorOffset >= index) {
386
- this.selection.setAnchor(slot, this.selection.startOffset - action.delete);
387
- }
388
- if (slot === this.selection.focusSlot && this.selection.focusOffset >= index) {
389
- this.selection.setFocus(slot, this.selection.focusOffset - action.delete);
390
- }
391
- }
392
- }
393
- });
394
- });
395
- };
396
- content.observe(syncRemote);
397
- const sub = slot.onContentChange.subscribe(actions => {
398
- this.runLocalUpdate(() => {
399
- var _a;
400
- let offset = 0;
401
- let length = 0;
402
- for (const action of actions) {
403
- if (action.type === 'retain') {
404
- const formats = action.formats;
405
- if (formats) {
406
- const keys = Object.keys(formats);
407
- let length = keys.length;
408
- keys.forEach(key => {
409
- const formatter = this.registry.getFormatter(key);
410
- if (!formatter) {
411
- length--;
412
- Reflect.deleteProperty(formats, key);
413
- }
414
- });
415
- if (length) {
416
- content.format(offset, action.offset, formats);
417
- }
418
- }
419
- else {
420
- offset = action.offset;
421
- }
422
- }
423
- else if (action.type === 'insert') {
424
- const delta = content.toDelta();
425
- const isEmpty = delta.length === 1 && delta[0].insert === Slot.emptyPlaceholder;
426
- if (typeof action.content === 'string') {
427
- length = action.content.length;
428
- content.insert(offset, action.content, action.formats || {});
429
- }
430
- else {
431
- length = 1;
432
- const sharedComponent = this.createSharedComponentByComponent(action.ref);
433
- content.insertEmbed(offset, sharedComponent, action.formats || {});
434
- }
435
- if (isEmpty && offset === 0) {
436
- content.delete(content.length - 1, 1);
437
- }
438
- offset += length;
439
- }
440
- else if (action.type === 'delete') {
441
- const delta = content.toDelta();
442
- if (content.length) {
443
- content.delete(offset, action.count);
444
- }
445
- if (content.length === 0) {
446
- content.insert(0, '\n', (_a = delta[0]) === null || _a === void 0 ? void 0 : _a.attributes);
447
- }
448
- }
449
- else if (action.type === 'attrSet') {
450
- content.setAttribute(action.name, action.value);
451
- }
452
- else if (action.type === 'attrRemove') {
453
- content.removeAttribute(action.name);
454
- }
455
- }
456
- });
457
- });
458
- sub.add(slot.onChildComponentRemove.subscribe(components => {
459
- components.forEach(c => {
460
- this.cleanSubscriptionsByComponent(c);
461
- });
462
- }));
463
- this.contentSyncCaches.set(slot, () => {
464
- content.unobserve(syncRemote);
465
- sub.unsubscribe();
466
- });
467
- }
468
- syncSlotState(remoteSlot, slot) {
469
- const syncRemote = (ev, tr) => {
470
- this.runRemoteUpdate(tr, () => {
471
- ev.keysChanged.forEach(key => {
472
- if (key === 'state') {
473
- const state = ev.target.get('state');
474
- slot.updateState(draft => {
475
- if (typeof draft === 'object' && draft !== null) {
476
- Object.assign(draft, state);
477
- }
478
- else {
479
- return state;
480
- }
481
- });
482
- }
483
- });
484
- });
485
- };
486
- remoteSlot.observe(syncRemote);
487
- const sub = slot.onStateChange.subscribe(change => {
488
- this.runLocalUpdate(() => {
489
- remoteSlot.set('state', change.newState);
490
- }, change.record);
491
- });
492
- this.slotStateSyncCaches.set(slot, () => {
493
- remoteSlot.unobserve(syncRemote);
494
- sub.unsubscribe();
495
- });
496
- }
497
- syncComponentSlots(remoteSlots, component) {
498
- const slots = component.slots;
499
- const syncRemote = (ev, tr) => {
500
- this.runRemoteUpdate(tr, () => {
501
- let index = 0;
502
- slots.retain(index);
503
- ev.delta.forEach(action => {
504
- if (Reflect.has(action, 'retain')) {
505
- index += action.retain;
506
- slots.retain(index);
507
- }
508
- else if (action.insert) {
509
- action.insert.forEach(item => {
510
- const slot = this.createSlotBySharedSlot(item);
511
- slots.insert(slot);
512
- this.syncSlotContent(item.get('content'), slot);
513
- this.syncSlotState(item, slot);
514
- index++;
515
- });
516
- }
517
- else if (action.delete) {
518
- slots.retain(index);
519
- slots.delete(action.delete);
520
- }
521
- });
522
- });
523
- };
524
- remoteSlots.observe(syncRemote);
525
- const sub = slots.onChange.subscribe(operations => {
526
- this.runLocalUpdate(() => {
527
- const applyActions = operations.apply;
528
- let index;
529
- applyActions.forEach(action => {
530
- if (action.type === 'retain') {
531
- index = action.offset;
532
- }
533
- else if (action.type === 'insertSlot') {
534
- const sharedSlot = this.createSharedSlotBySlot(action.ref);
535
- remoteSlots.insert(index, [sharedSlot]);
536
- index++;
537
- }
538
- else if (action.type === 'delete') {
539
- remoteSlots.delete(index, action.count);
540
- }
541
- });
542
- });
543
- });
544
- sub.add(slots.onChildSlotRemove.subscribe(slots => {
545
- slots.forEach(slot => {
546
- this.cleanSubscriptionsBySlot(slot);
547
- });
548
- }));
549
- this.slotsSyncCaches.set(component, () => {
550
- remoteSlots.unobserve(syncRemote);
551
- sub.unsubscribe();
552
- });
553
- }
554
- syncComponentState(remoteComponent, component) {
555
- const syncRemote = (ev, tr) => {
556
- this.runRemoteUpdate(tr, () => {
557
- ev.keysChanged.forEach(key => {
558
- if (key === 'state') {
559
- const state = ev.target.get('state');
560
- component.updateState(draft => {
561
- if (typeof draft === 'object' && draft !== null) {
562
- Object.assign(draft, state);
563
- }
564
- else {
565
- return state;
566
- }
567
- });
568
- }
569
- });
570
- });
571
- };
572
- remoteComponent.observe(syncRemote);
573
- const sub = component.onStateChange.subscribe(change => {
574
- this.runLocalUpdate(() => {
575
- remoteComponent.set('state', change.newState);
576
- }, change.record);
577
- });
578
- this.componentStateSyncCaches.set(component, () => {
579
- remoteComponent.unobserve(syncRemote);
580
- sub.unsubscribe();
581
- });
582
- }
583
- runLocalUpdate(fn, record = true) {
584
- if (this.updateFromRemote || this.controller.readonly) {
585
- return;
586
- }
587
- this.updateRemoteActions.push({
588
- record,
589
- action: fn
590
- });
591
- }
592
- runRemoteUpdate(tr, fn) {
593
- if (tr.origin === this.yDoc) {
594
- return;
595
- }
596
- this.updateFromRemote = true;
597
- if (tr.origin === this.manager) {
598
- this.scheduler.historyApplyTransact(fn);
599
- }
600
- else {
601
- this.scheduler.remoteUpdateTransact(fn);
602
- }
603
- this.updateFromRemote = false;
604
- }
605
- createSharedComponentByComponent(component) {
606
- const sharedComponent = new Map();
607
- sharedComponent.set('state', component.state);
608
- sharedComponent.set('name', component.name);
609
- const sharedSlots = new Array();
610
- sharedComponent.set('slots', sharedSlots);
611
- component.slots.toArray().forEach(slot => {
612
- const sharedSlot = this.createSharedSlotBySlot(slot);
613
- sharedSlots.push([sharedSlot]);
614
- });
615
- this.syncComponentSlots(sharedSlots, component);
616
- this.syncComponentState(sharedComponent, component);
617
- return sharedComponent;
618
- }
619
- createSharedSlotBySlot(slot) {
620
- const sharedSlot = new Map();
621
- sharedSlot.set('schema', slot.schema);
622
- sharedSlot.set('state', slot.state);
623
- const sharedContent = new Text();
624
- sharedSlot.set('content', sharedContent);
625
- let offset = 0;
626
- slot.toDelta().forEach(i => {
627
- let formats = {};
628
- if (i.formats) {
629
- i.formats.forEach(item => {
630
- formats[item[0].name] = item[1];
631
- });
632
- }
633
- else {
634
- formats = null;
635
- }
636
- if (typeof i.insert === 'string') {
637
- sharedContent.insert(offset, i.insert, formats);
638
- }
639
- else {
640
- const sharedComponent = this.createSharedComponentByComponent(i.insert);
641
- sharedContent.insertEmbed(offset, sharedComponent, formats);
642
- }
643
- offset += i.insert.length;
644
- });
645
- slot.getAttributes().forEach(item => {
646
- sharedContent.setAttribute(item[0].name, item[1]);
647
- });
648
- this.syncSlotContent(sharedContent, slot);
649
- this.syncSlotState(sharedSlot, slot);
650
- return sharedSlot;
651
- }
652
- createComponentBySharedComponent(yMap) {
653
- const sharedSlots = yMap.get('slots');
654
- const slots = [];
655
- sharedSlots.forEach(sharedSlot => {
656
- const slot = this.createSlotBySharedSlot(sharedSlot);
657
- slots.push(slot);
658
- });
659
- const name = yMap.get('name');
660
- const state = yMap.get('state');
661
- const instance = this.registry.createComponentByData(name, {
662
- state,
663
- slots
664
- });
665
- if (instance) {
666
- instance.slots.toArray().forEach((slot, index) => {
667
- let sharedSlot = sharedSlots.get(index);
668
- if (!sharedSlot) {
669
- sharedSlot = this.createSharedSlotBySlot(slot);
670
- sharedSlots.push([sharedSlot]);
671
- }
672
- this.syncSlotState(sharedSlot, slot);
673
- this.syncSlotContent(sharedSlot.get('content'), slot);
674
- });
675
- return instance;
676
- }
677
- throw collaborateErrorFn(`cannot find component factory \`${name}\`.`);
678
- }
679
- createSlotBySharedSlot(sharedSlot) {
680
- const content = sharedSlot.get('content');
681
- const delta = content.toDelta();
682
- const slot = this.registry.createSlot({
683
- schema: sharedSlot.get('schema'),
684
- state: sharedSlot.get('state'),
685
- attributes: {},
686
- formats: {},
687
- content: []
688
- });
689
- const attrs = content.getAttributes();
690
- Object.keys(attrs).forEach(key => {
691
- const attribute = this.registry.getAttribute(key);
692
- if (attribute) {
693
- slot.setAttribute(attribute, attrs[key]);
694
- }
695
- });
696
- for (const action of delta) {
697
- if (action.insert) {
698
- if (typeof action.insert === 'string') {
699
- const formats = remoteFormatsToLocal(this.registry, action.attributes);
700
- slot.insert(action.insert, formats);
701
- }
702
- else {
703
- const sharedComponent = action.insert;
704
- const component = this.createComponentBySharedComponent(sharedComponent);
705
- slot.insert(component, remoteFormatsToLocal(this.registry, action.attributes));
706
- this.syncComponentSlots(sharedComponent.get('slots'), component);
707
- this.syncComponentState(sharedComponent, component);
708
- }
709
- }
710
- else {
711
- throw collaborateErrorFn('unexpected delta action.');
712
- }
713
- }
714
- return slot;
715
- }
716
- cleanSubscriptionsBySlot(slot) {
717
- this.contentMap.delete(slot);
718
- [this.contentSyncCaches.get(slot), this.slotStateSyncCaches.get(slot)].forEach(fn => {
719
- if (fn) {
720
- fn();
721
- }
722
- });
723
- slot.sliceContent().forEach(i => {
724
- if (typeof i !== 'string') {
725
- this.cleanSubscriptionsByComponent(i);
726
- }
727
- });
728
- }
729
- cleanSubscriptionsByComponent(component) {
730
- [this.slotsSyncCaches.get(component), this.componentStateSyncCaches.get(component)].forEach(fn => {
731
- if (fn) {
732
- fn();
733
- }
734
- });
735
- component.slots.toArray().forEach(slot => {
736
- this.cleanSubscriptionsBySlot(slot);
737
- });
738
- }
739
- };
740
- Collaborate = __decorate([
741
- Injectable(),
742
- __param(0, Inject(HISTORY_STACK_SIZE)),
743
- __param(7, Optional()),
744
- __metadata("design:paramtypes", [Number, RootComponentRef,
745
- Controller,
746
- Scheduler,
747
- Registry,
748
- Selection,
749
- Starter,
750
- CustomUndoManagerConfig])
751
- ], Collaborate);
752
- function remoteFormatsToLocal(registry, attrs) {
753
- const formats = [];
754
- if (attrs) {
755
- Object.keys(attrs).forEach(key => {
756
- const formatter = registry.getFormatter(key);
757
- if (formatter) {
758
- formats.push([formatter, attrs[key]]);
759
- }
760
- });
761
- }
762
- return formats;
36
+ const collaborateErrorFn = makeError('Collaborate');
37
+ class ContentMap {
38
+ constructor() {
39
+ this.slotAndYTextMap = new WeakMap();
40
+ this.yTextAndSLotMap = new WeakMap();
41
+ }
42
+ set(key, value) {
43
+ if (key instanceof Slot) {
44
+ this.slotAndYTextMap.set(key, value);
45
+ this.yTextAndSLotMap.set(value, key);
46
+ }
47
+ else {
48
+ this.slotAndYTextMap.set(value, key);
49
+ this.yTextAndSLotMap.set(key, value);
50
+ }
51
+ }
52
+ get(key) {
53
+ if (key instanceof Slot) {
54
+ return this.slotAndYTextMap.get(key) || null;
55
+ }
56
+ return this.yTextAndSLotMap.get(key) || null;
57
+ }
58
+ delete(key) {
59
+ if (key instanceof Slot) {
60
+ const v = this.slotAndYTextMap.get(key);
61
+ this.slotAndYTextMap.delete(key);
62
+ if (v) {
63
+ this.yTextAndSLotMap.delete(v);
64
+ }
65
+ }
66
+ else {
67
+ const v = this.yTextAndSLotMap.get(key);
68
+ this.yTextAndSLotMap.delete(key);
69
+ if (v) {
70
+ this.slotAndYTextMap.delete(v);
71
+ }
72
+ }
73
+ }
74
+ }
75
+ class CustomUndoManagerConfig {
76
+ }
77
+ let Collaborate = class Collaborate {
78
+ get canBack() {
79
+ var _a;
80
+ return ((_a = this.manager) === null || _a === void 0 ? void 0 : _a.canUndo()) || false;
81
+ }
82
+ get canForward() {
83
+ var _a;
84
+ return ((_a = this.manager) === null || _a === void 0 ? void 0 : _a.canRedo()) || false;
85
+ }
86
+ constructor(stackSize, rootComponentRef, controller, scheduler, registry, selection, starter, undoManagerConfig) {
87
+ this.stackSize = stackSize;
88
+ this.rootComponentRef = rootComponentRef;
89
+ this.controller = controller;
90
+ this.scheduler = scheduler;
91
+ this.registry = registry;
92
+ this.selection = selection;
93
+ this.starter = starter;
94
+ this.undoManagerConfig = undoManagerConfig;
95
+ this.yDoc = new Doc();
96
+ this.backEvent = new Subject();
97
+ this.forwardEvent = new Subject();
98
+ this.changeEvent = new Subject();
99
+ this.pushEvent = new Subject();
100
+ this.manager = null;
101
+ this.subscriptions = [];
102
+ this.updateFromRemote = false;
103
+ this.contentSyncCaches = new WeakMap();
104
+ this.slotStateSyncCaches = new WeakMap();
105
+ this.slotsSyncCaches = new WeakMap();
106
+ this.componentStateSyncCaches = new WeakMap();
107
+ this.localChangesAppliedEvent = new Subject();
108
+ this.selectionChangeEvent = new Subject();
109
+ this.contentMap = new ContentMap();
110
+ this.updateRemoteActions = [];
111
+ this.noRecord = {};
112
+ this.historyItems = [];
113
+ this.index = 0;
114
+ this.onBack = this.backEvent.asObservable();
115
+ this.onForward = this.forwardEvent.asObservable();
116
+ this.onChange = this.changeEvent.asObservable();
117
+ this.onPush = this.pushEvent.asObservable();
118
+ this.onLocalChangesApplied = this.localChangesAppliedEvent.asObservable();
119
+ }
120
+ listen() {
121
+ const root = this.yDoc.getMap('RootComponent');
122
+ const rootComponent = this.rootComponentRef.component;
123
+ const undoManagerConfig = this.undoManagerConfig || {};
124
+ const manager = new UndoManager(root, {
125
+ trackedOrigins: new Set([this.yDoc]),
126
+ captureTransaction(arg) {
127
+ if (undoManagerConfig.captureTransaction) {
128
+ return undoManagerConfig.captureTransaction(arg);
129
+ }
130
+ return true;
131
+ },
132
+ deleteFilter(item) {
133
+ if (undoManagerConfig.deleteFilter) {
134
+ return undoManagerConfig.deleteFilter(item);
135
+ }
136
+ return true;
137
+ }
138
+ });
139
+ this.manager = manager;
140
+ manager.on('stack-item-added', event => {
141
+ if (event.type === 'undo') {
142
+ if (event.origin === manager) {
143
+ this.index++;
144
+ }
145
+ else {
146
+ this.historyItems.length = this.index;
147
+ this.historyItems.push(this.getRelativeCursorLocation());
148
+ this.index++;
149
+ }
150
+ }
151
+ else {
152
+ this.index--;
153
+ }
154
+ if (manager.undoStack.length > this.stackSize) {
155
+ this.historyItems.shift();
156
+ manager.undoStack.shift();
157
+ }
158
+ if (event.origin === this.yDoc) {
159
+ this.pushEvent.next();
160
+ }
161
+ this.changeEvent.next();
162
+ });
163
+ manager.on('stack-item-popped', () => {
164
+ const position = this.historyItems[this.index - 1];
165
+ if (position) {
166
+ const selection = this.getAbstractSelection(position);
167
+ if (selection) {
168
+ this.selection.setBaseAndExtent(selection.anchorSlot, selection.anchorOffset, selection.focusSlot, selection.focusOffset);
169
+ return;
170
+ }
171
+ }
172
+ this.selection.unSelect();
173
+ });
174
+ this.subscriptions.push(this.selection.onChange.subscribe(() => {
175
+ const paths = this.selection.getPaths();
176
+ this.selectionChangeEvent.next(paths);
177
+ }), this.scheduler.onDocChanged.pipe(map(item => {
178
+ return item.filter(i => {
179
+ return i.from !== ChangeOrigin.Remote;
180
+ });
181
+ }), filter(item => {
182
+ return item.length;
183
+ })).subscribe(() => {
184
+ const updates = [];
185
+ let update = null;
186
+ for (const item of this.updateRemoteActions) {
187
+ if (!update) {
188
+ update = {
189
+ record: item.record,
190
+ actions: []
191
+ };
192
+ updates.push(update);
193
+ }
194
+ if (update.record === item.record) {
195
+ update.actions.push(item.action);
196
+ }
197
+ else {
198
+ update = {
199
+ record: item.record,
200
+ actions: [item.action]
201
+ };
202
+ updates.push(update);
203
+ }
204
+ }
205
+ this.updateRemoteActions = [];
206
+ for (const item of updates) {
207
+ this.yDoc.transact(() => {
208
+ item.actions.forEach(fn => {
209
+ fn();
210
+ });
211
+ }, item.record ? this.yDoc : this.noRecord);
212
+ }
213
+ this.localChangesAppliedEvent.next();
214
+ }));
215
+ this.syncRootComponent(root, rootComponent);
216
+ }
217
+ back() {
218
+ var _a;
219
+ if (this.canBack) {
220
+ (_a = this.manager) === null || _a === void 0 ? void 0 : _a.undo();
221
+ this.backEvent.next();
222
+ }
223
+ }
224
+ forward() {
225
+ var _a;
226
+ if (this.canForward) {
227
+ (_a = this.manager) === null || _a === void 0 ? void 0 : _a.redo();
228
+ this.forwardEvent.next();
229
+ }
230
+ }
231
+ clear() {
232
+ var _a;
233
+ this.index = 0;
234
+ this.historyItems = [];
235
+ (_a = this.manager) === null || _a === void 0 ? void 0 : _a.clear();
236
+ this.changeEvent.next();
237
+ }
238
+ destroy() {
239
+ var _a;
240
+ this.index = 0;
241
+ this.historyItems = [];
242
+ this.subscriptions.forEach(i => i.unsubscribe());
243
+ (_a = this.manager) === null || _a === void 0 ? void 0 : _a.destroy();
244
+ }
245
+ syncRootComponent(root, rootComponent) {
246
+ let slots = root.get('slots');
247
+ if (!slots) {
248
+ slots = new Array();
249
+ rootComponent.slots.toArray().forEach(i => {
250
+ const sharedSlot = this.createSharedSlotBySlot(i);
251
+ slots.push([sharedSlot]);
252
+ });
253
+ this.yDoc.transact(() => {
254
+ root.set('state', rootComponent.state);
255
+ root.set('slots', slots);
256
+ });
257
+ }
258
+ else if (slots.length === 0) {
259
+ rootComponent.updateState(() => {
260
+ return root.get('state');
261
+ });
262
+ this.yDoc.transact(() => {
263
+ rootComponent.slots.toArray().forEach(i => {
264
+ const sharedSlot = this.createSharedSlotBySlot(i);
265
+ slots.push([sharedSlot]);
266
+ });
267
+ });
268
+ }
269
+ else {
270
+ rootComponent.updateState(() => {
271
+ return root.get('state');
272
+ });
273
+ rootComponent.slots.clean();
274
+ slots.forEach(sharedSlot => {
275
+ const slot = this.createSlotBySharedSlot(sharedSlot);
276
+ this.syncSlotContent(sharedSlot.get('content'), slot);
277
+ this.syncSlotState(sharedSlot, slot);
278
+ rootComponent.slots.insert(slot);
279
+ });
280
+ }
281
+ this.syncComponentState(root, rootComponent);
282
+ this.syncComponentSlots(slots, rootComponent);
283
+ }
284
+ getAbstractSelection(position) {
285
+ const anchorPosition = createAbsolutePositionFromRelativePosition(position.anchor, this.yDoc);
286
+ const focusPosition = createAbsolutePositionFromRelativePosition(position.focus, this.yDoc);
287
+ if (anchorPosition && focusPosition) {
288
+ const focusSlot = this.contentMap.get(focusPosition.type);
289
+ const anchorSlot = this.contentMap.get(anchorPosition.type);
290
+ if (focusSlot && anchorSlot) {
291
+ return {
292
+ anchorSlot,
293
+ anchorOffset: anchorPosition.index,
294
+ focusSlot,
295
+ focusOffset: focusPosition.index
296
+ };
297
+ }
298
+ }
299
+ return null;
300
+ }
301
+ getRelativeCursorLocation() {
302
+ const { anchorSlot, anchorOffset, focusSlot, focusOffset } = this.selection;
303
+ if (anchorSlot) {
304
+ const anchorYText = this.contentMap.get(anchorSlot);
305
+ if (anchorYText) {
306
+ const anchorPosition = createRelativePositionFromTypeIndex(anchorYText, anchorOffset);
307
+ if (focusSlot) {
308
+ const focusYText = this.contentMap.get(focusSlot);
309
+ if (focusYText) {
310
+ const focusPosition = createRelativePositionFromTypeIndex(focusYText, focusOffset);
311
+ return {
312
+ focus: focusPosition,
313
+ anchor: anchorPosition
314
+ };
315
+ }
316
+ }
317
+ }
318
+ }
319
+ return null;
320
+ }
321
+ syncSlotContent(content, slot) {
322
+ this.contentMap.set(slot, content);
323
+ const syncRemote = (ev, tr) => {
324
+ this.runRemoteUpdate(tr, () => {
325
+ slot.retain(0);
326
+ ev.keysChanged.forEach(key => {
327
+ const change = ev.keys.get(key);
328
+ if (!change) {
329
+ return;
330
+ }
331
+ const updateType = change.action;
332
+ if (updateType === 'update' || updateType === 'add') {
333
+ const attribute = this.registry.getAttribute(key);
334
+ if (attribute) {
335
+ slot.setAttribute(attribute, content.getAttribute(key));
336
+ }
337
+ }
338
+ else if (updateType === 'delete') {
339
+ const attribute = this.registry.getAttribute(key);
340
+ if (attribute) {
341
+ slot.removeAttribute(attribute);
342
+ }
343
+ }
344
+ });
345
+ ev.delta.forEach(action => {
346
+ if (Reflect.has(action, 'retain')) {
347
+ if (action.attributes) {
348
+ const formats = remoteFormatsToLocal(this.registry, action.attributes);
349
+ if (formats.length) {
350
+ slot.retain(action.retain, formats);
351
+ }
352
+ slot.retain(slot.index + action.retain);
353
+ }
354
+ else {
355
+ slot.retain(action.retain);
356
+ }
357
+ }
358
+ else if (action.insert) {
359
+ const index = slot.index;
360
+ let length = 1;
361
+ if (typeof action.insert === 'string') {
362
+ length = action.insert.length;
363
+ slot.insert(action.insert, remoteFormatsToLocal(this.registry, action.attributes));
364
+ }
365
+ else {
366
+ const sharedComponent = action.insert;
367
+ const component = this.createComponentBySharedComponent(sharedComponent);
368
+ this.syncComponentSlots(sharedComponent.get('slots'), component);
369
+ this.syncComponentState(sharedComponent, component);
370
+ slot.insert(component);
371
+ }
372
+ if (this.selection.isSelected && tr.origin !== this.manager) {
373
+ if (slot === this.selection.anchorSlot && this.selection.anchorOffset > index) {
374
+ this.selection.setAnchor(slot, this.selection.anchorOffset + length);
375
+ }
376
+ if (slot === this.selection.focusSlot && this.selection.focusOffset > index) {
377
+ this.selection.setFocus(slot, this.selection.focusOffset + length);
378
+ }
379
+ }
380
+ }
381
+ else if (action.delete) {
382
+ const index = slot.index;
383
+ slot.delete(action.delete);
384
+ if (this.selection.isSelected && tr.origin !== this.manager) {
385
+ if (slot === this.selection.anchorSlot && this.selection.anchorOffset >= index) {
386
+ this.selection.setAnchor(slot, this.selection.startOffset - action.delete);
387
+ }
388
+ if (slot === this.selection.focusSlot && this.selection.focusOffset >= index) {
389
+ this.selection.setFocus(slot, this.selection.focusOffset - action.delete);
390
+ }
391
+ }
392
+ }
393
+ });
394
+ });
395
+ };
396
+ content.observe(syncRemote);
397
+ const sub = slot.onContentChange.subscribe(actions => {
398
+ this.runLocalUpdate(() => {
399
+ var _a;
400
+ let offset = 0;
401
+ let length = 0;
402
+ for (const action of actions) {
403
+ if (action.type === 'retain') {
404
+ const formats = action.formats;
405
+ if (formats) {
406
+ const keys = Object.keys(formats);
407
+ let length = keys.length;
408
+ keys.forEach(key => {
409
+ const formatter = this.registry.getFormatter(key);
410
+ if (!formatter) {
411
+ length--;
412
+ Reflect.deleteProperty(formats, key);
413
+ }
414
+ });
415
+ if (length) {
416
+ content.format(offset, action.offset, formats);
417
+ }
418
+ }
419
+ else {
420
+ offset = action.offset;
421
+ }
422
+ }
423
+ else if (action.type === 'insert') {
424
+ const delta = content.toDelta();
425
+ const isEmpty = delta.length === 1 && delta[0].insert === Slot.emptyPlaceholder;
426
+ if (typeof action.content === 'string') {
427
+ length = action.content.length;
428
+ content.insert(offset, action.content, action.formats || {});
429
+ }
430
+ else {
431
+ length = 1;
432
+ const sharedComponent = this.createSharedComponentByComponent(action.ref);
433
+ content.insertEmbed(offset, sharedComponent, action.formats || {});
434
+ }
435
+ if (isEmpty && offset === 0) {
436
+ content.delete(content.length - 1, 1);
437
+ }
438
+ offset += length;
439
+ }
440
+ else if (action.type === 'delete') {
441
+ const delta = content.toDelta();
442
+ if (content.length) {
443
+ content.delete(offset, action.count);
444
+ }
445
+ if (content.length === 0) {
446
+ content.insert(0, '\n', (_a = delta[0]) === null || _a === void 0 ? void 0 : _a.attributes);
447
+ }
448
+ }
449
+ else if (action.type === 'attrSet') {
450
+ content.setAttribute(action.name, action.value);
451
+ }
452
+ else if (action.type === 'attrRemove') {
453
+ content.removeAttribute(action.name);
454
+ }
455
+ }
456
+ });
457
+ });
458
+ sub.add(slot.onChildComponentRemove.subscribe(components => {
459
+ components.forEach(c => {
460
+ this.cleanSubscriptionsByComponent(c);
461
+ });
462
+ }));
463
+ this.contentSyncCaches.set(slot, () => {
464
+ content.unobserve(syncRemote);
465
+ sub.unsubscribe();
466
+ });
467
+ }
468
+ syncSlotState(remoteSlot, slot) {
469
+ const syncRemote = (ev, tr) => {
470
+ this.runRemoteUpdate(tr, () => {
471
+ ev.keysChanged.forEach(key => {
472
+ if (key === 'state') {
473
+ const state = ev.target.get('state');
474
+ slot.updateState(draft => {
475
+ if (typeof draft === 'object' && draft !== null) {
476
+ Object.assign(draft, state);
477
+ }
478
+ else {
479
+ return state;
480
+ }
481
+ });
482
+ }
483
+ });
484
+ });
485
+ };
486
+ remoteSlot.observe(syncRemote);
487
+ const sub = slot.onStateChange.subscribe(change => {
488
+ this.runLocalUpdate(() => {
489
+ remoteSlot.set('state', change.newState);
490
+ }, change.record);
491
+ });
492
+ this.slotStateSyncCaches.set(slot, () => {
493
+ remoteSlot.unobserve(syncRemote);
494
+ sub.unsubscribe();
495
+ });
496
+ }
497
+ syncComponentSlots(remoteSlots, component) {
498
+ const slots = component.slots;
499
+ const syncRemote = (ev, tr) => {
500
+ this.runRemoteUpdate(tr, () => {
501
+ let index = 0;
502
+ slots.retain(index);
503
+ ev.delta.forEach(action => {
504
+ if (Reflect.has(action, 'retain')) {
505
+ index += action.retain;
506
+ slots.retain(index);
507
+ }
508
+ else if (action.insert) {
509
+ action.insert.forEach(item => {
510
+ const slot = this.createSlotBySharedSlot(item);
511
+ slots.insert(slot);
512
+ this.syncSlotContent(item.get('content'), slot);
513
+ this.syncSlotState(item, slot);
514
+ index++;
515
+ });
516
+ }
517
+ else if (action.delete) {
518
+ slots.retain(index);
519
+ slots.delete(action.delete);
520
+ }
521
+ });
522
+ });
523
+ };
524
+ remoteSlots.observe(syncRemote);
525
+ const sub = slots.onChange.subscribe(operations => {
526
+ this.runLocalUpdate(() => {
527
+ const applyActions = operations.apply;
528
+ let index;
529
+ applyActions.forEach(action => {
530
+ if (action.type === 'retain') {
531
+ index = action.offset;
532
+ }
533
+ else if (action.type === 'insertSlot') {
534
+ const sharedSlot = this.createSharedSlotBySlot(action.ref);
535
+ remoteSlots.insert(index, [sharedSlot]);
536
+ index++;
537
+ }
538
+ else if (action.type === 'delete') {
539
+ remoteSlots.delete(index, action.count);
540
+ }
541
+ });
542
+ });
543
+ });
544
+ sub.add(slots.onChildSlotRemove.subscribe(slots => {
545
+ slots.forEach(slot => {
546
+ this.cleanSubscriptionsBySlot(slot);
547
+ });
548
+ }));
549
+ this.slotsSyncCaches.set(component, () => {
550
+ remoteSlots.unobserve(syncRemote);
551
+ sub.unsubscribe();
552
+ });
553
+ }
554
+ syncComponentState(remoteComponent, component) {
555
+ const syncRemote = (ev, tr) => {
556
+ this.runRemoteUpdate(tr, () => {
557
+ ev.keysChanged.forEach(key => {
558
+ if (key === 'state') {
559
+ const state = ev.target.get('state');
560
+ component.updateState(draft => {
561
+ if (typeof draft === 'object' && draft !== null) {
562
+ Object.assign(draft, state);
563
+ }
564
+ else {
565
+ return state;
566
+ }
567
+ });
568
+ }
569
+ });
570
+ });
571
+ };
572
+ remoteComponent.observe(syncRemote);
573
+ const sub = component.onStateChange.subscribe(change => {
574
+ this.runLocalUpdate(() => {
575
+ remoteComponent.set('state', change.newState);
576
+ }, change.record);
577
+ });
578
+ this.componentStateSyncCaches.set(component, () => {
579
+ remoteComponent.unobserve(syncRemote);
580
+ sub.unsubscribe();
581
+ });
582
+ }
583
+ runLocalUpdate(fn, record = true) {
584
+ if (this.updateFromRemote || this.controller.readonly) {
585
+ return;
586
+ }
587
+ this.updateRemoteActions.push({
588
+ record,
589
+ action: fn
590
+ });
591
+ }
592
+ runRemoteUpdate(tr, fn) {
593
+ if (tr.origin === this.yDoc) {
594
+ return;
595
+ }
596
+ this.updateFromRemote = true;
597
+ if (tr.origin === this.manager) {
598
+ this.scheduler.historyApplyTransact(fn);
599
+ }
600
+ else {
601
+ this.scheduler.remoteUpdateTransact(fn);
602
+ }
603
+ this.updateFromRemote = false;
604
+ }
605
+ createSharedComponentByComponent(component) {
606
+ const sharedComponent = new Map();
607
+ sharedComponent.set('state', component.state);
608
+ sharedComponent.set('name', component.name);
609
+ const sharedSlots = new Array();
610
+ sharedComponent.set('slots', sharedSlots);
611
+ component.slots.toArray().forEach(slot => {
612
+ const sharedSlot = this.createSharedSlotBySlot(slot);
613
+ sharedSlots.push([sharedSlot]);
614
+ });
615
+ this.syncComponentSlots(sharedSlots, component);
616
+ this.syncComponentState(sharedComponent, component);
617
+ return sharedComponent;
618
+ }
619
+ createSharedSlotBySlot(slot) {
620
+ const sharedSlot = new Map();
621
+ sharedSlot.set('schema', slot.schema);
622
+ sharedSlot.set('state', slot.state);
623
+ const sharedContent = new Text();
624
+ sharedSlot.set('content', sharedContent);
625
+ let offset = 0;
626
+ slot.toDelta().forEach(i => {
627
+ let formats = {};
628
+ if (i.formats) {
629
+ i.formats.forEach(item => {
630
+ formats[item[0].name] = item[1];
631
+ });
632
+ }
633
+ else {
634
+ formats = null;
635
+ }
636
+ if (typeof i.insert === 'string') {
637
+ sharedContent.insert(offset, i.insert, formats);
638
+ }
639
+ else {
640
+ const sharedComponent = this.createSharedComponentByComponent(i.insert);
641
+ sharedContent.insertEmbed(offset, sharedComponent, formats);
642
+ }
643
+ offset += i.insert.length;
644
+ });
645
+ slot.getAttributes().forEach(item => {
646
+ sharedContent.setAttribute(item[0].name, item[1]);
647
+ });
648
+ this.syncSlotContent(sharedContent, slot);
649
+ this.syncSlotState(sharedSlot, slot);
650
+ return sharedSlot;
651
+ }
652
+ createComponentBySharedComponent(yMap) {
653
+ const sharedSlots = yMap.get('slots');
654
+ const slots = [];
655
+ sharedSlots.forEach(sharedSlot => {
656
+ const slot = this.createSlotBySharedSlot(sharedSlot);
657
+ slots.push(slot);
658
+ });
659
+ const name = yMap.get('name');
660
+ const state = yMap.get('state');
661
+ const instance = this.registry.createComponentByData(name, {
662
+ state,
663
+ slots
664
+ });
665
+ if (instance) {
666
+ instance.slots.toArray().forEach((slot, index) => {
667
+ let sharedSlot = sharedSlots.get(index);
668
+ if (!sharedSlot) {
669
+ sharedSlot = this.createSharedSlotBySlot(slot);
670
+ sharedSlots.push([sharedSlot]);
671
+ }
672
+ this.syncSlotState(sharedSlot, slot);
673
+ this.syncSlotContent(sharedSlot.get('content'), slot);
674
+ });
675
+ return instance;
676
+ }
677
+ throw collaborateErrorFn(`cannot find component factory \`${name}\`.`);
678
+ }
679
+ createSlotBySharedSlot(sharedSlot) {
680
+ const content = sharedSlot.get('content');
681
+ const delta = content.toDelta();
682
+ const slot = this.registry.createSlot({
683
+ schema: sharedSlot.get('schema'),
684
+ state: sharedSlot.get('state'),
685
+ attributes: {},
686
+ formats: {},
687
+ content: []
688
+ });
689
+ const attrs = content.getAttributes();
690
+ Object.keys(attrs).forEach(key => {
691
+ const attribute = this.registry.getAttribute(key);
692
+ if (attribute) {
693
+ slot.setAttribute(attribute, attrs[key]);
694
+ }
695
+ });
696
+ for (const action of delta) {
697
+ if (action.insert) {
698
+ if (typeof action.insert === 'string') {
699
+ const formats = remoteFormatsToLocal(this.registry, action.attributes);
700
+ slot.insert(action.insert, formats);
701
+ }
702
+ else {
703
+ const sharedComponent = action.insert;
704
+ const component = this.createComponentBySharedComponent(sharedComponent);
705
+ slot.insert(component, remoteFormatsToLocal(this.registry, action.attributes));
706
+ this.syncComponentSlots(sharedComponent.get('slots'), component);
707
+ this.syncComponentState(sharedComponent, component);
708
+ }
709
+ }
710
+ else {
711
+ throw collaborateErrorFn('unexpected delta action.');
712
+ }
713
+ }
714
+ return slot;
715
+ }
716
+ cleanSubscriptionsBySlot(slot) {
717
+ this.contentMap.delete(slot);
718
+ [this.contentSyncCaches.get(slot), this.slotStateSyncCaches.get(slot)].forEach(fn => {
719
+ if (fn) {
720
+ fn();
721
+ }
722
+ });
723
+ slot.sliceContent().forEach(i => {
724
+ if (typeof i !== 'string') {
725
+ this.cleanSubscriptionsByComponent(i);
726
+ }
727
+ });
728
+ }
729
+ cleanSubscriptionsByComponent(component) {
730
+ [this.slotsSyncCaches.get(component), this.componentStateSyncCaches.get(component)].forEach(fn => {
731
+ if (fn) {
732
+ fn();
733
+ }
734
+ });
735
+ component.slots.toArray().forEach(slot => {
736
+ this.cleanSubscriptionsBySlot(slot);
737
+ });
738
+ }
739
+ };
740
+ Collaborate = __decorate([
741
+ Injectable(),
742
+ __param(0, Inject(HISTORY_STACK_SIZE)),
743
+ __param(7, Optional()),
744
+ __metadata("design:paramtypes", [Number, RootComponentRef,
745
+ Controller,
746
+ Scheduler,
747
+ Registry,
748
+ Selection,
749
+ Starter,
750
+ CustomUndoManagerConfig])
751
+ ], Collaborate);
752
+ function remoteFormatsToLocal(registry, attrs) {
753
+ const formats = [];
754
+ if (attrs) {
755
+ Object.keys(attrs).forEach(key => {
756
+ const formatter = registry.getFormatter(key);
757
+ if (formatter) {
758
+ formats.push([formatter, attrs[key]]);
759
+ }
760
+ });
761
+ }
762
+ return formats;
763
763
  }
764
764
 
765
- const collaborateModule = {
766
- providers: [
767
- Collaborate,
768
- {
769
- provide: History,
770
- useExisting: Collaborate
771
- }
772
- ]
765
+ const collaborateModule = {
766
+ providers: [
767
+ Collaborate,
768
+ {
769
+ provide: History,
770
+ useExisting: Collaborate
771
+ }
772
+ ]
773
773
  };
774
774
 
775
775
  export { Collaborate, CustomUndoManagerConfig, collaborateModule };