@textbus/collaborate 4.0.4 → 4.1.0-alpha.1
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 +36 -0
- package/bundles/collaborate.d.ts +44 -35
- package/bundles/connectors/hocuspocus-connector.d.ts +2 -1
- package/bundles/connectors/y-websocket-connector.d.ts +2 -1
- package/bundles/index.esm.js +765 -317
- package/bundles/index.js +764 -314
- package/bundles/multiple-doc-collab-history.d.ts +37 -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 +3 -3
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,96 @@ 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
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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();
|
|
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
|
+
yDoc.transact(() => {
|
|
215
|
+
this.initSharedSlotByLocalSlot(sharedSlot, localSlot);
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
this.initSyncEvent(yDoc);
|
|
219
|
+
this.syncSlot(sharedSlot, localSlot);
|
|
220
|
+
}
|
|
221
|
+
getAbstractSelection(position) {
|
|
222
|
+
const anchorPosition = yjs.createAbsolutePositionFromRelativePosition(position.anchor.position, position.anchor.doc);
|
|
223
|
+
const focusPosition = yjs.createAbsolutePositionFromRelativePosition(position.focus.position, position.focus.doc);
|
|
224
|
+
if (anchorPosition && focusPosition) {
|
|
225
|
+
const focusSlot = this.slotMap.get(focusPosition.type);
|
|
226
|
+
const anchorSlot = this.slotMap.get(anchorPosition.type);
|
|
227
|
+
if (focusSlot && anchorSlot) {
|
|
228
|
+
return {
|
|
229
|
+
anchorSlot,
|
|
230
|
+
anchorOffset: anchorPosition.index,
|
|
231
|
+
focusSlot,
|
|
232
|
+
focusOffset: focusPosition.index
|
|
233
|
+
};
|
|
242
234
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
235
|
+
}
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
getRelativeCursorLocation() {
|
|
239
|
+
const { anchorSlot, anchorOffset, focusSlot, focusOffset } = this.selection;
|
|
240
|
+
if (anchorSlot) {
|
|
241
|
+
const anchorYText = this.slotMap.get(anchorSlot);
|
|
242
|
+
if (anchorYText) {
|
|
243
|
+
const anchorPosition = yjs.createRelativePositionFromTypeIndex(anchorYText, anchorOffset);
|
|
244
|
+
if (focusSlot) {
|
|
245
|
+
const focusYText = this.slotMap.get(focusSlot);
|
|
246
|
+
if (focusYText) {
|
|
247
|
+
const focusPosition = yjs.createRelativePositionFromTypeIndex(focusYText, focusOffset);
|
|
248
|
+
return {
|
|
249
|
+
focus: {
|
|
250
|
+
doc: focusYText.doc,
|
|
251
|
+
position: focusPosition
|
|
252
|
+
},
|
|
253
|
+
anchor: {
|
|
254
|
+
doc: anchorYText.doc,
|
|
255
|
+
position: anchorPosition
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
}
|
|
254
259
|
}
|
|
255
260
|
}
|
|
261
|
+
}
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
restoreCursorPosition(position) {
|
|
265
|
+
if (!position) {
|
|
256
266
|
this.selection.unSelect();
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const selection = this.getAbstractSelection(position);
|
|
270
|
+
if (selection) {
|
|
271
|
+
this.selection.setBaseAndExtent(selection.anchorSlot, selection.anchorOffset, selection.focusSlot, selection.focusOffset);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
initSyncEvent(yDoc) {
|
|
275
|
+
this.subscriptions.push(this.scheduler.onDocChanged.pipe(stream.map(item => {
|
|
262
276
|
return item.filter(i => {
|
|
263
277
|
return i.from !== core.ChangeOrigin.Remote;
|
|
264
278
|
});
|
|
@@ -267,7 +281,8 @@ exports.Collaborate = class Collaborate {
|
|
|
267
281
|
})).subscribe(() => {
|
|
268
282
|
const updates = [];
|
|
269
283
|
let update = null;
|
|
270
|
-
|
|
284
|
+
const updateRemoteActions = this.updateRemoteActions.get(yDoc) || [];
|
|
285
|
+
for (const item of updateRemoteActions) {
|
|
271
286
|
if (!update) {
|
|
272
287
|
update = {
|
|
273
288
|
record: item.record,
|
|
@@ -286,218 +301,32 @@ exports.Collaborate = class Collaborate {
|
|
|
286
301
|
updates.push(update);
|
|
287
302
|
}
|
|
288
303
|
}
|
|
289
|
-
this.updateRemoteActions
|
|
304
|
+
this.updateRemoteActions.delete(yDoc);
|
|
290
305
|
for (const item of updates) {
|
|
291
|
-
|
|
306
|
+
yDoc.transact(() => {
|
|
292
307
|
item.actions.forEach(fn => {
|
|
293
308
|
fn();
|
|
294
309
|
});
|
|
295
|
-
}, item.record ?
|
|
310
|
+
}, item.record ? yDoc : this.noRecord);
|
|
296
311
|
}
|
|
297
|
-
this.localChangesAppliedEvent.next();
|
|
298
312
|
}));
|
|
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
313
|
}
|
|
315
|
-
|
|
316
|
-
|
|
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
|
-
}
|
|
330
|
-
syncRootComponent(root, rootComponent) {
|
|
331
|
-
let state = root.get('state');
|
|
314
|
+
syncComponent(yDoc, sharedComponent, localComponent) {
|
|
315
|
+
let state = sharedComponent.get('state');
|
|
332
316
|
if (!state) {
|
|
333
317
|
state = new yjs.Map();
|
|
334
|
-
this.syncLocalMapToSharedMap(
|
|
335
|
-
|
|
336
|
-
|
|
318
|
+
this.syncLocalMapToSharedMap(localComponent.state, state);
|
|
319
|
+
yDoc.transact(() => {
|
|
320
|
+
sharedComponent.set('state', state);
|
|
337
321
|
});
|
|
338
322
|
}
|
|
339
323
|
else {
|
|
340
|
-
Object.keys(
|
|
341
|
-
Reflect.deleteProperty(
|
|
324
|
+
Object.keys(localComponent.state).forEach(key => {
|
|
325
|
+
Reflect.deleteProperty(localComponent.state, key);
|
|
342
326
|
});
|
|
343
|
-
this.syncSharedMapToLocalMap(state,
|
|
327
|
+
this.syncSharedMapToLocalMap(state, localComponent.state);
|
|
344
328
|
}
|
|
345
329
|
}
|
|
346
|
-
syncSharedMapToLocalMap(sharedMap, localMap) {
|
|
347
|
-
sharedMap.forEach((value, key) => {
|
|
348
|
-
localMap[key] = this.createLocalModelBySharedByModel(value);
|
|
349
|
-
});
|
|
350
|
-
this.syncObject(sharedMap, localMap);
|
|
351
|
-
}
|
|
352
|
-
createLocalMapBySharedMap(sharedMap) {
|
|
353
|
-
const localMap = core.createObjectProxy({});
|
|
354
|
-
this.syncSharedMapToLocalMap(sharedMap, localMap);
|
|
355
|
-
return localMap;
|
|
356
|
-
}
|
|
357
|
-
createLocalArrayBySharedArray(sharedArray) {
|
|
358
|
-
const localArray = core.createArrayProxy([]);
|
|
359
|
-
localArray.push(...sharedArray.map(item => this.createLocalModelBySharedByModel(item)));
|
|
360
|
-
this.syncArray(sharedArray, localArray);
|
|
361
|
-
return localArray;
|
|
362
|
-
}
|
|
363
|
-
syncLocalMapToSharedMap(localMap, sharedMap) {
|
|
364
|
-
Object.entries(localMap).forEach(([key, value]) => {
|
|
365
|
-
sharedMap.set(key, this.createSharedModelByLocalModel(value));
|
|
366
|
-
});
|
|
367
|
-
this.syncObject(sharedMap, localMap);
|
|
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
330
|
syncSlot(sharedSlot, localSlot) {
|
|
502
331
|
const syncRemote = (ev, tr) => {
|
|
503
332
|
this.runRemoteUpdate(tr, () => {
|
|
@@ -546,7 +375,7 @@ exports.Collaborate = class Collaborate {
|
|
|
546
375
|
const component = this.createLocalComponentBySharedComponent(sharedComponent);
|
|
547
376
|
localSlot.insert(component);
|
|
548
377
|
}
|
|
549
|
-
if (this.selection.isSelected && tr.origin
|
|
378
|
+
if (this.selection.isSelected && !(tr.origin instanceof yjs.UndoManager)) {
|
|
550
379
|
if (localSlot === this.selection.anchorSlot && this.selection.anchorOffset > index) {
|
|
551
380
|
this.selection.setAnchor(localSlot, this.selection.anchorOffset + length);
|
|
552
381
|
}
|
|
@@ -558,7 +387,7 @@ exports.Collaborate = class Collaborate {
|
|
|
558
387
|
else if (action.delete) {
|
|
559
388
|
const index = localSlot.index;
|
|
560
389
|
localSlot.delete(action.delete);
|
|
561
|
-
if (this.selection.isSelected && tr.origin
|
|
390
|
+
if (this.selection.isSelected && !(tr.origin instanceof yjs.UndoManager)) {
|
|
562
391
|
if (localSlot === this.selection.anchorSlot && this.selection.anchorOffset >= index) {
|
|
563
392
|
this.selection.setAnchor(localSlot, this.selection.startOffset - action.delete);
|
|
564
393
|
}
|
|
@@ -572,7 +401,7 @@ exports.Collaborate = class Collaborate {
|
|
|
572
401
|
};
|
|
573
402
|
sharedSlot.observe(syncRemote);
|
|
574
403
|
const sub = localSlot.onContentChange.subscribe(actions => {
|
|
575
|
-
this.runLocalUpdate(() => {
|
|
404
|
+
this.runLocalUpdate(sharedSlot.doc, true, () => {
|
|
576
405
|
var _a;
|
|
577
406
|
let offset = 0;
|
|
578
407
|
let length = 0;
|
|
@@ -630,7 +459,7 @@ exports.Collaborate = class Collaborate {
|
|
|
630
459
|
sharedSlot.removeAttribute(action.name);
|
|
631
460
|
}
|
|
632
461
|
}
|
|
633
|
-
}
|
|
462
|
+
});
|
|
634
463
|
});
|
|
635
464
|
this.slotMap.set(localSlot, sharedSlot);
|
|
636
465
|
localSlot.__changeMarker__.destroyCallbacks.push(() => {
|
|
@@ -639,18 +468,281 @@ exports.Collaborate = class Collaborate {
|
|
|
639
468
|
sub.unsubscribe();
|
|
640
469
|
});
|
|
641
470
|
}
|
|
471
|
+
destroy() {
|
|
472
|
+
this.subscriptions.forEach(i => i.unsubscribe());
|
|
473
|
+
}
|
|
474
|
+
syncSharedMapToLocalMap(sharedMap, localMap) {
|
|
475
|
+
sharedMap.forEach((value, key) => {
|
|
476
|
+
localMap[key] = this.createLocalModelBySharedByModel(value);
|
|
477
|
+
});
|
|
478
|
+
this.syncObject(sharedMap, localMap);
|
|
479
|
+
}
|
|
480
|
+
createLocalMapBySharedMap(sharedMap) {
|
|
481
|
+
const localMap = core.createObjectProxy({});
|
|
482
|
+
this.syncSharedMapToLocalMap(sharedMap, localMap);
|
|
483
|
+
return localMap;
|
|
484
|
+
}
|
|
485
|
+
createLocalArrayBySharedArray(sharedArray) {
|
|
486
|
+
const localArray = core.createArrayProxy([]);
|
|
487
|
+
localArray.push(...sharedArray.map(item => this.createLocalModelBySharedByModel(item)));
|
|
488
|
+
this.syncArray(sharedArray, localArray);
|
|
489
|
+
return localArray;
|
|
490
|
+
}
|
|
491
|
+
syncLocalMapToSharedMap(localMap, sharedMap) {
|
|
492
|
+
Object.entries(localMap).forEach(([key, value]) => {
|
|
493
|
+
sharedMap.set(key, this.createSharedModelByLocalModel(value));
|
|
494
|
+
});
|
|
495
|
+
this.syncObject(sharedMap, localMap);
|
|
496
|
+
}
|
|
497
|
+
createSharedMapByLocalMap(localMap) {
|
|
498
|
+
const sharedMap = new yjs.Map();
|
|
499
|
+
this.syncLocalMapToSharedMap(localMap, sharedMap);
|
|
500
|
+
return sharedMap;
|
|
501
|
+
}
|
|
502
|
+
createSharedArrayByLocalArray(localArray) {
|
|
503
|
+
const sharedArray = new yjs.Array();
|
|
504
|
+
localArray.forEach(value => {
|
|
505
|
+
sharedArray.push([this.createSharedModelByLocalModel(value)]);
|
|
506
|
+
});
|
|
507
|
+
this.syncArray(sharedArray, localArray);
|
|
508
|
+
return sharedArray;
|
|
509
|
+
}
|
|
510
|
+
createSharedSlotByLocalSlot(localSlot) {
|
|
511
|
+
const sharedSlot = new yjs.Text();
|
|
512
|
+
const isAsyncSlot = localSlot instanceof core.AsyncSlot;
|
|
513
|
+
sharedSlot.setAttribute('schema', [...localSlot.schema]);
|
|
514
|
+
sharedSlot.setAttribute('type', isAsyncSlot ? 'async' : 'sync');
|
|
515
|
+
if (isAsyncSlot) {
|
|
516
|
+
let isDestroyed = false;
|
|
517
|
+
sharedSlot.setAttribute('metadata', localSlot.metadata);
|
|
518
|
+
this.subModelLoader.createSubModelBySlot(localSlot).then(subDocument => {
|
|
519
|
+
if (isDestroyed) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
const content = subDocument.getText('content');
|
|
523
|
+
this.initSharedSlotByLocalSlot(content, localSlot);
|
|
524
|
+
this.syncSlot(content, localSlot);
|
|
525
|
+
this.addSubModelEvent.next({
|
|
526
|
+
yDoc: subDocument,
|
|
527
|
+
yType: content
|
|
528
|
+
});
|
|
529
|
+
this.initSyncEvent(subDocument);
|
|
530
|
+
localSlot.loader.markAsLoaded();
|
|
531
|
+
});
|
|
532
|
+
localSlot.__changeMarker__.destroyCallbacks.push(() => {
|
|
533
|
+
isDestroyed = true;
|
|
534
|
+
});
|
|
535
|
+
return sharedSlot;
|
|
536
|
+
}
|
|
537
|
+
const sharedContent = new yjs.Text();
|
|
538
|
+
this.initSharedSlotByLocalSlot(sharedContent, localSlot);
|
|
539
|
+
sharedSlot.insertEmbed(0, sharedContent);
|
|
540
|
+
this.syncSlot(sharedContent, localSlot);
|
|
541
|
+
return sharedSlot;
|
|
542
|
+
}
|
|
543
|
+
initSharedSlotByLocalSlot(sharedContent, localSlot) {
|
|
544
|
+
let offset = 0;
|
|
545
|
+
localSlot.toDelta().forEach(i => {
|
|
546
|
+
let formats = {};
|
|
547
|
+
if (i.formats) {
|
|
548
|
+
i.formats.forEach(item => {
|
|
549
|
+
formats[item[0].name] = item[1];
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
formats = null;
|
|
554
|
+
}
|
|
555
|
+
if (typeof i.insert === 'string') {
|
|
556
|
+
sharedContent.insert(offset, i.insert, formats);
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
const sharedComponent = this.createSharedComponentByLocalComponent(i.insert);
|
|
560
|
+
sharedContent.insertEmbed(offset, sharedComponent, formats);
|
|
561
|
+
}
|
|
562
|
+
offset += i.insert.length;
|
|
563
|
+
});
|
|
564
|
+
localSlot.getAttributes().forEach(item => {
|
|
565
|
+
sharedContent.setAttribute(item[0].name, item[1]);
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
createLocalSlotBySharedSlot(sharedSlot) {
|
|
569
|
+
var _a;
|
|
570
|
+
const type = sharedSlot.getAttribute('type');
|
|
571
|
+
const schema = sharedSlot.getAttribute('schema');
|
|
572
|
+
if (type === 'async') {
|
|
573
|
+
const metadata = sharedSlot.getAttribute('metadata');
|
|
574
|
+
const slot = new core.AsyncSlot(schema || [], metadata);
|
|
575
|
+
const loadedSubDocument = this.subModelLoader.getLoadedModelBySlot(slot);
|
|
576
|
+
if (loadedSubDocument) {
|
|
577
|
+
const subContent = loadedSubDocument.getText('content');
|
|
578
|
+
this.syncRootSlot(loadedSubDocument, subContent, slot);
|
|
579
|
+
this.addSubModelEvent.next({
|
|
580
|
+
yDoc: loadedSubDocument,
|
|
581
|
+
yType: subContent
|
|
582
|
+
});
|
|
583
|
+
slot.loader.markAsLoaded();
|
|
584
|
+
return slot;
|
|
585
|
+
}
|
|
586
|
+
let isDestroyed = false;
|
|
587
|
+
slot.loader.onRequestLoad.toPromise().then(() => {
|
|
588
|
+
return this.subModelLoader.loadSubModelBySlot(slot);
|
|
589
|
+
}).then(subDocument => {
|
|
590
|
+
if (isDestroyed) {
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
slot.loader.markAsLoaded();
|
|
594
|
+
const subContent = subDocument.getText('content');
|
|
595
|
+
this.syncRootSlot(subDocument, subContent, slot);
|
|
596
|
+
this.addSubModelEvent.next({
|
|
597
|
+
yDoc: subDocument,
|
|
598
|
+
yType: subContent
|
|
599
|
+
});
|
|
600
|
+
});
|
|
601
|
+
slot.__changeMarker__.destroyCallbacks.push(() => {
|
|
602
|
+
isDestroyed = true;
|
|
603
|
+
});
|
|
604
|
+
return slot;
|
|
605
|
+
}
|
|
606
|
+
const contentDelta = sharedSlot.toDelta();
|
|
607
|
+
const content = (_a = contentDelta[0]) === null || _a === void 0 ? void 0 : _a.insert;
|
|
608
|
+
if (!(content instanceof yjs.Text)) {
|
|
609
|
+
throw collaborateErrorFn('shared slot content type is not `YText`.');
|
|
610
|
+
}
|
|
611
|
+
const localSlot = new core.Slot(schema || []);
|
|
612
|
+
this.initLocalSlotBySharedSlot(content, localSlot);
|
|
613
|
+
this.syncSlot(content, localSlot);
|
|
614
|
+
return localSlot;
|
|
615
|
+
}
|
|
616
|
+
initLocalSlotBySharedSlot(content, localSlot) {
|
|
617
|
+
const delta = content.toDelta();
|
|
618
|
+
const attrs = content.getAttributes();
|
|
619
|
+
Object.keys(attrs).forEach(key => {
|
|
620
|
+
const attribute = this.registry.getAttribute(key);
|
|
621
|
+
if (attribute) {
|
|
622
|
+
localSlot.setAttribute(attribute, attrs[key]);
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
for (const action of delta) {
|
|
626
|
+
if (action.insert) {
|
|
627
|
+
if (typeof action.insert === 'string') {
|
|
628
|
+
const formats = remoteFormatsToLocal(this.registry, action.attributes);
|
|
629
|
+
localSlot.insert(action.insert, formats);
|
|
630
|
+
}
|
|
631
|
+
else {
|
|
632
|
+
const sharedComponent = action.insert;
|
|
633
|
+
const component = this.createLocalComponentBySharedComponent(sharedComponent);
|
|
634
|
+
localSlot.insert(component, remoteFormatsToLocal(this.registry, action.attributes));
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
throw collaborateErrorFn('unexpected delta action.');
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
createSharedModelByLocalModel(localModel) {
|
|
643
|
+
if (localModel instanceof core.Slot) {
|
|
644
|
+
return this.createSharedSlotByLocalSlot(localModel);
|
|
645
|
+
}
|
|
646
|
+
if (Array.isArray(localModel)) {
|
|
647
|
+
return this.createSharedArrayByLocalArray(localModel);
|
|
648
|
+
}
|
|
649
|
+
if (typeof localModel === 'object' && localModel !== null) {
|
|
650
|
+
return this.createSharedMapByLocalMap(localModel);
|
|
651
|
+
}
|
|
652
|
+
return localModel;
|
|
653
|
+
}
|
|
654
|
+
createLocalModelBySharedByModel(sharedModel) {
|
|
655
|
+
if (sharedModel instanceof yjs.Map) {
|
|
656
|
+
return this.createLocalMapBySharedMap(sharedModel);
|
|
657
|
+
}
|
|
658
|
+
if (sharedModel instanceof yjs.Array) {
|
|
659
|
+
return this.createLocalArrayBySharedArray(sharedModel);
|
|
660
|
+
}
|
|
661
|
+
if (sharedModel instanceof yjs.Text) {
|
|
662
|
+
return this.createLocalSlotBySharedSlot(sharedModel);
|
|
663
|
+
}
|
|
664
|
+
return sharedModel;
|
|
665
|
+
}
|
|
642
666
|
createSharedComponentByLocalComponent(component) {
|
|
643
667
|
const sharedComponent = new yjs.Map();
|
|
644
|
-
const sharedState = this.createSharedMapByLocalMap(component.state);
|
|
645
668
|
sharedComponent.set('name', component.name);
|
|
669
|
+
if (component instanceof core.AsyncComponent) {
|
|
670
|
+
sharedComponent.set('type', 'async');
|
|
671
|
+
sharedComponent.set('metadata', component.getMetadata());
|
|
672
|
+
const state = component.state;
|
|
673
|
+
let isDestroyed = false;
|
|
674
|
+
state.__changeMarker__.destroyCallbacks.push(() => {
|
|
675
|
+
isDestroyed = true;
|
|
676
|
+
});
|
|
677
|
+
this.subModelLoader.createSubModelByComponent(component).then(subDocument => {
|
|
678
|
+
if (isDestroyed) {
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
const state = subDocument.getMap('state');
|
|
682
|
+
this.syncComponent(subDocument, state, component);
|
|
683
|
+
this.addSubModelEvent.next({
|
|
684
|
+
yType: state,
|
|
685
|
+
yDoc: subDocument
|
|
686
|
+
});
|
|
687
|
+
this.initSyncEvent(subDocument);
|
|
688
|
+
component.loader.markAsLoaded();
|
|
689
|
+
});
|
|
690
|
+
return sharedComponent;
|
|
691
|
+
}
|
|
692
|
+
const sharedState = this.createSharedMapByLocalMap(component.state);
|
|
646
693
|
sharedComponent.set('state', sharedState);
|
|
694
|
+
sharedComponent.set('type', 'sync');
|
|
647
695
|
return sharedComponent;
|
|
648
696
|
}
|
|
649
697
|
createLocalComponentBySharedComponent(yMap) {
|
|
650
698
|
const componentName = yMap.get('name');
|
|
651
|
-
const
|
|
652
|
-
|
|
653
|
-
|
|
699
|
+
const type = yMap.get('type');
|
|
700
|
+
let instance;
|
|
701
|
+
if (type === 'async') {
|
|
702
|
+
instance = this.registry.createComponentByData(componentName, {});
|
|
703
|
+
if (instance instanceof core.AsyncComponent) {
|
|
704
|
+
instance.setMetadata(yMap.get('metadata'));
|
|
705
|
+
const loadedSubDocument = this.subModelLoader.getLoadedModelByComponent(instance);
|
|
706
|
+
if (loadedSubDocument) {
|
|
707
|
+
const state = loadedSubDocument.getMap('state');
|
|
708
|
+
this.syncComponent(loadedSubDocument, state, instance);
|
|
709
|
+
this.addSubModelEvent.next({
|
|
710
|
+
yType: state,
|
|
711
|
+
yDoc: loadedSubDocument
|
|
712
|
+
});
|
|
713
|
+
instance.loader.markAsLoaded();
|
|
714
|
+
return instance;
|
|
715
|
+
}
|
|
716
|
+
const state = instance.state;
|
|
717
|
+
let isDestroyed = false;
|
|
718
|
+
instance.loader.onRequestLoad.toPromise().then(() => {
|
|
719
|
+
return this.subModelLoader.loadSubModelByComponent(instance);
|
|
720
|
+
})
|
|
721
|
+
.then(subDocument => {
|
|
722
|
+
if (isDestroyed) {
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
instance.loader.markAsLoaded();
|
|
726
|
+
const state = subDocument.getMap('state');
|
|
727
|
+
this.syncComponent(subDocument, state, instance);
|
|
728
|
+
this.addSubModelEvent.next({
|
|
729
|
+
yType: state,
|
|
730
|
+
yDoc: subDocument
|
|
731
|
+
});
|
|
732
|
+
});
|
|
733
|
+
state.__changeMarker__.destroyCallbacks.push(() => {
|
|
734
|
+
isDestroyed = true;
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
else if (instance instanceof core.Component) {
|
|
738
|
+
throw collaborateErrorFn(`component name \`${componentName}\` is not a async component.`);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
else {
|
|
742
|
+
const sharedState = yMap.get('state');
|
|
743
|
+
const state = this.createLocalMapBySharedMap(sharedState);
|
|
744
|
+
instance = this.registry.createComponentByData(componentName, state);
|
|
745
|
+
}
|
|
654
746
|
if (instance) {
|
|
655
747
|
return instance;
|
|
656
748
|
}
|
|
@@ -664,7 +756,7 @@ exports.Collaborate = class Collaborate {
|
|
|
664
756
|
*/
|
|
665
757
|
syncArray(sharedArray, localArray) {
|
|
666
758
|
const sub = localArray.__changeMarker__.onSelfChange.subscribe((actions) => {
|
|
667
|
-
this.runLocalUpdate(() => {
|
|
759
|
+
this.runLocalUpdate(sharedArray.doc, !localArray.__changeMarker__.irrevocableUpdate, () => {
|
|
668
760
|
let index = 0;
|
|
669
761
|
for (const action of actions) {
|
|
670
762
|
switch (action.type) {
|
|
@@ -695,7 +787,7 @@ exports.Collaborate = class Collaborate {
|
|
|
695
787
|
break;
|
|
696
788
|
}
|
|
697
789
|
}
|
|
698
|
-
}
|
|
790
|
+
});
|
|
699
791
|
});
|
|
700
792
|
const syncRemote = (ev, tr) => {
|
|
701
793
|
this.runRemoteUpdate(tr, () => {
|
|
@@ -745,7 +837,7 @@ exports.Collaborate = class Collaborate {
|
|
|
745
837
|
};
|
|
746
838
|
sharedObject.observe(syncRemote);
|
|
747
839
|
const sub = localObject.__changeMarker__.onSelfChange.subscribe((actions) => {
|
|
748
|
-
this.runLocalUpdate(() => {
|
|
840
|
+
this.runLocalUpdate(sharedObject.doc, !localObject.__changeMarker__.irrevocableUpdate, () => {
|
|
749
841
|
for (const action of actions) {
|
|
750
842
|
switch (action.type) {
|
|
751
843
|
case 'propSet':
|
|
@@ -756,28 +848,33 @@ exports.Collaborate = class Collaborate {
|
|
|
756
848
|
break;
|
|
757
849
|
}
|
|
758
850
|
}
|
|
759
|
-
}
|
|
851
|
+
});
|
|
760
852
|
});
|
|
761
853
|
localObject.__changeMarker__.destroyCallbacks.push(function () {
|
|
762
854
|
sharedObject.unobserve(syncRemote);
|
|
763
855
|
sub.unsubscribe();
|
|
764
856
|
});
|
|
765
857
|
}
|
|
766
|
-
runLocalUpdate(
|
|
767
|
-
if (this.updateFromRemote) {
|
|
858
|
+
runLocalUpdate(yDoc, record, fn) {
|
|
859
|
+
if (this.updateFromRemote || !yDoc) {
|
|
768
860
|
return;
|
|
769
861
|
}
|
|
770
|
-
this.updateRemoteActions.
|
|
862
|
+
let changeList = this.updateRemoteActions.get(yDoc);
|
|
863
|
+
if (!changeList) {
|
|
864
|
+
changeList = [];
|
|
865
|
+
this.updateRemoteActions.set(yDoc, changeList);
|
|
866
|
+
}
|
|
867
|
+
changeList.push({
|
|
771
868
|
record,
|
|
772
869
|
action: fn
|
|
773
870
|
});
|
|
774
871
|
}
|
|
775
872
|
runRemoteUpdate(tr, fn) {
|
|
776
|
-
if (tr.origin ===
|
|
873
|
+
if (tr.origin === tr.doc) {
|
|
777
874
|
return;
|
|
778
875
|
}
|
|
779
876
|
this.updateFromRemote = true;
|
|
780
|
-
if (tr.origin
|
|
877
|
+
if (tr.origin instanceof yjs.UndoManager) {
|
|
781
878
|
this.scheduler.historyApplyTransact(fn);
|
|
782
879
|
}
|
|
783
880
|
else {
|
|
@@ -788,13 +885,10 @@ exports.Collaborate = class Collaborate {
|
|
|
788
885
|
};
|
|
789
886
|
exports.Collaborate = __decorate([
|
|
790
887
|
core$1.Injectable(),
|
|
791
|
-
|
|
792
|
-
__param(5, core$1.Optional()),
|
|
793
|
-
__metadata("design:paramtypes", [Number, core.RootComponentRef,
|
|
794
|
-
core.Scheduler,
|
|
888
|
+
__metadata("design:paramtypes", [core.Scheduler,
|
|
795
889
|
core.Registry,
|
|
796
890
|
core.Selection,
|
|
797
|
-
|
|
891
|
+
SubModelLoader])
|
|
798
892
|
], exports.Collaborate);
|
|
799
893
|
function remoteFormatsToLocal(registry, attrs) {
|
|
800
894
|
const formats = [];
|
|
@@ -809,6 +903,138 @@ function remoteFormatsToLocal(registry, attrs) {
|
|
|
809
903
|
return formats;
|
|
810
904
|
}
|
|
811
905
|
|
|
906
|
+
class CustomUndoManagerConfig {
|
|
907
|
+
}
|
|
908
|
+
const collabHistoryErrorFn = core.makeError('CollabHistory');
|
|
909
|
+
exports.CollabHistory = class CollabHistory {
|
|
910
|
+
get canBack() {
|
|
911
|
+
var _a;
|
|
912
|
+
return ((_a = this.manager) === null || _a === void 0 ? void 0 : _a.canUndo()) || false;
|
|
913
|
+
}
|
|
914
|
+
get canForward() {
|
|
915
|
+
var _a;
|
|
916
|
+
return ((_a = this.manager) === null || _a === void 0 ? void 0 : _a.canRedo()) || false;
|
|
917
|
+
}
|
|
918
|
+
constructor(rootComponentRef, collaborate, scheduler, selection, stackSize, undoManagerConfig) {
|
|
919
|
+
this.rootComponentRef = rootComponentRef;
|
|
920
|
+
this.collaborate = collaborate;
|
|
921
|
+
this.scheduler = scheduler;
|
|
922
|
+
this.selection = selection;
|
|
923
|
+
this.stackSize = stackSize;
|
|
924
|
+
this.undoManagerConfig = undoManagerConfig;
|
|
925
|
+
this.manager = null;
|
|
926
|
+
this.historyItems = [];
|
|
927
|
+
this.index = 0;
|
|
928
|
+
this.subscriptions = [];
|
|
929
|
+
this.backEvent = new stream.Subject();
|
|
930
|
+
this.forwardEvent = new stream.Subject();
|
|
931
|
+
this.changeEvent = new stream.Subject();
|
|
932
|
+
this.pushEvent = new stream.Subject();
|
|
933
|
+
this.onBack = this.backEvent.asObservable();
|
|
934
|
+
this.onForward = this.forwardEvent.asObservable();
|
|
935
|
+
this.onChange = this.changeEvent.asObservable();
|
|
936
|
+
this.onPush = this.pushEvent.asObservable();
|
|
937
|
+
}
|
|
938
|
+
listen() {
|
|
939
|
+
const root = this.collaborate.yDoc.getMap('RootComponent');
|
|
940
|
+
const rootComponent = this.rootComponentRef.component;
|
|
941
|
+
this.collaborate.syncRootComponent(this.collaborate.yDoc, root, rootComponent);
|
|
942
|
+
const undoManagerConfig = this.undoManagerConfig || {};
|
|
943
|
+
const manager = new yjs.UndoManager(root, {
|
|
944
|
+
trackedOrigins: new Set([this.collaborate.yDoc]),
|
|
945
|
+
captureTransaction(arg) {
|
|
946
|
+
if (undoManagerConfig.captureTransaction) {
|
|
947
|
+
return undoManagerConfig.captureTransaction(arg);
|
|
948
|
+
}
|
|
949
|
+
return true;
|
|
950
|
+
},
|
|
951
|
+
deleteFilter(item) {
|
|
952
|
+
if (undoManagerConfig.deleteFilter) {
|
|
953
|
+
return undoManagerConfig.deleteFilter(item);
|
|
954
|
+
}
|
|
955
|
+
return true;
|
|
956
|
+
}
|
|
957
|
+
});
|
|
958
|
+
this.manager = manager;
|
|
959
|
+
let beforePosition = null;
|
|
960
|
+
this.subscriptions.push(this.scheduler.onLocalChangeBefore.subscribe(() => {
|
|
961
|
+
beforePosition = this.collaborate.getRelativeCursorLocation();
|
|
962
|
+
}), this.collaborate.onAddSubModel.subscribe(() => {
|
|
963
|
+
throw collabHistoryErrorFn('single document does not support submodels.');
|
|
964
|
+
}));
|
|
965
|
+
manager.on('stack-item-added', (event) => {
|
|
966
|
+
if (event.type === 'undo') {
|
|
967
|
+
if (event.origin === manager) {
|
|
968
|
+
this.index++;
|
|
969
|
+
}
|
|
970
|
+
else {
|
|
971
|
+
this.historyItems.length = this.index;
|
|
972
|
+
this.historyItems.push({
|
|
973
|
+
before: beforePosition,
|
|
974
|
+
after: this.collaborate.getRelativeCursorLocation()
|
|
975
|
+
});
|
|
976
|
+
this.index++;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
else {
|
|
980
|
+
this.index--;
|
|
981
|
+
}
|
|
982
|
+
if (manager.undoStack.length > this.stackSize) {
|
|
983
|
+
this.historyItems.shift();
|
|
984
|
+
manager.undoStack.shift();
|
|
985
|
+
}
|
|
986
|
+
if (event.origin === this.collaborate.yDoc) {
|
|
987
|
+
this.pushEvent.next();
|
|
988
|
+
}
|
|
989
|
+
this.changeEvent.next();
|
|
990
|
+
});
|
|
991
|
+
manager.on('stack-item-popped', (ev) => {
|
|
992
|
+
const index = ev.type === 'undo' ? this.index : this.index - 1;
|
|
993
|
+
const position = this.historyItems[index] || null;
|
|
994
|
+
const p = ev.type === 'undo' ? position === null || position === void 0 ? void 0 : position.before : position === null || position === void 0 ? void 0 : position.after;
|
|
995
|
+
this.collaborate.restoreCursorPosition(p);
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
back() {
|
|
999
|
+
var _a;
|
|
1000
|
+
if (this.canBack) {
|
|
1001
|
+
(_a = this.manager) === null || _a === void 0 ? void 0 : _a.undo();
|
|
1002
|
+
this.backEvent.next();
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
forward() {
|
|
1006
|
+
var _a;
|
|
1007
|
+
if (this.canForward) {
|
|
1008
|
+
(_a = this.manager) === null || _a === void 0 ? void 0 : _a.redo();
|
|
1009
|
+
this.forwardEvent.next();
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
clear() {
|
|
1013
|
+
var _a;
|
|
1014
|
+
const last = this.historyItems.pop();
|
|
1015
|
+
this.historyItems = last ? [last] : [];
|
|
1016
|
+
this.index = last ? 1 : 0;
|
|
1017
|
+
(_a = this.manager) === null || _a === void 0 ? void 0 : _a.clear();
|
|
1018
|
+
this.changeEvent.next();
|
|
1019
|
+
}
|
|
1020
|
+
destroy() {
|
|
1021
|
+
var _a;
|
|
1022
|
+
this.index = 0;
|
|
1023
|
+
this.historyItems = [];
|
|
1024
|
+
this.subscriptions.forEach(i => i.unsubscribe());
|
|
1025
|
+
(_a = this.manager) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
1026
|
+
}
|
|
1027
|
+
};
|
|
1028
|
+
exports.CollabHistory = __decorate([
|
|
1029
|
+
core$1.Injectable(),
|
|
1030
|
+
__param(4, core$1.Inject(core.HISTORY_STACK_SIZE)),
|
|
1031
|
+
__param(5, core$1.Optional()),
|
|
1032
|
+
__metadata("design:paramtypes", [core.RootComponentRef,
|
|
1033
|
+
exports.Collaborate,
|
|
1034
|
+
core.Scheduler,
|
|
1035
|
+
core.Selection, Number, CustomUndoManagerConfig])
|
|
1036
|
+
], exports.CollabHistory);
|
|
1037
|
+
|
|
812
1038
|
exports.UserActivity = class UserActivity {
|
|
813
1039
|
constructor(syncConnector, selection) {
|
|
814
1040
|
this.syncConnector = syncConnector;
|
|
@@ -857,15 +1083,235 @@ class CollaborateModule {
|
|
|
857
1083
|
this.providers = [
|
|
858
1084
|
exports.Collaborate,
|
|
859
1085
|
exports.UserActivity,
|
|
1086
|
+
exports.CollabHistory,
|
|
1087
|
+
{
|
|
1088
|
+
provide: core.History,
|
|
1089
|
+
useExisting: exports.CollabHistory
|
|
1090
|
+
}, {
|
|
1091
|
+
provide: SyncConnector,
|
|
1092
|
+
useFactory: (collab) => {
|
|
1093
|
+
return this.config.createConnector(collab.yDoc);
|
|
1094
|
+
},
|
|
1095
|
+
deps: [exports.Collaborate]
|
|
1096
|
+
}, {
|
|
1097
|
+
provide: SubModelLoader,
|
|
1098
|
+
useClass: exports.NonSubModelLoader
|
|
1099
|
+
}
|
|
1100
|
+
];
|
|
1101
|
+
}
|
|
1102
|
+
setup(textbus) {
|
|
1103
|
+
const connector = textbus.get(SyncConnector);
|
|
1104
|
+
const userActivity = textbus.get(exports.UserActivity);
|
|
1105
|
+
userActivity.init(this.config.userinfo);
|
|
1106
|
+
return connector.onLoad.toPromise();
|
|
1107
|
+
}
|
|
1108
|
+
onDestroy(textbus) {
|
|
1109
|
+
textbus.get(exports.Collaborate).destroy();
|
|
1110
|
+
textbus.get(core.History).destroy();
|
|
1111
|
+
textbus.get(exports.UserActivity).destroy();
|
|
1112
|
+
textbus.get(SyncConnector).onDestroy();
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
exports.MultipleDocCollabHistory = class MultipleDocCollabHistory {
|
|
1117
|
+
get canBack() {
|
|
1118
|
+
return this.actionStack.length > 0 && this.index > 0;
|
|
1119
|
+
}
|
|
1120
|
+
get canForward() {
|
|
1121
|
+
return this.actionStack.length > 0 && this.index < this.actionStack.length;
|
|
1122
|
+
}
|
|
1123
|
+
constructor(collaborate, scheduler, rootComponentRef, stackSize, undoManagerConfig) {
|
|
1124
|
+
this.collaborate = collaborate;
|
|
1125
|
+
this.scheduler = scheduler;
|
|
1126
|
+
this.rootComponentRef = rootComponentRef;
|
|
1127
|
+
this.stackSize = stackSize;
|
|
1128
|
+
this.undoManagerConfig = undoManagerConfig;
|
|
1129
|
+
this.isListen = false;
|
|
1130
|
+
this.changeEvent = new stream.Subject();
|
|
1131
|
+
this.backEvent = new stream.Subject();
|
|
1132
|
+
this.forwardEvent = new stream.Subject();
|
|
1133
|
+
this.pushEvent = new stream.Subject();
|
|
1134
|
+
this.actionStack = [];
|
|
1135
|
+
this.index = 0;
|
|
1136
|
+
this.stackItem = null;
|
|
1137
|
+
this.timer = null;
|
|
1138
|
+
this.beforePosition = null;
|
|
1139
|
+
this.subscription = new stream.Subscription();
|
|
1140
|
+
this.subDocs = new Set();
|
|
1141
|
+
this.listenerCaches = new Set();
|
|
1142
|
+
this.onChange = this.changeEvent.asObservable();
|
|
1143
|
+
this.onBack = this.backEvent.asObservable();
|
|
1144
|
+
this.onForward = this.forwardEvent.asObservable();
|
|
1145
|
+
this.onPush = this.pushEvent.asObservable();
|
|
1146
|
+
}
|
|
1147
|
+
listen() {
|
|
1148
|
+
this.isListen = true;
|
|
1149
|
+
const root = this.collaborate.yDoc.getMap('RootComponent');
|
|
1150
|
+
const rootComponent = this.rootComponentRef.component;
|
|
1151
|
+
this.collaborate.syncRootComponent(this.collaborate.yDoc, root, rootComponent);
|
|
1152
|
+
this.listenItem(root, this.collaborate.yDoc);
|
|
1153
|
+
this.subscription.add(this.collaborate.onAddSubModel.subscribe(({ yType, yDoc }) => {
|
|
1154
|
+
if (this.subDocs.has(yType)) {
|
|
1155
|
+
return;
|
|
1156
|
+
}
|
|
1157
|
+
this.subDocs.add(yType);
|
|
1158
|
+
if (this.isListen) {
|
|
1159
|
+
this.listenItem(yType, yDoc);
|
|
1160
|
+
}
|
|
1161
|
+
}), this.scheduler.onLocalChangeBefore.subscribe(() => {
|
|
1162
|
+
this.beforePosition = this.collaborate.getRelativeCursorLocation();
|
|
1163
|
+
}));
|
|
1164
|
+
}
|
|
1165
|
+
forward() {
|
|
1166
|
+
if (!this.canForward) {
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1169
|
+
clearTimeout(this.timer);
|
|
1170
|
+
const item = this.actionStack[this.index];
|
|
1171
|
+
if (item) {
|
|
1172
|
+
for (const i of item.undoManagers) {
|
|
1173
|
+
i.redo();
|
|
1174
|
+
}
|
|
1175
|
+
this.collaborate.restoreCursorPosition(item.after);
|
|
1176
|
+
}
|
|
1177
|
+
this.index++;
|
|
1178
|
+
this.forwardEvent.next();
|
|
1179
|
+
this.changeEvent.next();
|
|
1180
|
+
}
|
|
1181
|
+
back() {
|
|
1182
|
+
if (!this.canBack) {
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1185
|
+
clearTimeout(this.timer);
|
|
1186
|
+
let historyStackItem;
|
|
1187
|
+
if (this.stackItem) {
|
|
1188
|
+
historyStackItem = this.stackItem;
|
|
1189
|
+
this.stackItem = null;
|
|
1190
|
+
}
|
|
1191
|
+
else {
|
|
1192
|
+
this.index--;
|
|
1193
|
+
historyStackItem = this.actionStack[this.index];
|
|
1194
|
+
}
|
|
1195
|
+
let len = historyStackItem.undoManagers.length;
|
|
1196
|
+
while (len > 0) {
|
|
1197
|
+
len--;
|
|
1198
|
+
historyStackItem.undoManagers[len].undo();
|
|
1199
|
+
}
|
|
1200
|
+
if (historyStackItem) {
|
|
1201
|
+
const beforePosition = historyStackItem.before;
|
|
1202
|
+
this.collaborate.restoreCursorPosition(beforePosition);
|
|
1203
|
+
this.backEvent.next();
|
|
1204
|
+
this.changeEvent.next();
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
clear() {
|
|
1208
|
+
this.actionStack = [];
|
|
1209
|
+
this.stackItem = null;
|
|
1210
|
+
this.index = 0;
|
|
1211
|
+
this.beforePosition = null;
|
|
1212
|
+
clearTimeout(this.timer);
|
|
1213
|
+
this.listenerCaches.forEach((undoManager) => {
|
|
1214
|
+
undoManager.clear();
|
|
1215
|
+
});
|
|
1216
|
+
this.changeEvent.next();
|
|
1217
|
+
}
|
|
1218
|
+
destroy() {
|
|
1219
|
+
this.clear();
|
|
1220
|
+
this.beforePosition = this.stackItem = null;
|
|
1221
|
+
this.subscription.unsubscribe();
|
|
1222
|
+
this.listenerCaches.forEach((undoManager) => {
|
|
1223
|
+
undoManager.destroy();
|
|
1224
|
+
});
|
|
1225
|
+
this.subDocs.clear();
|
|
1226
|
+
this.listenerCaches.clear();
|
|
1227
|
+
}
|
|
1228
|
+
listenItem(yType, yDoc) {
|
|
1229
|
+
const undoManagerConfig = this.undoManagerConfig || {};
|
|
1230
|
+
const undoManager = new yjs.UndoManager(yType, {
|
|
1231
|
+
trackedOrigins: new Set([yDoc]),
|
|
1232
|
+
captureTimeout: 0,
|
|
1233
|
+
captureTransaction(arg) {
|
|
1234
|
+
if (undoManagerConfig.captureTransaction) {
|
|
1235
|
+
return undoManagerConfig.captureTransaction(arg);
|
|
1236
|
+
}
|
|
1237
|
+
return true;
|
|
1238
|
+
},
|
|
1239
|
+
deleteFilter(item) {
|
|
1240
|
+
if (undoManagerConfig.deleteFilter) {
|
|
1241
|
+
return undoManagerConfig.deleteFilter(item);
|
|
1242
|
+
}
|
|
1243
|
+
return true;
|
|
1244
|
+
}
|
|
1245
|
+
});
|
|
1246
|
+
undoManager.on('stack-item-added', (event) => {
|
|
1247
|
+
if (event.type === 'undo' && !(event.origin instanceof yjs.UndoManager)) {
|
|
1248
|
+
if (this.index != this.actionStack.length) {
|
|
1249
|
+
const redoStack = this.actionStack.slice(this.index);
|
|
1250
|
+
redoStack.forEach(item => {
|
|
1251
|
+
item.undoManagers.forEach(i => {
|
|
1252
|
+
i.clear(false, true);
|
|
1253
|
+
});
|
|
1254
|
+
});
|
|
1255
|
+
this.actionStack.length = this.index;
|
|
1256
|
+
this.changeEvent.next();
|
|
1257
|
+
}
|
|
1258
|
+
if (this.stackItem === null) {
|
|
1259
|
+
this.stackItem = {
|
|
1260
|
+
before: this.beforePosition,
|
|
1261
|
+
after: null,
|
|
1262
|
+
undoManagers: []
|
|
1263
|
+
};
|
|
1264
|
+
this.timer = setTimeout(() => {
|
|
1265
|
+
if (this.actionStack.length >= this.stackSize) {
|
|
1266
|
+
this.actionStack.shift();
|
|
1267
|
+
}
|
|
1268
|
+
else {
|
|
1269
|
+
this.index++;
|
|
1270
|
+
}
|
|
1271
|
+
// this.beforePosition = this.collaborate.getRelativeCursorLocation()
|
|
1272
|
+
this.stackItem.after = this.beforePosition;
|
|
1273
|
+
this.actionStack.push(this.stackItem);
|
|
1274
|
+
this.stackItem = null;
|
|
1275
|
+
this.pushEvent.next();
|
|
1276
|
+
this.changeEvent.next();
|
|
1277
|
+
}, 500);
|
|
1278
|
+
}
|
|
1279
|
+
this.stackItem.undoManagers.push(undoManager);
|
|
1280
|
+
}
|
|
1281
|
+
});
|
|
1282
|
+
this.listenerCaches.add(undoManager);
|
|
1283
|
+
}
|
|
1284
|
+
};
|
|
1285
|
+
exports.MultipleDocCollabHistory = __decorate([
|
|
1286
|
+
core$1.Injectable(),
|
|
1287
|
+
__param(3, core$1.Inject(core.HISTORY_STACK_SIZE)),
|
|
1288
|
+
__param(4, core$1.Optional()),
|
|
1289
|
+
__metadata("design:paramtypes", [exports.Collaborate,
|
|
1290
|
+
core.Scheduler,
|
|
1291
|
+
core.RootComponentRef, Number, CustomUndoManagerConfig])
|
|
1292
|
+
], exports.MultipleDocCollabHistory);
|
|
1293
|
+
|
|
1294
|
+
class MultipleDocumentCollaborateModule {
|
|
1295
|
+
constructor(config) {
|
|
1296
|
+
this.config = config;
|
|
1297
|
+
this.providers = [
|
|
1298
|
+
exports.Collaborate,
|
|
1299
|
+
exports.UserActivity,
|
|
1300
|
+
exports.MultipleDocCollabHistory,
|
|
860
1301
|
{
|
|
861
1302
|
provide: core.History,
|
|
862
|
-
useExisting: exports.
|
|
1303
|
+
useExisting: exports.MultipleDocCollabHistory
|
|
863
1304
|
}, {
|
|
864
1305
|
provide: SyncConnector,
|
|
865
1306
|
useFactory: (collab) => {
|
|
866
1307
|
return this.config.createConnector(collab.yDoc);
|
|
867
1308
|
},
|
|
868
1309
|
deps: [exports.Collaborate]
|
|
1310
|
+
}, {
|
|
1311
|
+
provide: SubModelLoader,
|
|
1312
|
+
useFactory: () => {
|
|
1313
|
+
return this.config.subModelLoader;
|
|
1314
|
+
}
|
|
869
1315
|
}
|
|
870
1316
|
];
|
|
871
1317
|
}
|
|
@@ -876,6 +1322,8 @@ class CollaborateModule {
|
|
|
876
1322
|
return connector.onLoad.toPromise();
|
|
877
1323
|
}
|
|
878
1324
|
onDestroy(textbus) {
|
|
1325
|
+
textbus.get(exports.Collaborate).destroy();
|
|
1326
|
+
textbus.get(core.History).destroy();
|
|
879
1327
|
textbus.get(exports.UserActivity).destroy();
|
|
880
1328
|
textbus.get(SyncConnector).onDestroy();
|
|
881
1329
|
}
|
|
@@ -884,5 +1332,7 @@ class CollaborateModule {
|
|
|
884
1332
|
exports.CollaborateModule = CollaborateModule;
|
|
885
1333
|
exports.CustomUndoManagerConfig = CustomUndoManagerConfig;
|
|
886
1334
|
exports.HocuspocusConnector = HocuspocusConnector;
|
|
1335
|
+
exports.MultipleDocumentCollaborateModule = MultipleDocumentCollaborateModule;
|
|
1336
|
+
exports.SubModelLoader = SubModelLoader;
|
|
887
1337
|
exports.SyncConnector = SyncConnector;
|
|
888
1338
|
exports.YWebsocketConnector = YWebsocketConnector;
|