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