@textbus/collaborate 4.0.4 → 4.1.0-alpha.0
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.
- package/bundles/collab-history.d.ts +38 -0
- package/bundles/collaborate.d.ts +29 -35
- package/bundles/index.esm.js +762 -343
- package/bundles/index.js +761 -340
- package/bundles/multiple-doc-collab-history.d.ts +35 -0
- package/bundles/multiple-document-collaborate-module.d.ts +14 -0
- package/bundles/public-api.d.ts +4 -0
- package/bundles/sub-model-loader.d.ts +45 -0
- package/package.json +2 -2
package/bundles/index.js
CHANGED
@@ -114,6 +114,36 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
114
114
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
115
115
|
};
|
116
116
|
|
117
|
+
const subModelLoaderErrorFn = core.makeError('subModelLoaderError');
|
118
|
+
/**
|
119
|
+
* 子文档加载器
|
120
|
+
*/
|
121
|
+
class SubModelLoader {
|
122
|
+
}
|
123
|
+
exports.NonSubModelLoader = class NonSubModelLoader extends SubModelLoader {
|
124
|
+
createSubModelBySlot() {
|
125
|
+
throw subModelLoaderErrorFn('single document does not support async slot.');
|
126
|
+
}
|
127
|
+
createSubModelByComponent() {
|
128
|
+
throw subModelLoaderErrorFn('single document does not support async component.');
|
129
|
+
}
|
130
|
+
loadSubModelByComponent() {
|
131
|
+
throw subModelLoaderErrorFn('single document does not support async component.');
|
132
|
+
}
|
133
|
+
loadSubModelBySlot() {
|
134
|
+
throw subModelLoaderErrorFn('single document does not support async slot.');
|
135
|
+
}
|
136
|
+
getLoadedModelBySlot() {
|
137
|
+
throw subModelLoaderErrorFn('single document does not support async slot.');
|
138
|
+
}
|
139
|
+
getLoadedModelByComponent() {
|
140
|
+
throw subModelLoaderErrorFn('single document does not support async component.');
|
141
|
+
}
|
142
|
+
};
|
143
|
+
exports.NonSubModelLoader = __decorate([
|
144
|
+
core$1.Injectable()
|
145
|
+
], exports.NonSubModelLoader);
|
146
|
+
|
117
147
|
const collaborateErrorFn = core.makeError('Collaborate');
|
118
148
|
class SlotMap {
|
119
149
|
constructor() {
|
@@ -153,112 +183,41 @@ class SlotMap {
|
|
153
183
|
}
|
154
184
|
}
|
155
185
|
}
|
156
|
-
class CustomUndoManagerConfig {
|
157
|
-
}
|
158
186
|
exports.Collaborate = class Collaborate {
|
159
|
-
|
160
|
-
var _a;
|
161
|
-
return ((_a = this.manager) === null || _a === void 0 ? void 0 : _a.canUndo()) || false;
|
162
|
-
}
|
163
|
-
get canForward() {
|
164
|
-
var _a;
|
165
|
-
return ((_a = this.manager) === null || _a === void 0 ? void 0 : _a.canRedo()) || false;
|
166
|
-
}
|
167
|
-
constructor(stackSize, rootComponentRef, scheduler, registry, selection, undoManagerConfig) {
|
168
|
-
this.stackSize = stackSize;
|
169
|
-
this.rootComponentRef = rootComponentRef;
|
187
|
+
constructor(scheduler, registry, selection, subModelLoader) {
|
170
188
|
this.scheduler = scheduler;
|
171
189
|
this.registry = registry;
|
172
190
|
this.selection = selection;
|
173
|
-
this.
|
191
|
+
this.subModelLoader = subModelLoader;
|
174
192
|
this.yDoc = new yjs.Doc();
|
175
|
-
this.
|
176
|
-
this.forwardEvent = new stream.Subject();
|
177
|
-
this.changeEvent = new stream.Subject();
|
178
|
-
this.pushEvent = new stream.Subject();
|
179
|
-
this.manager = null;
|
193
|
+
this.slotMap = new SlotMap();
|
180
194
|
this.subscriptions = [];
|
181
195
|
this.updateFromRemote = false;
|
182
|
-
this.
|
183
|
-
this.
|
184
|
-
this.slotMap = new SlotMap();
|
185
|
-
this.updateRemoteActions = [];
|
196
|
+
this.addSubModelEvent = new stream.Subject();
|
197
|
+
this.updateRemoteActions = new WeakMap();
|
186
198
|
this.noRecord = {};
|
187
|
-
this.
|
188
|
-
this.index = 0;
|
189
|
-
this.onBack = this.backEvent.asObservable();
|
190
|
-
this.onForward = this.forwardEvent.asObservable();
|
191
|
-
this.onChange = this.changeEvent.asObservable();
|
192
|
-
this.onPush = this.pushEvent.asObservable();
|
193
|
-
this.onLocalChangesApplied = this.localChangesAppliedEvent.asObservable();
|
199
|
+
this.onAddSubModel = this.addSubModelEvent.asObservable();
|
194
200
|
}
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
this.
|
215
|
-
let beforePosition = null;
|
216
|
-
this.subscriptions.push(this.scheduler.onLocalChangeBefore.subscribe(() => {
|
217
|
-
beforePosition = this.getRelativeCursorLocation();
|
218
|
-
}));
|
219
|
-
manager.on('stack-item-added', (event) => {
|
220
|
-
if (event.type === 'undo') {
|
221
|
-
if (event.origin === manager) {
|
222
|
-
this.index++;
|
223
|
-
}
|
224
|
-
else {
|
225
|
-
this.historyItems.length = this.index;
|
226
|
-
this.historyItems.push({
|
227
|
-
before: beforePosition,
|
228
|
-
after: this.getRelativeCursorLocation()
|
229
|
-
});
|
230
|
-
this.index++;
|
231
|
-
}
|
232
|
-
}
|
233
|
-
else {
|
234
|
-
this.index--;
|
235
|
-
}
|
236
|
-
if (manager.undoStack.length > this.stackSize) {
|
237
|
-
this.historyItems.shift();
|
238
|
-
manager.undoStack.shift();
|
239
|
-
}
|
240
|
-
if (event.origin === this.yDoc) {
|
241
|
-
this.pushEvent.next();
|
242
|
-
}
|
243
|
-
this.changeEvent.next();
|
244
|
-
});
|
245
|
-
manager.on('stack-item-popped', (ev) => {
|
246
|
-
const index = ev.type === 'undo' ? this.index : this.index - 1;
|
247
|
-
const position = this.historyItems[index] || null;
|
248
|
-
const p = ev.type === 'undo' ? position === null || position === void 0 ? void 0 : position.before : position === null || position === void 0 ? void 0 : position.after;
|
249
|
-
if (p) {
|
250
|
-
const selection = this.getAbstractSelection(p);
|
251
|
-
if (selection) {
|
252
|
-
this.selection.setBaseAndExtent(selection.anchorSlot, selection.anchorOffset, selection.focusSlot, selection.focusOffset);
|
253
|
-
return;
|
254
|
-
}
|
255
|
-
}
|
256
|
-
this.selection.unSelect();
|
257
|
-
});
|
258
|
-
this.subscriptions.push(this.selection.onChange.subscribe(() => {
|
259
|
-
const paths = this.selection.getPaths();
|
260
|
-
this.selectionChangeEvent.next(paths);
|
261
|
-
}), this.scheduler.onDocChanged.pipe(stream.map(item => {
|
201
|
+
syncRootComponent(yDoc, sharedComponent, localComponent) {
|
202
|
+
this.initSyncEvent(yDoc);
|
203
|
+
this.syncComponent(yDoc, sharedComponent, localComponent);
|
204
|
+
}
|
205
|
+
syncRootSlot(yDoc, sharedSlot, localSlot) {
|
206
|
+
if (sharedSlot.length) {
|
207
|
+
localSlot.retain(0);
|
208
|
+
localSlot.delete(localSlot.length);
|
209
|
+
localSlot.cleanAttributes();
|
210
|
+
localSlot.cleanFormats();
|
211
|
+
this.initLocalSlotBySharedSlot(sharedSlot, localSlot);
|
212
|
+
}
|
213
|
+
else {
|
214
|
+
this.initSharedSlotByLocalSlot(sharedSlot, localSlot);
|
215
|
+
}
|
216
|
+
this.initSyncEvent(yDoc);
|
217
|
+
this.syncSlot(sharedSlot, localSlot);
|
218
|
+
}
|
219
|
+
initSyncEvent(yDoc) {
|
220
|
+
this.subscriptions.push(this.scheduler.onDocChanged.pipe(stream.map(item => {
|
262
221
|
return item.filter(i => {
|
263
222
|
return i.from !== core.ChangeOrigin.Remote;
|
264
223
|
});
|
@@ -267,7 +226,8 @@ exports.Collaborate = class Collaborate {
|
|
267
226
|
})).subscribe(() => {
|
268
227
|
const updates = [];
|
269
228
|
let update = null;
|
270
|
-
|
229
|
+
const updateRemoteActions = this.updateRemoteActions.get(yDoc) || [];
|
230
|
+
for (const item of updateRemoteActions) {
|
271
231
|
if (!update) {
|
272
232
|
update = {
|
273
233
|
record: item.record,
|
@@ -286,240 +246,54 @@ exports.Collaborate = class Collaborate {
|
|
286
246
|
updates.push(update);
|
287
247
|
}
|
288
248
|
}
|
289
|
-
this.updateRemoteActions
|
249
|
+
this.updateRemoteActions.delete(yDoc);
|
290
250
|
for (const item of updates) {
|
291
|
-
|
251
|
+
yDoc.transact(() => {
|
292
252
|
item.actions.forEach(fn => {
|
293
253
|
fn();
|
294
254
|
});
|
295
|
-
}, item.record ?
|
255
|
+
}, item.record ? yDoc : this.noRecord);
|
296
256
|
}
|
297
|
-
this.localChangesAppliedEvent.next();
|
298
257
|
}));
|
299
|
-
this.syncRootComponent(root, rootComponent);
|
300
|
-
}
|
301
|
-
back() {
|
302
|
-
var _a;
|
303
|
-
if (this.canBack) {
|
304
|
-
(_a = this.manager) === null || _a === void 0 ? void 0 : _a.undo();
|
305
|
-
this.backEvent.next();
|
306
|
-
}
|
307
|
-
}
|
308
|
-
forward() {
|
309
|
-
var _a;
|
310
|
-
if (this.canForward) {
|
311
|
-
(_a = this.manager) === null || _a === void 0 ? void 0 : _a.redo();
|
312
|
-
this.forwardEvent.next();
|
313
|
-
}
|
314
|
-
}
|
315
|
-
clear() {
|
316
|
-
var _a;
|
317
|
-
const last = this.historyItems.pop();
|
318
|
-
this.historyItems = last ? [last] : [];
|
319
|
-
this.index = last ? 1 : 0;
|
320
|
-
(_a = this.manager) === null || _a === void 0 ? void 0 : _a.clear();
|
321
|
-
this.changeEvent.next();
|
322
|
-
}
|
323
|
-
destroy() {
|
324
|
-
var _a;
|
325
|
-
this.index = 0;
|
326
|
-
this.historyItems = [];
|
327
|
-
this.subscriptions.forEach(i => i.unsubscribe());
|
328
|
-
(_a = this.manager) === null || _a === void 0 ? void 0 : _a.destroy();
|
329
258
|
}
|
330
|
-
|
331
|
-
let state =
|
259
|
+
syncComponent(yDoc, sharedComponent, localComponent) {
|
260
|
+
let state = sharedComponent.get('state');
|
332
261
|
if (!state) {
|
333
262
|
state = new yjs.Map();
|
334
|
-
this.syncLocalMapToSharedMap(
|
335
|
-
|
336
|
-
|
263
|
+
this.syncLocalMapToSharedMap(localComponent.state, state);
|
264
|
+
yDoc.transact(() => {
|
265
|
+
sharedComponent.set('state', state);
|
337
266
|
});
|
338
267
|
}
|
339
268
|
else {
|
340
|
-
Object.keys(
|
341
|
-
Reflect.deleteProperty(
|
269
|
+
Object.keys(localComponent.state).forEach(key => {
|
270
|
+
Reflect.deleteProperty(localComponent.state, key);
|
342
271
|
});
|
343
|
-
this.syncSharedMapToLocalMap(state,
|
272
|
+
this.syncSharedMapToLocalMap(state, localComponent.state);
|
344
273
|
}
|
345
274
|
}
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
}
|
369
|
-
createSharedMapByLocalMap(localMap) {
|
370
|
-
const sharedMap = new yjs.Map();
|
371
|
-
this.syncLocalMapToSharedMap(localMap, sharedMap);
|
372
|
-
return sharedMap;
|
373
|
-
}
|
374
|
-
createSharedArrayByLocalArray(localArray) {
|
375
|
-
const sharedArray = new yjs.Array();
|
376
|
-
localArray.forEach(value => {
|
377
|
-
sharedArray.push([this.createSharedModelByLocalModel(value)]);
|
378
|
-
});
|
379
|
-
this.syncArray(sharedArray, localArray);
|
380
|
-
return sharedArray;
|
381
|
-
}
|
382
|
-
createSharedSlotByLocalSlot(localSlot) {
|
383
|
-
const sharedSlot = new yjs.Text();
|
384
|
-
sharedSlot.setAttribute('__schema__', [...localSlot.schema]);
|
385
|
-
let offset = 0;
|
386
|
-
localSlot.toDelta().forEach(i => {
|
387
|
-
let formats = {};
|
388
|
-
if (i.formats) {
|
389
|
-
i.formats.forEach(item => {
|
390
|
-
formats[item[0].name] = item[1];
|
391
|
-
});
|
392
|
-
}
|
393
|
-
else {
|
394
|
-
formats = null;
|
395
|
-
}
|
396
|
-
if (typeof i.insert === 'string') {
|
397
|
-
sharedSlot.insert(offset, i.insert, formats);
|
398
|
-
}
|
399
|
-
else {
|
400
|
-
const sharedComponent = this.createSharedComponentByLocalComponent(i.insert);
|
401
|
-
sharedSlot.insertEmbed(offset, sharedComponent, formats);
|
402
|
-
}
|
403
|
-
offset += i.insert.length;
|
404
|
-
});
|
405
|
-
localSlot.getAttributes().forEach(item => {
|
406
|
-
sharedSlot.setAttribute(item[0].name, item[1]);
|
407
|
-
});
|
408
|
-
this.syncSlot(sharedSlot, localSlot);
|
409
|
-
return sharedSlot;
|
410
|
-
}
|
411
|
-
createLocalSlotBySharedSlot(sharedSlot) {
|
412
|
-
const delta = sharedSlot.toDelta();
|
413
|
-
const localSlot = new core.Slot(sharedSlot.getAttribute('__schema__') || []); // TODO 这里有潜在的问题
|
414
|
-
const attrs = sharedSlot.getAttributes();
|
415
|
-
Object.keys(attrs).forEach(key => {
|
416
|
-
const attribute = this.registry.getAttribute(key);
|
417
|
-
if (attribute) {
|
418
|
-
localSlot.setAttribute(attribute, attrs[key]);
|
419
|
-
}
|
420
|
-
});
|
421
|
-
for (const action of delta) {
|
422
|
-
if (action.insert) {
|
423
|
-
if (typeof action.insert === 'string') {
|
424
|
-
const formats = remoteFormatsToLocal(this.registry, action.attributes);
|
425
|
-
localSlot.insert(action.insert, formats);
|
426
|
-
}
|
427
|
-
else {
|
428
|
-
const sharedComponent = action.insert;
|
429
|
-
const component = this.createLocalComponentBySharedComponent(sharedComponent);
|
430
|
-
localSlot.insert(component, remoteFormatsToLocal(this.registry, action.attributes));
|
431
|
-
}
|
432
|
-
}
|
433
|
-
else {
|
434
|
-
throw collaborateErrorFn('unexpected delta action.');
|
435
|
-
}
|
436
|
-
}
|
437
|
-
this.syncSlot(sharedSlot, localSlot);
|
438
|
-
return localSlot;
|
439
|
-
}
|
440
|
-
createSharedModelByLocalModel(localModel) {
|
441
|
-
if (localModel instanceof core.Slot) {
|
442
|
-
return this.createSharedSlotByLocalSlot(localModel);
|
443
|
-
}
|
444
|
-
if (Array.isArray(localModel)) {
|
445
|
-
return this.createSharedArrayByLocalArray(localModel);
|
446
|
-
}
|
447
|
-
if (typeof localModel === 'object' && localModel !== null) {
|
448
|
-
return this.createSharedMapByLocalMap(localModel);
|
449
|
-
}
|
450
|
-
return localModel;
|
451
|
-
}
|
452
|
-
createLocalModelBySharedByModel(sharedModel) {
|
453
|
-
if (sharedModel instanceof yjs.Map) {
|
454
|
-
return this.createLocalMapBySharedMap(sharedModel);
|
455
|
-
}
|
456
|
-
if (sharedModel instanceof yjs.Array) {
|
457
|
-
return this.createLocalArrayBySharedArray(sharedModel);
|
458
|
-
}
|
459
|
-
if (sharedModel instanceof yjs.Text) {
|
460
|
-
return this.createLocalSlotBySharedSlot(sharedModel);
|
461
|
-
}
|
462
|
-
return sharedModel;
|
463
|
-
}
|
464
|
-
getAbstractSelection(position) {
|
465
|
-
const anchorPosition = yjs.createAbsolutePositionFromRelativePosition(position.anchor, this.yDoc);
|
466
|
-
const focusPosition = yjs.createAbsolutePositionFromRelativePosition(position.focus, this.yDoc);
|
467
|
-
if (anchorPosition && focusPosition) {
|
468
|
-
const focusSlot = this.slotMap.get(focusPosition.type);
|
469
|
-
const anchorSlot = this.slotMap.get(anchorPosition.type);
|
470
|
-
if (focusSlot && anchorSlot) {
|
471
|
-
return {
|
472
|
-
anchorSlot,
|
473
|
-
anchorOffset: anchorPosition.index,
|
474
|
-
focusSlot,
|
475
|
-
focusOffset: focusPosition.index
|
476
|
-
};
|
477
|
-
}
|
478
|
-
}
|
479
|
-
return null;
|
480
|
-
}
|
481
|
-
getRelativeCursorLocation() {
|
482
|
-
const { anchorSlot, anchorOffset, focusSlot, focusOffset } = this.selection;
|
483
|
-
if (anchorSlot) {
|
484
|
-
const anchorYText = this.slotMap.get(anchorSlot);
|
485
|
-
if (anchorYText) {
|
486
|
-
const anchorPosition = yjs.createRelativePositionFromTypeIndex(anchorYText, anchorOffset);
|
487
|
-
if (focusSlot) {
|
488
|
-
const focusYText = this.slotMap.get(focusSlot);
|
489
|
-
if (focusYText) {
|
490
|
-
const focusPosition = yjs.createRelativePositionFromTypeIndex(focusYText, focusOffset);
|
491
|
-
return {
|
492
|
-
focus: focusPosition,
|
493
|
-
anchor: anchorPosition
|
494
|
-
};
|
495
|
-
}
|
496
|
-
}
|
497
|
-
}
|
498
|
-
}
|
499
|
-
return null;
|
500
|
-
}
|
501
|
-
syncSlot(sharedSlot, localSlot) {
|
502
|
-
const syncRemote = (ev, tr) => {
|
503
|
-
this.runRemoteUpdate(tr, () => {
|
504
|
-
localSlot.retain(0);
|
505
|
-
ev.keysChanged.forEach(key => {
|
506
|
-
const change = ev.keys.get(key);
|
507
|
-
if (!change) {
|
508
|
-
return;
|
509
|
-
}
|
510
|
-
const updateType = change.action;
|
511
|
-
if (updateType === 'update' || updateType === 'add') {
|
512
|
-
const attribute = this.registry.getAttribute(key);
|
513
|
-
if (attribute) {
|
514
|
-
localSlot.setAttribute(attribute, sharedSlot.getAttribute(key));
|
515
|
-
}
|
516
|
-
}
|
517
|
-
else if (updateType === 'delete') {
|
518
|
-
const attribute = this.registry.getAttribute(key);
|
519
|
-
if (attribute) {
|
520
|
-
localSlot.removeAttribute(attribute);
|
521
|
-
}
|
522
|
-
}
|
275
|
+
syncSlot(sharedSlot, localSlot) {
|
276
|
+
const syncRemote = (ev, tr) => {
|
277
|
+
this.runRemoteUpdate(tr, () => {
|
278
|
+
localSlot.retain(0);
|
279
|
+
ev.keysChanged.forEach(key => {
|
280
|
+
const change = ev.keys.get(key);
|
281
|
+
if (!change) {
|
282
|
+
return;
|
283
|
+
}
|
284
|
+
const updateType = change.action;
|
285
|
+
if (updateType === 'update' || updateType === 'add') {
|
286
|
+
const attribute = this.registry.getAttribute(key);
|
287
|
+
if (attribute) {
|
288
|
+
localSlot.setAttribute(attribute, sharedSlot.getAttribute(key));
|
289
|
+
}
|
290
|
+
}
|
291
|
+
else if (updateType === 'delete') {
|
292
|
+
const attribute = this.registry.getAttribute(key);
|
293
|
+
if (attribute) {
|
294
|
+
localSlot.removeAttribute(attribute);
|
295
|
+
}
|
296
|
+
}
|
523
297
|
});
|
524
298
|
ev.delta.forEach(action => {
|
525
299
|
if (Reflect.has(action, 'retain')) {
|
@@ -546,7 +320,7 @@ exports.Collaborate = class Collaborate {
|
|
546
320
|
const component = this.createLocalComponentBySharedComponent(sharedComponent);
|
547
321
|
localSlot.insert(component);
|
548
322
|
}
|
549
|
-
if (this.selection.isSelected && tr.origin
|
323
|
+
if (this.selection.isSelected && !(tr.origin instanceof yjs.UndoManager)) {
|
550
324
|
if (localSlot === this.selection.anchorSlot && this.selection.anchorOffset > index) {
|
551
325
|
this.selection.setAnchor(localSlot, this.selection.anchorOffset + length);
|
552
326
|
}
|
@@ -558,7 +332,7 @@ exports.Collaborate = class Collaborate {
|
|
558
332
|
else if (action.delete) {
|
559
333
|
const index = localSlot.index;
|
560
334
|
localSlot.delete(action.delete);
|
561
|
-
if (this.selection.isSelected && tr.origin
|
335
|
+
if (this.selection.isSelected && !(tr.origin instanceof yjs.UndoManager)) {
|
562
336
|
if (localSlot === this.selection.anchorSlot && this.selection.anchorOffset >= index) {
|
563
337
|
this.selection.setAnchor(localSlot, this.selection.startOffset - action.delete);
|
564
338
|
}
|
@@ -572,7 +346,7 @@ exports.Collaborate = class Collaborate {
|
|
572
346
|
};
|
573
347
|
sharedSlot.observe(syncRemote);
|
574
348
|
const sub = localSlot.onContentChange.subscribe(actions => {
|
575
|
-
this.runLocalUpdate(() => {
|
349
|
+
this.runLocalUpdate(sharedSlot.doc, true, () => {
|
576
350
|
var _a;
|
577
351
|
let offset = 0;
|
578
352
|
let length = 0;
|
@@ -630,7 +404,7 @@ exports.Collaborate = class Collaborate {
|
|
630
404
|
sharedSlot.removeAttribute(action.name);
|
631
405
|
}
|
632
406
|
}
|
633
|
-
}
|
407
|
+
});
|
634
408
|
});
|
635
409
|
this.slotMap.set(localSlot, sharedSlot);
|
636
410
|
localSlot.__changeMarker__.destroyCallbacks.push(() => {
|
@@ -639,18 +413,279 @@ exports.Collaborate = class Collaborate {
|
|
639
413
|
sub.unsubscribe();
|
640
414
|
});
|
641
415
|
}
|
416
|
+
destroy() {
|
417
|
+
this.subscriptions.forEach(i => i.unsubscribe());
|
418
|
+
}
|
419
|
+
syncSharedMapToLocalMap(sharedMap, localMap) {
|
420
|
+
sharedMap.forEach((value, key) => {
|
421
|
+
localMap[key] = this.createLocalModelBySharedByModel(value);
|
422
|
+
});
|
423
|
+
this.syncObject(sharedMap, localMap);
|
424
|
+
}
|
425
|
+
createLocalMapBySharedMap(sharedMap) {
|
426
|
+
const localMap = core.createObjectProxy({});
|
427
|
+
this.syncSharedMapToLocalMap(sharedMap, localMap);
|
428
|
+
return localMap;
|
429
|
+
}
|
430
|
+
createLocalArrayBySharedArray(sharedArray) {
|
431
|
+
const localArray = core.createArrayProxy([]);
|
432
|
+
localArray.push(...sharedArray.map(item => this.createLocalModelBySharedByModel(item)));
|
433
|
+
this.syncArray(sharedArray, localArray);
|
434
|
+
return localArray;
|
435
|
+
}
|
436
|
+
syncLocalMapToSharedMap(localMap, sharedMap) {
|
437
|
+
Object.entries(localMap).forEach(([key, value]) => {
|
438
|
+
sharedMap.set(key, this.createSharedModelByLocalModel(value));
|
439
|
+
});
|
440
|
+
this.syncObject(sharedMap, localMap);
|
441
|
+
}
|
442
|
+
createSharedMapByLocalMap(localMap) {
|
443
|
+
const sharedMap = new yjs.Map();
|
444
|
+
this.syncLocalMapToSharedMap(localMap, sharedMap);
|
445
|
+
return sharedMap;
|
446
|
+
}
|
447
|
+
createSharedArrayByLocalArray(localArray) {
|
448
|
+
const sharedArray = new yjs.Array();
|
449
|
+
localArray.forEach(value => {
|
450
|
+
sharedArray.push([this.createSharedModelByLocalModel(value)]);
|
451
|
+
});
|
452
|
+
this.syncArray(sharedArray, localArray);
|
453
|
+
return sharedArray;
|
454
|
+
}
|
455
|
+
createSharedSlotByLocalSlot(localSlot) {
|
456
|
+
const sharedSlot = new yjs.Text();
|
457
|
+
const isAsyncSlot = localSlot instanceof core.AsyncSlot;
|
458
|
+
sharedSlot.setAttribute('schema', [...localSlot.schema]);
|
459
|
+
sharedSlot.setAttribute('type', isAsyncSlot ? 'async' : 'sync');
|
460
|
+
if (isAsyncSlot) {
|
461
|
+
let isDestroyed = false;
|
462
|
+
sharedSlot.setAttribute('metadata', localSlot.metadata);
|
463
|
+
this.subModelLoader.createSubModelBySlot(localSlot).then(subDocument => {
|
464
|
+
if (isDestroyed) {
|
465
|
+
return;
|
466
|
+
}
|
467
|
+
const content = subDocument.getText('content');
|
468
|
+
this.initSharedSlotByLocalSlot(content, localSlot);
|
469
|
+
this.syncSlot(content, localSlot);
|
470
|
+
this.addSubModelEvent.next({
|
471
|
+
yDoc: subDocument,
|
472
|
+
yType: content
|
473
|
+
});
|
474
|
+
localSlot.loader.markAsLoaded();
|
475
|
+
});
|
476
|
+
localSlot.__changeMarker__.destroyCallbacks.push(() => {
|
477
|
+
isDestroyed = true;
|
478
|
+
});
|
479
|
+
return sharedSlot;
|
480
|
+
}
|
481
|
+
const sharedContent = new yjs.Text();
|
482
|
+
this.initSharedSlotByLocalSlot(sharedContent, localSlot);
|
483
|
+
sharedSlot.insertEmbed(0, sharedContent);
|
484
|
+
this.syncSlot(sharedContent, localSlot);
|
485
|
+
return sharedSlot;
|
486
|
+
}
|
487
|
+
initSharedSlotByLocalSlot(sharedContent, localSlot) {
|
488
|
+
let offset = 0;
|
489
|
+
localSlot.toDelta().forEach(i => {
|
490
|
+
let formats = {};
|
491
|
+
if (i.formats) {
|
492
|
+
i.formats.forEach(item => {
|
493
|
+
formats[item[0].name] = item[1];
|
494
|
+
});
|
495
|
+
}
|
496
|
+
else {
|
497
|
+
formats = null;
|
498
|
+
}
|
499
|
+
if (typeof i.insert === 'string') {
|
500
|
+
sharedContent.insert(offset, i.insert, formats);
|
501
|
+
}
|
502
|
+
else {
|
503
|
+
const sharedComponent = this.createSharedComponentByLocalComponent(i.insert);
|
504
|
+
sharedContent.insertEmbed(offset, sharedComponent, formats);
|
505
|
+
}
|
506
|
+
offset += i.insert.length;
|
507
|
+
});
|
508
|
+
localSlot.getAttributes().forEach(item => {
|
509
|
+
sharedContent.setAttribute(item[0].name, item[1]);
|
510
|
+
});
|
511
|
+
}
|
512
|
+
createLocalSlotBySharedSlot(sharedSlot) {
|
513
|
+
var _a;
|
514
|
+
const type = sharedSlot.getAttribute('type');
|
515
|
+
const schema = sharedSlot.getAttribute('schema');
|
516
|
+
if (type === 'async') {
|
517
|
+
const metadata = sharedSlot.getAttribute('metadata');
|
518
|
+
const slot = new core.AsyncSlot(schema || [], metadata);
|
519
|
+
const loadedSubDocument = this.subModelLoader.getLoadedModelBySlot(slot);
|
520
|
+
if (loadedSubDocument) {
|
521
|
+
const subContent = loadedSubDocument.getText('content');
|
522
|
+
this.syncRootSlot(loadedSubDocument, subContent, slot);
|
523
|
+
this.addSubModelEvent.next({
|
524
|
+
yDoc: loadedSubDocument,
|
525
|
+
yType: subContent
|
526
|
+
});
|
527
|
+
slot.loader.markAsLoaded();
|
528
|
+
return slot;
|
529
|
+
}
|
530
|
+
let isDestroyed = false;
|
531
|
+
slot.loader.onRequestLoad.toPromise().then(() => {
|
532
|
+
return this.subModelLoader.loadSubModelBySlot(slot);
|
533
|
+
}).then(subDocument => {
|
534
|
+
if (isDestroyed) {
|
535
|
+
return;
|
536
|
+
}
|
537
|
+
slot.loader.markAsLoaded();
|
538
|
+
const subContent = subDocument.getText('content');
|
539
|
+
this.syncRootSlot(subDocument, subContent, slot);
|
540
|
+
this.addSubModelEvent.next({
|
541
|
+
yDoc: subDocument,
|
542
|
+
yType: subContent
|
543
|
+
});
|
544
|
+
});
|
545
|
+
slot.__changeMarker__.destroyCallbacks.push(() => {
|
546
|
+
isDestroyed = true;
|
547
|
+
});
|
548
|
+
return slot;
|
549
|
+
}
|
550
|
+
const contentDelta = sharedSlot.toDelta();
|
551
|
+
const content = (_a = contentDelta[0]) === null || _a === void 0 ? void 0 : _a.insert;
|
552
|
+
if (!(content instanceof yjs.Text)) {
|
553
|
+
throw collaborateErrorFn('shared slot content type is not `YText`.');
|
554
|
+
}
|
555
|
+
const localSlot = new core.Slot(schema || []);
|
556
|
+
this.initLocalSlotBySharedSlot(content, localSlot);
|
557
|
+
this.syncSlot(content, localSlot);
|
558
|
+
return localSlot;
|
559
|
+
}
|
560
|
+
initLocalSlotBySharedSlot(content, localSlot) {
|
561
|
+
const delta = content.toDelta();
|
562
|
+
const attrs = content.getAttributes();
|
563
|
+
Object.keys(attrs).forEach(key => {
|
564
|
+
const attribute = this.registry.getAttribute(key);
|
565
|
+
if (attribute) {
|
566
|
+
localSlot.setAttribute(attribute, attrs[key]);
|
567
|
+
}
|
568
|
+
});
|
569
|
+
for (const action of delta) {
|
570
|
+
if (action.insert) {
|
571
|
+
if (typeof action.insert === 'string') {
|
572
|
+
const formats = remoteFormatsToLocal(this.registry, action.attributes);
|
573
|
+
localSlot.insert(action.insert, formats);
|
574
|
+
}
|
575
|
+
else {
|
576
|
+
const sharedComponent = action.insert;
|
577
|
+
const component = this.createLocalComponentBySharedComponent(sharedComponent);
|
578
|
+
localSlot.insert(component, remoteFormatsToLocal(this.registry, action.attributes));
|
579
|
+
}
|
580
|
+
}
|
581
|
+
else {
|
582
|
+
throw collaborateErrorFn('unexpected delta action.');
|
583
|
+
}
|
584
|
+
}
|
585
|
+
}
|
586
|
+
createSharedModelByLocalModel(localModel) {
|
587
|
+
if (localModel instanceof core.Slot) {
|
588
|
+
return this.createSharedSlotByLocalSlot(localModel);
|
589
|
+
}
|
590
|
+
if (Array.isArray(localModel)) {
|
591
|
+
return this.createSharedArrayByLocalArray(localModel);
|
592
|
+
}
|
593
|
+
if (typeof localModel === 'object' && localModel !== null) {
|
594
|
+
return this.createSharedMapByLocalMap(localModel);
|
595
|
+
}
|
596
|
+
return localModel;
|
597
|
+
}
|
598
|
+
createLocalModelBySharedByModel(sharedModel) {
|
599
|
+
if (sharedModel instanceof yjs.Map) {
|
600
|
+
return this.createLocalMapBySharedMap(sharedModel);
|
601
|
+
}
|
602
|
+
if (sharedModel instanceof yjs.Array) {
|
603
|
+
return this.createLocalArrayBySharedArray(sharedModel);
|
604
|
+
}
|
605
|
+
if (sharedModel instanceof yjs.Text) {
|
606
|
+
return this.createLocalSlotBySharedSlot(sharedModel);
|
607
|
+
}
|
608
|
+
return sharedModel;
|
609
|
+
}
|
642
610
|
createSharedComponentByLocalComponent(component) {
|
643
611
|
const sharedComponent = new yjs.Map();
|
644
|
-
const sharedState = this.createSharedMapByLocalMap(component.state);
|
645
612
|
sharedComponent.set('name', component.name);
|
613
|
+
if (component instanceof core.AsyncComponent) {
|
614
|
+
sharedComponent.set('type', 'async');
|
615
|
+
sharedComponent.set('metadata', component.getMetadata());
|
616
|
+
const state = component.state;
|
617
|
+
let isDestroyed = false;
|
618
|
+
state.__changeMarker__.destroyCallbacks.push(() => {
|
619
|
+
isDestroyed = true;
|
620
|
+
});
|
621
|
+
this.subModelLoader.createSubModelByComponent(component).then(subDocument => {
|
622
|
+
if (isDestroyed) {
|
623
|
+
return;
|
624
|
+
}
|
625
|
+
const state = subDocument.getMap('state');
|
626
|
+
this.syncComponent(subDocument, state, component);
|
627
|
+
this.addSubModelEvent.next({
|
628
|
+
yType: state,
|
629
|
+
yDoc: subDocument
|
630
|
+
});
|
631
|
+
component.loader.markAsLoaded();
|
632
|
+
});
|
633
|
+
return sharedComponent;
|
634
|
+
}
|
635
|
+
const sharedState = this.createSharedMapByLocalMap(component.state);
|
646
636
|
sharedComponent.set('state', sharedState);
|
637
|
+
sharedComponent.set('type', 'sync');
|
647
638
|
return sharedComponent;
|
648
639
|
}
|
649
640
|
createLocalComponentBySharedComponent(yMap) {
|
650
641
|
const componentName = yMap.get('name');
|
651
|
-
const
|
652
|
-
|
653
|
-
|
642
|
+
const type = yMap.get('type');
|
643
|
+
let instance;
|
644
|
+
if (type === 'async') {
|
645
|
+
instance = this.registry.createComponentByData(componentName, {});
|
646
|
+
if (instance instanceof core.AsyncComponent) {
|
647
|
+
instance.setMetadata(yMap.get('metadata'));
|
648
|
+
const loadedSubDocument = this.subModelLoader.getLoadedModelByComponent(instance);
|
649
|
+
if (loadedSubDocument) {
|
650
|
+
const state = loadedSubDocument.getMap('state');
|
651
|
+
this.syncComponent(loadedSubDocument, state, instance);
|
652
|
+
this.addSubModelEvent.next({
|
653
|
+
yType: state,
|
654
|
+
yDoc: loadedSubDocument
|
655
|
+
});
|
656
|
+
instance.loader.markAsLoaded();
|
657
|
+
return instance;
|
658
|
+
}
|
659
|
+
const state = instance.state;
|
660
|
+
let isDestroyed = false;
|
661
|
+
instance.loader.onRequestLoad.toPromise().then(() => {
|
662
|
+
return this.subModelLoader.loadSubModelByComponent(instance);
|
663
|
+
})
|
664
|
+
.then(subDocument => {
|
665
|
+
if (isDestroyed) {
|
666
|
+
return;
|
667
|
+
}
|
668
|
+
instance.loader.markAsLoaded();
|
669
|
+
const state = subDocument.getMap('state');
|
670
|
+
this.syncComponent(subDocument, state, instance);
|
671
|
+
this.addSubModelEvent.next({
|
672
|
+
yType: state,
|
673
|
+
yDoc: subDocument
|
674
|
+
});
|
675
|
+
});
|
676
|
+
state.__changeMarker__.destroyCallbacks.push(() => {
|
677
|
+
isDestroyed = true;
|
678
|
+
});
|
679
|
+
}
|
680
|
+
else if (instance instanceof core.Component) {
|
681
|
+
throw collaborateErrorFn(`component name \`${componentName}\` is not a async component.`);
|
682
|
+
}
|
683
|
+
}
|
684
|
+
else {
|
685
|
+
const sharedState = yMap.get('state');
|
686
|
+
const state = this.createLocalMapBySharedMap(sharedState);
|
687
|
+
instance = this.registry.createComponentByData(componentName, state);
|
688
|
+
}
|
654
689
|
if (instance) {
|
655
690
|
return instance;
|
656
691
|
}
|
@@ -664,7 +699,7 @@ exports.Collaborate = class Collaborate {
|
|
664
699
|
*/
|
665
700
|
syncArray(sharedArray, localArray) {
|
666
701
|
const sub = localArray.__changeMarker__.onSelfChange.subscribe((actions) => {
|
667
|
-
this.runLocalUpdate(() => {
|
702
|
+
this.runLocalUpdate(sharedArray.doc, !localArray.__changeMarker__.irrevocableUpdate, () => {
|
668
703
|
let index = 0;
|
669
704
|
for (const action of actions) {
|
670
705
|
switch (action.type) {
|
@@ -695,7 +730,7 @@ exports.Collaborate = class Collaborate {
|
|
695
730
|
break;
|
696
731
|
}
|
697
732
|
}
|
698
|
-
}
|
733
|
+
});
|
699
734
|
});
|
700
735
|
const syncRemote = (ev, tr) => {
|
701
736
|
this.runRemoteUpdate(tr, () => {
|
@@ -745,7 +780,7 @@ exports.Collaborate = class Collaborate {
|
|
745
780
|
};
|
746
781
|
sharedObject.observe(syncRemote);
|
747
782
|
const sub = localObject.__changeMarker__.onSelfChange.subscribe((actions) => {
|
748
|
-
this.runLocalUpdate(() => {
|
783
|
+
this.runLocalUpdate(sharedObject.doc, !localObject.__changeMarker__.irrevocableUpdate, () => {
|
749
784
|
for (const action of actions) {
|
750
785
|
switch (action.type) {
|
751
786
|
case 'propSet':
|
@@ -756,28 +791,33 @@ exports.Collaborate = class Collaborate {
|
|
756
791
|
break;
|
757
792
|
}
|
758
793
|
}
|
759
|
-
}
|
794
|
+
});
|
760
795
|
});
|
761
796
|
localObject.__changeMarker__.destroyCallbacks.push(function () {
|
762
797
|
sharedObject.unobserve(syncRemote);
|
763
798
|
sub.unsubscribe();
|
764
799
|
});
|
765
800
|
}
|
766
|
-
runLocalUpdate(
|
767
|
-
if (this.updateFromRemote) {
|
801
|
+
runLocalUpdate(yDoc, record, fn) {
|
802
|
+
if (this.updateFromRemote || !yDoc) {
|
768
803
|
return;
|
769
804
|
}
|
770
|
-
this.updateRemoteActions.
|
805
|
+
let changeList = this.updateRemoteActions.get(yDoc);
|
806
|
+
if (!changeList) {
|
807
|
+
changeList = [];
|
808
|
+
this.updateRemoteActions.set(yDoc, changeList);
|
809
|
+
}
|
810
|
+
changeList.push({
|
771
811
|
record,
|
772
812
|
action: fn
|
773
813
|
});
|
774
814
|
}
|
775
815
|
runRemoteUpdate(tr, fn) {
|
776
|
-
if (tr.origin ===
|
816
|
+
if (tr.origin === tr.doc) {
|
777
817
|
return;
|
778
818
|
}
|
779
819
|
this.updateFromRemote = true;
|
780
|
-
if (tr.origin
|
820
|
+
if (tr.origin instanceof yjs.UndoManager) {
|
781
821
|
this.scheduler.historyApplyTransact(fn);
|
782
822
|
}
|
783
823
|
else {
|
@@ -788,13 +828,10 @@ exports.Collaborate = class Collaborate {
|
|
788
828
|
};
|
789
829
|
exports.Collaborate = __decorate([
|
790
830
|
core$1.Injectable(),
|
791
|
-
|
792
|
-
__param(5, core$1.Optional()),
|
793
|
-
__metadata("design:paramtypes", [Number, core.RootComponentRef,
|
794
|
-
core.Scheduler,
|
831
|
+
__metadata("design:paramtypes", [core.Scheduler,
|
795
832
|
core.Registry,
|
796
833
|
core.Selection,
|
797
|
-
|
834
|
+
SubModelLoader])
|
798
835
|
], exports.Collaborate);
|
799
836
|
function remoteFormatsToLocal(registry, attrs) {
|
800
837
|
const formats = [];
|
@@ -809,6 +846,182 @@ function remoteFormatsToLocal(registry, attrs) {
|
|
809
846
|
return formats;
|
810
847
|
}
|
811
848
|
|
849
|
+
class CustomUndoManagerConfig {
|
850
|
+
}
|
851
|
+
const collabHistoryErrorFn = core.makeError('CollabHistory');
|
852
|
+
exports.CollabHistory = class CollabHistory {
|
853
|
+
get canBack() {
|
854
|
+
var _a;
|
855
|
+
return ((_a = this.manager) === null || _a === void 0 ? void 0 : _a.canUndo()) || false;
|
856
|
+
}
|
857
|
+
get canForward() {
|
858
|
+
var _a;
|
859
|
+
return ((_a = this.manager) === null || _a === void 0 ? void 0 : _a.canRedo()) || false;
|
860
|
+
}
|
861
|
+
constructor(rootComponentRef, collaborate, scheduler, selection, stackSize, undoManagerConfig) {
|
862
|
+
this.rootComponentRef = rootComponentRef;
|
863
|
+
this.collaborate = collaborate;
|
864
|
+
this.scheduler = scheduler;
|
865
|
+
this.selection = selection;
|
866
|
+
this.stackSize = stackSize;
|
867
|
+
this.undoManagerConfig = undoManagerConfig;
|
868
|
+
this.manager = null;
|
869
|
+
this.historyItems = [];
|
870
|
+
this.index = 0;
|
871
|
+
this.subscriptions = [];
|
872
|
+
this.backEvent = new stream.Subject();
|
873
|
+
this.forwardEvent = new stream.Subject();
|
874
|
+
this.changeEvent = new stream.Subject();
|
875
|
+
this.pushEvent = new stream.Subject();
|
876
|
+
this.onBack = this.backEvent.asObservable();
|
877
|
+
this.onForward = this.forwardEvent.asObservable();
|
878
|
+
this.onChange = this.changeEvent.asObservable();
|
879
|
+
this.onPush = this.pushEvent.asObservable();
|
880
|
+
}
|
881
|
+
listen() {
|
882
|
+
const root = this.collaborate.yDoc.getMap('RootComponent');
|
883
|
+
const rootComponent = this.rootComponentRef.component;
|
884
|
+
this.collaborate.syncRootComponent(this.collaborate.yDoc, root, rootComponent);
|
885
|
+
const undoManagerConfig = this.undoManagerConfig || {};
|
886
|
+
const manager = new yjs.UndoManager(root, {
|
887
|
+
trackedOrigins: new Set([this.collaborate.yDoc]),
|
888
|
+
captureTransaction(arg) {
|
889
|
+
if (undoManagerConfig.captureTransaction) {
|
890
|
+
return undoManagerConfig.captureTransaction(arg);
|
891
|
+
}
|
892
|
+
return true;
|
893
|
+
},
|
894
|
+
deleteFilter(item) {
|
895
|
+
if (undoManagerConfig.deleteFilter) {
|
896
|
+
return undoManagerConfig.deleteFilter(item);
|
897
|
+
}
|
898
|
+
return true;
|
899
|
+
}
|
900
|
+
});
|
901
|
+
this.manager = manager;
|
902
|
+
let beforePosition = null;
|
903
|
+
this.subscriptions.push(this.scheduler.onLocalChangeBefore.subscribe(() => {
|
904
|
+
beforePosition = this.getRelativeCursorLocation();
|
905
|
+
}), this.collaborate.onAddSubModel.subscribe(() => {
|
906
|
+
throw collabHistoryErrorFn('single document does not support submodels.');
|
907
|
+
}));
|
908
|
+
manager.on('stack-item-added', (event) => {
|
909
|
+
if (event.type === 'undo') {
|
910
|
+
if (event.origin === manager) {
|
911
|
+
this.index++;
|
912
|
+
}
|
913
|
+
else {
|
914
|
+
this.historyItems.length = this.index;
|
915
|
+
this.historyItems.push({
|
916
|
+
before: beforePosition,
|
917
|
+
after: this.getRelativeCursorLocation()
|
918
|
+
});
|
919
|
+
this.index++;
|
920
|
+
}
|
921
|
+
}
|
922
|
+
else {
|
923
|
+
this.index--;
|
924
|
+
}
|
925
|
+
if (manager.undoStack.length > this.stackSize) {
|
926
|
+
this.historyItems.shift();
|
927
|
+
manager.undoStack.shift();
|
928
|
+
}
|
929
|
+
if (event.origin === this.collaborate.yDoc) {
|
930
|
+
this.pushEvent.next();
|
931
|
+
}
|
932
|
+
this.changeEvent.next();
|
933
|
+
});
|
934
|
+
manager.on('stack-item-popped', (ev) => {
|
935
|
+
const index = ev.type === 'undo' ? this.index : this.index - 1;
|
936
|
+
const position = this.historyItems[index] || null;
|
937
|
+
const p = ev.type === 'undo' ? position === null || position === void 0 ? void 0 : position.before : position === null || position === void 0 ? void 0 : position.after;
|
938
|
+
if (p) {
|
939
|
+
const selection = this.getAbstractSelection(p);
|
940
|
+
if (selection) {
|
941
|
+
this.selection.setBaseAndExtent(selection.anchorSlot, selection.anchorOffset, selection.focusSlot, selection.focusOffset);
|
942
|
+
return;
|
943
|
+
}
|
944
|
+
}
|
945
|
+
this.selection.unSelect();
|
946
|
+
});
|
947
|
+
}
|
948
|
+
back() {
|
949
|
+
var _a;
|
950
|
+
if (this.canBack) {
|
951
|
+
(_a = this.manager) === null || _a === void 0 ? void 0 : _a.undo();
|
952
|
+
this.backEvent.next();
|
953
|
+
}
|
954
|
+
}
|
955
|
+
forward() {
|
956
|
+
var _a;
|
957
|
+
if (this.canForward) {
|
958
|
+
(_a = this.manager) === null || _a === void 0 ? void 0 : _a.redo();
|
959
|
+
this.forwardEvent.next();
|
960
|
+
}
|
961
|
+
}
|
962
|
+
clear() {
|
963
|
+
var _a;
|
964
|
+
const last = this.historyItems.pop();
|
965
|
+
this.historyItems = last ? [last] : [];
|
966
|
+
this.index = last ? 1 : 0;
|
967
|
+
(_a = this.manager) === null || _a === void 0 ? void 0 : _a.clear();
|
968
|
+
this.changeEvent.next();
|
969
|
+
}
|
970
|
+
destroy() {
|
971
|
+
var _a;
|
972
|
+
this.index = 0;
|
973
|
+
this.historyItems = [];
|
974
|
+
this.subscriptions.forEach(i => i.unsubscribe());
|
975
|
+
(_a = this.manager) === null || _a === void 0 ? void 0 : _a.destroy();
|
976
|
+
}
|
977
|
+
getAbstractSelection(position) {
|
978
|
+
const anchorPosition = yjs.createAbsolutePositionFromRelativePosition(position.anchor, this.collaborate.yDoc);
|
979
|
+
const focusPosition = yjs.createAbsolutePositionFromRelativePosition(position.focus, this.collaborate.yDoc);
|
980
|
+
if (anchorPosition && focusPosition) {
|
981
|
+
const focusSlot = this.collaborate.slotMap.get(focusPosition.type);
|
982
|
+
const anchorSlot = this.collaborate.slotMap.get(anchorPosition.type);
|
983
|
+
if (focusSlot && anchorSlot) {
|
984
|
+
return {
|
985
|
+
anchorSlot,
|
986
|
+
anchorOffset: anchorPosition.index,
|
987
|
+
focusSlot,
|
988
|
+
focusOffset: focusPosition.index
|
989
|
+
};
|
990
|
+
}
|
991
|
+
}
|
992
|
+
return null;
|
993
|
+
}
|
994
|
+
getRelativeCursorLocation() {
|
995
|
+
const { anchorSlot, anchorOffset, focusSlot, focusOffset } = this.selection;
|
996
|
+
if (anchorSlot) {
|
997
|
+
const anchorYText = this.collaborate.slotMap.get(anchorSlot);
|
998
|
+
if (anchorYText) {
|
999
|
+
const anchorPosition = yjs.createRelativePositionFromTypeIndex(anchorYText, anchorOffset);
|
1000
|
+
if (focusSlot) {
|
1001
|
+
const focusYText = this.collaborate.slotMap.get(focusSlot);
|
1002
|
+
if (focusYText) {
|
1003
|
+
const focusPosition = yjs.createRelativePositionFromTypeIndex(focusYText, focusOffset);
|
1004
|
+
return {
|
1005
|
+
focus: focusPosition,
|
1006
|
+
anchor: anchorPosition
|
1007
|
+
};
|
1008
|
+
}
|
1009
|
+
}
|
1010
|
+
}
|
1011
|
+
}
|
1012
|
+
return null;
|
1013
|
+
}
|
1014
|
+
};
|
1015
|
+
exports.CollabHistory = __decorate([
|
1016
|
+
core$1.Injectable(),
|
1017
|
+
__param(4, core$1.Inject(core.HISTORY_STACK_SIZE)),
|
1018
|
+
__param(5, core$1.Optional()),
|
1019
|
+
__metadata("design:paramtypes", [core.RootComponentRef,
|
1020
|
+
exports.Collaborate,
|
1021
|
+
core.Scheduler,
|
1022
|
+
core.Selection, Number, CustomUndoManagerConfig])
|
1023
|
+
], exports.CollabHistory);
|
1024
|
+
|
812
1025
|
exports.UserActivity = class UserActivity {
|
813
1026
|
constructor(syncConnector, selection) {
|
814
1027
|
this.syncConnector = syncConnector;
|
@@ -857,15 +1070,219 @@ class CollaborateModule {
|
|
857
1070
|
this.providers = [
|
858
1071
|
exports.Collaborate,
|
859
1072
|
exports.UserActivity,
|
1073
|
+
exports.CollabHistory,
|
1074
|
+
{
|
1075
|
+
provide: core.History,
|
1076
|
+
useExisting: exports.CollabHistory
|
1077
|
+
}, {
|
1078
|
+
provide: SyncConnector,
|
1079
|
+
useFactory: (collab) => {
|
1080
|
+
return this.config.createConnector(collab.yDoc);
|
1081
|
+
},
|
1082
|
+
deps: [exports.Collaborate]
|
1083
|
+
}, {
|
1084
|
+
provide: SubModelLoader,
|
1085
|
+
useClass: exports.NonSubModelLoader
|
1086
|
+
}
|
1087
|
+
];
|
1088
|
+
}
|
1089
|
+
setup(textbus) {
|
1090
|
+
const connector = textbus.get(SyncConnector);
|
1091
|
+
const userActivity = textbus.get(exports.UserActivity);
|
1092
|
+
userActivity.init(this.config.userinfo);
|
1093
|
+
return connector.onLoad.toPromise();
|
1094
|
+
}
|
1095
|
+
onDestroy(textbus) {
|
1096
|
+
textbus.get(exports.Collaborate).destroy();
|
1097
|
+
textbus.get(core.History).destroy();
|
1098
|
+
textbus.get(exports.UserActivity).destroy();
|
1099
|
+
textbus.get(SyncConnector).onDestroy();
|
1100
|
+
}
|
1101
|
+
}
|
1102
|
+
|
1103
|
+
exports.MultipleDocCollabHistory = class MultipleDocCollabHistory {
|
1104
|
+
get canBack() {
|
1105
|
+
return this.actionStack.length > 0 && this.index > 0;
|
1106
|
+
}
|
1107
|
+
get canForward() {
|
1108
|
+
return this.actionStack.length > 0 && this.index < this.actionStack.length;
|
1109
|
+
}
|
1110
|
+
constructor(collaborate, rootComponentRef, stackSize, undoManagerConfig) {
|
1111
|
+
this.collaborate = collaborate;
|
1112
|
+
this.rootComponentRef = rootComponentRef;
|
1113
|
+
this.stackSize = stackSize;
|
1114
|
+
this.undoManagerConfig = undoManagerConfig;
|
1115
|
+
this.isListen = false;
|
1116
|
+
this.changeEvent = new stream.Subject();
|
1117
|
+
this.backEvent = new stream.Subject();
|
1118
|
+
this.forwardEvent = new stream.Subject();
|
1119
|
+
this.pushEvent = new stream.Subject();
|
1120
|
+
this.actionStack = [];
|
1121
|
+
this.index = 0;
|
1122
|
+
this.stackItem = null;
|
1123
|
+
this.timer = null;
|
1124
|
+
this.subscription = new stream.Subscription();
|
1125
|
+
this.subDocs = new Set();
|
1126
|
+
this.listenerCaches = new Set();
|
1127
|
+
this.onChange = this.changeEvent.asObservable();
|
1128
|
+
this.onBack = this.backEvent.asObservable();
|
1129
|
+
this.onForward = this.forwardEvent.asObservable();
|
1130
|
+
this.onPush = this.pushEvent.asObservable();
|
1131
|
+
}
|
1132
|
+
listen() {
|
1133
|
+
this.isListen = true;
|
1134
|
+
const root = this.collaborate.yDoc.getMap('RootComponent');
|
1135
|
+
const rootComponent = this.rootComponentRef.component;
|
1136
|
+
this.collaborate.syncRootComponent(this.collaborate.yDoc, root, rootComponent);
|
1137
|
+
this.listenItem(root, this.collaborate.yDoc);
|
1138
|
+
this.subscription.add(this.collaborate.onAddSubModel.subscribe(({ yType, yDoc }) => {
|
1139
|
+
if (this.subDocs.has(yType)) {
|
1140
|
+
return;
|
1141
|
+
}
|
1142
|
+
this.subDocs.add(yType);
|
1143
|
+
if (this.isListen) {
|
1144
|
+
this.listenItem(yType, yDoc);
|
1145
|
+
}
|
1146
|
+
}));
|
1147
|
+
}
|
1148
|
+
forward() {
|
1149
|
+
if (!this.canForward) {
|
1150
|
+
return;
|
1151
|
+
}
|
1152
|
+
clearTimeout(this.timer);
|
1153
|
+
const item = this.actionStack[this.index];
|
1154
|
+
if (item) {
|
1155
|
+
for (const i of item) {
|
1156
|
+
i.redo();
|
1157
|
+
}
|
1158
|
+
}
|
1159
|
+
this.index++;
|
1160
|
+
this.forwardEvent.next();
|
1161
|
+
this.changeEvent.next();
|
1162
|
+
}
|
1163
|
+
back() {
|
1164
|
+
if (!this.canBack) {
|
1165
|
+
return;
|
1166
|
+
}
|
1167
|
+
clearTimeout(this.timer);
|
1168
|
+
let actions;
|
1169
|
+
if (this.stackItem) {
|
1170
|
+
actions = this.stackItem;
|
1171
|
+
this.stackItem = null;
|
1172
|
+
}
|
1173
|
+
else {
|
1174
|
+
this.index--;
|
1175
|
+
actions = this.actionStack[this.index];
|
1176
|
+
}
|
1177
|
+
let len = actions.length;
|
1178
|
+
while (len > 0) {
|
1179
|
+
len--;
|
1180
|
+
actions[len].undo();
|
1181
|
+
}
|
1182
|
+
if (actions) {
|
1183
|
+
this.backEvent.next();
|
1184
|
+
this.changeEvent.next();
|
1185
|
+
}
|
1186
|
+
}
|
1187
|
+
clear() {
|
1188
|
+
this.actionStack = [];
|
1189
|
+
this.stackItem = [];
|
1190
|
+
this.index = 0;
|
1191
|
+
clearTimeout(this.timer);
|
1192
|
+
this.listenerCaches.forEach((undoManager) => {
|
1193
|
+
undoManager.clear();
|
1194
|
+
});
|
1195
|
+
this.changeEvent.next();
|
1196
|
+
}
|
1197
|
+
destroy() {
|
1198
|
+
this.clear();
|
1199
|
+
this.subscription.unsubscribe();
|
1200
|
+
this.listenerCaches.forEach((undoManager) => {
|
1201
|
+
undoManager.destroy();
|
1202
|
+
});
|
1203
|
+
this.subDocs.clear();
|
1204
|
+
this.listenerCaches.clear();
|
1205
|
+
}
|
1206
|
+
listenItem(yType, yDoc) {
|
1207
|
+
const undoManagerConfig = this.undoManagerConfig || {};
|
1208
|
+
const undoManager = new yjs.UndoManager(yType, {
|
1209
|
+
trackedOrigins: new Set([yDoc]),
|
1210
|
+
captureTimeout: 0,
|
1211
|
+
captureTransaction(arg) {
|
1212
|
+
if (undoManagerConfig.captureTransaction) {
|
1213
|
+
return undoManagerConfig.captureTransaction(arg);
|
1214
|
+
}
|
1215
|
+
return true;
|
1216
|
+
},
|
1217
|
+
deleteFilter(item) {
|
1218
|
+
if (undoManagerConfig.deleteFilter) {
|
1219
|
+
return undoManagerConfig.deleteFilter(item);
|
1220
|
+
}
|
1221
|
+
return true;
|
1222
|
+
}
|
1223
|
+
});
|
1224
|
+
undoManager.on('stack-item-added', (event) => {
|
1225
|
+
if (event.type === 'undo' && !(event.origin instanceof yjs.UndoManager)) {
|
1226
|
+
if (this.index != this.actionStack.length) {
|
1227
|
+
const redoStack = this.actionStack.slice(this.index);
|
1228
|
+
redoStack.forEach(item => {
|
1229
|
+
item.forEach(i => {
|
1230
|
+
i.clear(false, true);
|
1231
|
+
});
|
1232
|
+
});
|
1233
|
+
this.actionStack.length = this.index;
|
1234
|
+
this.changeEvent.next();
|
1235
|
+
}
|
1236
|
+
if (this.stackItem === null) {
|
1237
|
+
this.stackItem = [];
|
1238
|
+
this.timer = setTimeout(() => {
|
1239
|
+
if (this.actionStack.length >= this.stackSize) {
|
1240
|
+
this.actionStack.shift();
|
1241
|
+
}
|
1242
|
+
else {
|
1243
|
+
this.index++;
|
1244
|
+
}
|
1245
|
+
this.actionStack.push(this.stackItem);
|
1246
|
+
this.stackItem = null;
|
1247
|
+
this.pushEvent.next();
|
1248
|
+
this.changeEvent.next();
|
1249
|
+
}, 500);
|
1250
|
+
}
|
1251
|
+
this.stackItem.push(undoManager);
|
1252
|
+
}
|
1253
|
+
});
|
1254
|
+
this.listenerCaches.add(undoManager);
|
1255
|
+
}
|
1256
|
+
};
|
1257
|
+
exports.MultipleDocCollabHistory = __decorate([
|
1258
|
+
core$1.Injectable(),
|
1259
|
+
__param(2, core$1.Inject(core.HISTORY_STACK_SIZE)),
|
1260
|
+
__param(3, core$1.Optional()),
|
1261
|
+
__metadata("design:paramtypes", [exports.Collaborate,
|
1262
|
+
core.RootComponentRef, Number, CustomUndoManagerConfig])
|
1263
|
+
], exports.MultipleDocCollabHistory);
|
1264
|
+
|
1265
|
+
class MultipleDocumentCollaborateModule {
|
1266
|
+
constructor(config) {
|
1267
|
+
this.config = config;
|
1268
|
+
this.providers = [
|
1269
|
+
exports.Collaborate,
|
1270
|
+
exports.UserActivity,
|
1271
|
+
exports.MultipleDocCollabHistory,
|
860
1272
|
{
|
861
1273
|
provide: core.History,
|
862
|
-
useExisting: exports.
|
1274
|
+
useExisting: exports.MultipleDocCollabHistory
|
863
1275
|
}, {
|
864
1276
|
provide: SyncConnector,
|
865
1277
|
useFactory: (collab) => {
|
866
1278
|
return this.config.createConnector(collab.yDoc);
|
867
1279
|
},
|
868
1280
|
deps: [exports.Collaborate]
|
1281
|
+
}, {
|
1282
|
+
provide: SubModelLoader,
|
1283
|
+
useFactory: () => {
|
1284
|
+
return this.config.subModelLoader;
|
1285
|
+
}
|
869
1286
|
}
|
870
1287
|
];
|
871
1288
|
}
|
@@ -876,6 +1293,8 @@ class CollaborateModule {
|
|
876
1293
|
return connector.onLoad.toPromise();
|
877
1294
|
}
|
878
1295
|
onDestroy(textbus) {
|
1296
|
+
textbus.get(exports.Collaborate).destroy();
|
1297
|
+
textbus.get(core.History).destroy();
|
879
1298
|
textbus.get(exports.UserActivity).destroy();
|
880
1299
|
textbus.get(SyncConnector).onDestroy();
|
881
1300
|
}
|
@@ -884,5 +1303,7 @@ class CollaborateModule {
|
|
884
1303
|
exports.CollaborateModule = CollaborateModule;
|
885
1304
|
exports.CustomUndoManagerConfig = CustomUndoManagerConfig;
|
886
1305
|
exports.HocuspocusConnector = HocuspocusConnector;
|
1306
|
+
exports.MultipleDocumentCollaborateModule = MultipleDocumentCollaborateModule;
|
1307
|
+
exports.SubModelLoader = SubModelLoader;
|
887
1308
|
exports.SyncConnector = SyncConnector;
|
888
1309
|
exports.YWebsocketConnector = YWebsocketConnector;
|