@textbus/collaborate 2.0.0-beta.8 → 2.0.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/collaborate-cursor.d.ts +11 -11
- package/bundles/collaborate-cursor.js +120 -117
- package/bundles/collaborate.d.ts +16 -7
- package/bundles/collaborate.js +258 -220
- package/bundles/public-api.d.ts +2 -0
- package/bundles/public-api.js +14 -1
- package/package.json +7 -7
- package/src/collaborate-cursor.ts +100 -56
- package/src/collaborate.ts +252 -76
- package/src/public-api.ts +16 -0
- package/tsconfig-build.json +1 -1
package/src/collaborate.ts
CHANGED
|
@@ -1,42 +1,104 @@
|
|
|
1
|
-
import { Injectable } from '@tanbo/di'
|
|
2
|
-
import {
|
|
1
|
+
import { Inject, Injectable, Optional } from '@tanbo/di'
|
|
2
|
+
import { delay, filter, map, Observable, Subject, Subscription } from '@tanbo/stream'
|
|
3
3
|
import {
|
|
4
|
+
ChangeOrigin, ComponentInitData,
|
|
4
5
|
ComponentInstance,
|
|
5
|
-
ContentType,
|
|
6
|
+
ContentType, Controller,
|
|
6
7
|
Formats,
|
|
7
|
-
History,
|
|
8
|
+
History, HISTORY_STACK_SIZE,
|
|
8
9
|
makeError,
|
|
9
10
|
Registry,
|
|
10
|
-
Renderer,
|
|
11
11
|
RootComponentRef,
|
|
12
|
+
Scheduler,
|
|
12
13
|
Selection,
|
|
13
14
|
SelectionPaths,
|
|
14
15
|
Slot,
|
|
15
16
|
Starter,
|
|
16
17
|
Translator
|
|
17
18
|
} from '@textbus/core'
|
|
18
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
Array as YArray,
|
|
21
|
+
Doc as YDoc,
|
|
22
|
+
Map as YMap,
|
|
23
|
+
RelativePosition,
|
|
24
|
+
Text as YText,
|
|
25
|
+
Transaction,
|
|
26
|
+
UndoManager,
|
|
27
|
+
createAbsolutePositionFromRelativePosition,
|
|
28
|
+
createRelativePositionFromTypeIndex
|
|
29
|
+
} from 'yjs'
|
|
19
30
|
|
|
20
31
|
import { CollaborateCursor, RemoteSelection } from './collaborate-cursor'
|
|
21
32
|
import { createUnknownComponent } from './unknown.component'
|
|
22
33
|
|
|
23
34
|
const collaborateErrorFn = makeError('Collaborate')
|
|
24
35
|
|
|
36
|
+
interface CursorPosition {
|
|
37
|
+
anchor: RelativePosition
|
|
38
|
+
focus: RelativePosition
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
class ContentMap {
|
|
42
|
+
private slotAndYTextMap = new WeakMap<Slot, YText>()
|
|
43
|
+
private yTextAndSLotMap = new WeakMap<YText, Slot>()
|
|
44
|
+
|
|
45
|
+
set(key: Slot, value: YText): void
|
|
46
|
+
set(key: YText, value: Slot): void
|
|
47
|
+
set(key: any, value: any) {
|
|
48
|
+
if (key instanceof Slot) {
|
|
49
|
+
this.slotAndYTextMap.set(key, value)
|
|
50
|
+
this.yTextAndSLotMap.set(value, key)
|
|
51
|
+
} else {
|
|
52
|
+
this.slotAndYTextMap.set(value, key)
|
|
53
|
+
this.yTextAndSLotMap.set(key, value)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get(key: Slot): YText | null
|
|
58
|
+
get(key: YText): Slot | null
|
|
59
|
+
get(key: any) {
|
|
60
|
+
if (key instanceof Slot) {
|
|
61
|
+
return this.slotAndYTextMap.get(key) || null
|
|
62
|
+
}
|
|
63
|
+
return this.yTextAndSLotMap.get(key) || null
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
delete(key: Slot | YText) {
|
|
67
|
+
if (key instanceof Slot) {
|
|
68
|
+
const v = this.slotAndYTextMap.get(key)
|
|
69
|
+
this.slotAndYTextMap.delete(key)
|
|
70
|
+
if (v) {
|
|
71
|
+
this.yTextAndSLotMap.delete(v)
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
const v = this.yTextAndSLotMap.get(key)
|
|
75
|
+
this.yTextAndSLotMap.delete(key)
|
|
76
|
+
if (v) {
|
|
77
|
+
this.slotAndYTextMap.delete(v)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export abstract class TranslatorFallback {
|
|
84
|
+
abstract createComponentByData(name: string, data: ComponentInitData): ComponentInstance | null
|
|
85
|
+
}
|
|
86
|
+
|
|
25
87
|
@Injectable()
|
|
26
88
|
export class Collaborate implements History {
|
|
27
89
|
onSelectionChange: Observable<SelectionPaths>
|
|
28
90
|
yDoc = new YDoc()
|
|
29
91
|
onBack: Observable<void>
|
|
30
92
|
onForward: Observable<void>
|
|
31
|
-
onChange: Observable<
|
|
93
|
+
onChange: Observable<void>
|
|
32
94
|
onPush: Observable<void>
|
|
33
95
|
|
|
34
96
|
get canBack() {
|
|
35
|
-
return this.manager?.canUndo()
|
|
97
|
+
return this.manager?.canUndo() || false
|
|
36
98
|
}
|
|
37
99
|
|
|
38
100
|
get canForward() {
|
|
39
|
-
return this.manager?.canRedo()
|
|
101
|
+
return this.manager?.canRedo() || false
|
|
40
102
|
}
|
|
41
103
|
|
|
42
104
|
private backEvent = new Subject<void>()
|
|
@@ -44,7 +106,7 @@ export class Collaborate implements History {
|
|
|
44
106
|
private changeEvent = new Subject<void>()
|
|
45
107
|
private pushEvent = new Subject<void>()
|
|
46
108
|
|
|
47
|
-
private manager
|
|
109
|
+
private manager: UndoManager | null = null
|
|
48
110
|
|
|
49
111
|
private subscriptions: Subscription[] = []
|
|
50
112
|
private updateFromRemote = false
|
|
@@ -55,89 +117,180 @@ export class Collaborate implements History {
|
|
|
55
117
|
private componentStateSyncCaches = new WeakMap<ComponentInstance, () => void>()
|
|
56
118
|
|
|
57
119
|
private selectionChangeEvent = new Subject<SelectionPaths>()
|
|
120
|
+
private contentMap = new ContentMap()
|
|
58
121
|
|
|
59
122
|
private updateRemoteActions: Array<() => void> = []
|
|
60
123
|
|
|
61
|
-
constructor(private
|
|
124
|
+
constructor(@Inject(HISTORY_STACK_SIZE) private stackSize: number,
|
|
125
|
+
private rootComponentRef: RootComponentRef,
|
|
62
126
|
private collaborateCursor: CollaborateCursor,
|
|
127
|
+
private controller: Controller,
|
|
128
|
+
private scheduler: Scheduler,
|
|
63
129
|
private translator: Translator,
|
|
64
|
-
private renderer: Renderer,
|
|
65
130
|
private registry: Registry,
|
|
66
131
|
private selection: Selection,
|
|
67
|
-
private starter: Starter
|
|
68
|
-
|
|
132
|
+
private starter: Starter,
|
|
133
|
+
@Optional() private translatorFallback: TranslatorFallback) {
|
|
134
|
+
this.onSelectionChange = this.selectionChangeEvent.asObservable().pipe(delay())
|
|
69
135
|
this.onBack = this.backEvent.asObservable()
|
|
70
136
|
this.onForward = this.forwardEvent.asObservable()
|
|
71
137
|
this.onChange = this.changeEvent.asObservable()
|
|
72
138
|
this.onPush = this.pushEvent.asObservable()
|
|
73
139
|
}
|
|
74
140
|
|
|
75
|
-
|
|
141
|
+
listen() {
|
|
142
|
+
const root = this.yDoc.getMap('RootComponent')
|
|
143
|
+
const rootComponent = this.rootComponentRef.component!
|
|
144
|
+
this.manager = new UndoManager(root, {
|
|
145
|
+
trackedOrigins: new Set<any>([this.yDoc])
|
|
146
|
+
})
|
|
147
|
+
const cursorKey = 'cursor-position'
|
|
148
|
+
this.manager.on('stack-item-added', event => {
|
|
149
|
+
event.stackItem.meta.set(cursorKey, this.getRelativeCursorLocation())
|
|
150
|
+
if (this.manager!.undoStack.length > this.stackSize) {
|
|
151
|
+
this.manager!.undoStack.shift()
|
|
152
|
+
}
|
|
153
|
+
if (event.origin === this.yDoc) {
|
|
154
|
+
this.pushEvent.next()
|
|
155
|
+
}
|
|
156
|
+
this.changeEvent.next()
|
|
157
|
+
})
|
|
158
|
+
this.manager.on('stack-item-popped', event => {
|
|
159
|
+
const position = event.stackItem.meta.get(cursorKey) as CursorPosition
|
|
160
|
+
if (position) {
|
|
161
|
+
this.restoreCursorLocation(position)
|
|
162
|
+
}
|
|
163
|
+
})
|
|
76
164
|
this.subscriptions.push(
|
|
77
|
-
this.starter.onReady.subscribe(() => {
|
|
78
|
-
this.listen2()
|
|
79
|
-
}),
|
|
80
165
|
this.selection.onChange.subscribe(() => {
|
|
81
166
|
const paths = this.selection.getPaths()
|
|
82
167
|
this.selectionChangeEvent.next(paths)
|
|
168
|
+
}),
|
|
169
|
+
this.scheduler.onDocChanged.pipe(
|
|
170
|
+
map(item => {
|
|
171
|
+
return item.filter(i => {
|
|
172
|
+
return i.from !== ChangeOrigin.Remote
|
|
173
|
+
})
|
|
174
|
+
}),
|
|
175
|
+
filter(item => {
|
|
176
|
+
return item.length
|
|
177
|
+
})
|
|
178
|
+
).subscribe(() => {
|
|
179
|
+
this.yDoc.transact(() => {
|
|
180
|
+
this.updateRemoteActions.forEach(fn => {
|
|
181
|
+
fn()
|
|
182
|
+
})
|
|
183
|
+
this.updateRemoteActions = []
|
|
184
|
+
}, this.yDoc)
|
|
83
185
|
})
|
|
84
186
|
)
|
|
187
|
+
this.syncRootComponent(root, rootComponent)
|
|
85
188
|
}
|
|
86
189
|
|
|
87
190
|
updateRemoteSelection(paths: RemoteSelection[]) {
|
|
88
191
|
this.collaborateCursor.draw(paths)
|
|
89
192
|
}
|
|
90
193
|
|
|
91
|
-
listen() {
|
|
92
|
-
//
|
|
93
|
-
}
|
|
94
|
-
|
|
95
194
|
back() {
|
|
96
195
|
if (this.canBack) {
|
|
97
|
-
this.manager
|
|
196
|
+
this.manager?.undo()
|
|
197
|
+
this.backEvent.next()
|
|
98
198
|
}
|
|
99
199
|
}
|
|
100
200
|
|
|
101
201
|
forward() {
|
|
102
202
|
if (this.canForward) {
|
|
103
|
-
this.manager
|
|
203
|
+
this.manager?.redo()
|
|
204
|
+
this.forwardEvent.next()
|
|
104
205
|
}
|
|
105
206
|
}
|
|
106
207
|
|
|
208
|
+
clear() {
|
|
209
|
+
this.manager?.clear()
|
|
210
|
+
this.changeEvent.next()
|
|
211
|
+
}
|
|
212
|
+
|
|
107
213
|
destroy() {
|
|
108
214
|
this.subscriptions.forEach(i => i.unsubscribe())
|
|
215
|
+
this.collaborateCursor.destroy()
|
|
216
|
+
this.manager?.destroy()
|
|
109
217
|
}
|
|
110
218
|
|
|
111
|
-
private
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
this.subscriptions.push(
|
|
120
|
-
rootComponent.changeMarker.onForceChange.pipe(
|
|
121
|
-
microTask()
|
|
122
|
-
).subscribe(() => {
|
|
123
|
-
this.renderer.render()
|
|
124
|
-
}),
|
|
125
|
-
rootComponent.changeMarker.onChange.pipe(
|
|
126
|
-
microTask()
|
|
127
|
-
).subscribe(() => {
|
|
128
|
-
this.yDoc.transact(() => {
|
|
129
|
-
this.updateRemoteActions.forEach(fn => {
|
|
130
|
-
fn()
|
|
131
|
-
})
|
|
132
|
-
this.updateRemoteActions = []
|
|
133
|
-
}, this.yDoc)
|
|
134
|
-
this.renderer.render()
|
|
135
|
-
this.selection.restore()
|
|
219
|
+
private syncRootComponent(root: YMap<any>, rootComponent: ComponentInstance) {
|
|
220
|
+
let slots = root.get('slots') as YArray<YMap<any>>
|
|
221
|
+
if (!slots) {
|
|
222
|
+
slots = new YArray()
|
|
223
|
+
rootComponent.slots.toArray().forEach(i => {
|
|
224
|
+
const sharedSlot = this.createSharedSlotBySlot(i)
|
|
225
|
+
slots.push([sharedSlot])
|
|
136
226
|
})
|
|
137
|
-
|
|
227
|
+
this.yDoc.transact(() => {
|
|
228
|
+
root.set('state', rootComponent.state)
|
|
229
|
+
root.set('slots', slots)
|
|
230
|
+
})
|
|
231
|
+
} else if (slots.length === 0) {
|
|
232
|
+
rootComponent.updateState(() => {
|
|
233
|
+
return root.get('state')
|
|
234
|
+
})
|
|
235
|
+
this.yDoc.transact(() => {
|
|
236
|
+
rootComponent.slots.toArray().forEach(i => {
|
|
237
|
+
const sharedSlot = this.createSharedSlotBySlot(i)
|
|
238
|
+
slots.push([sharedSlot])
|
|
239
|
+
})
|
|
240
|
+
})
|
|
241
|
+
} else {
|
|
242
|
+
rootComponent.updateState(() => {
|
|
243
|
+
return root.get('state')
|
|
244
|
+
})
|
|
245
|
+
rootComponent.slots.clean()
|
|
246
|
+
slots.forEach(sharedSlot => {
|
|
247
|
+
const slot = this.createSlotBySharedSlot(sharedSlot)
|
|
248
|
+
this.syncContent(sharedSlot.get('content'), slot)
|
|
249
|
+
this.syncSlot(sharedSlot, slot)
|
|
250
|
+
rootComponent.slots.insert(slot)
|
|
251
|
+
})
|
|
252
|
+
}
|
|
253
|
+
this.syncComponent(root, rootComponent)
|
|
254
|
+
this.syncSlots(slots, rootComponent)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
private restoreCursorLocation(position: CursorPosition) {
|
|
258
|
+
const anchorPosition = createAbsolutePositionFromRelativePosition(position.anchor, this.yDoc)
|
|
259
|
+
const focusPosition = createAbsolutePositionFromRelativePosition(position.focus, this.yDoc)
|
|
260
|
+
if (anchorPosition && focusPosition) {
|
|
261
|
+
const focusSlot = this.contentMap.get(focusPosition.type as YText)
|
|
262
|
+
const anchorSlot = this.contentMap.get(anchorPosition.type as YText)
|
|
263
|
+
if (focusSlot && anchorSlot) {
|
|
264
|
+
this.selection.setBaseAndExtent(anchorSlot, anchorPosition.index, focusSlot, focusPosition.index)
|
|
265
|
+
return
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
this.selection.unSelect()
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private getRelativeCursorLocation(): CursorPosition | null {
|
|
272
|
+
const { anchorSlot, anchorOffset, focusSlot, focusOffset } = this.selection
|
|
273
|
+
if (anchorSlot) {
|
|
274
|
+
const anchorYText = this.contentMap.get(anchorSlot)
|
|
275
|
+
if (anchorYText) {
|
|
276
|
+
const anchorPosition = createRelativePositionFromTypeIndex(anchorYText, anchorOffset!)
|
|
277
|
+
if (focusSlot) {
|
|
278
|
+
const focusYText = this.contentMap.get(focusSlot)
|
|
279
|
+
if (focusYText) {
|
|
280
|
+
const focusPosition = createRelativePositionFromTypeIndex(focusYText, focusOffset!)
|
|
281
|
+
return {
|
|
282
|
+
focus: focusPosition,
|
|
283
|
+
anchor: anchorPosition
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return null
|
|
138
290
|
}
|
|
139
291
|
|
|
140
292
|
private syncContent(content: YText, slot: Slot) {
|
|
293
|
+
this.contentMap.set(slot, content)
|
|
141
294
|
const syncRemote = (ev, tr) => {
|
|
142
295
|
this.runRemoteUpdate(tr, () => {
|
|
143
296
|
slot.retain(0)
|
|
@@ -148,6 +301,7 @@ export class Collaborate implements History {
|
|
|
148
301
|
if (formats.length) {
|
|
149
302
|
slot.retain(action.retain!, formats)
|
|
150
303
|
}
|
|
304
|
+
slot.retain(slot.index + action.retain)
|
|
151
305
|
} else {
|
|
152
306
|
slot.retain(action.retain)
|
|
153
307
|
}
|
|
@@ -166,11 +320,11 @@ export class Collaborate implements History {
|
|
|
166
320
|
slot.insert(component)
|
|
167
321
|
}
|
|
168
322
|
if (this.selection.isSelected) {
|
|
169
|
-
if (slot === this.selection.
|
|
170
|
-
this.selection.
|
|
323
|
+
if (slot === this.selection.anchorSlot && this.selection.anchorOffset! > index) {
|
|
324
|
+
this.selection.setAnchor(slot, this.selection.anchorOffset! + length)
|
|
171
325
|
}
|
|
172
|
-
if (slot === this.selection.
|
|
173
|
-
this.selection.
|
|
326
|
+
if (slot === this.selection.focusSlot && this.selection.focusOffset! > index) {
|
|
327
|
+
this.selection.setFocus(slot, this.selection.focusOffset! + length)
|
|
174
328
|
}
|
|
175
329
|
}
|
|
176
330
|
} else if (action.delete) {
|
|
@@ -178,16 +332,20 @@ export class Collaborate implements History {
|
|
|
178
332
|
slot.retain(slot.index)
|
|
179
333
|
slot.delete(action.delete)
|
|
180
334
|
if (this.selection.isSelected) {
|
|
181
|
-
if (slot === this.selection.
|
|
182
|
-
this.selection.
|
|
335
|
+
if (slot === this.selection.anchorSlot && this.selection.anchorOffset! >= index) {
|
|
336
|
+
this.selection.setAnchor(slot, this.selection.startOffset! - action.delete)
|
|
183
337
|
}
|
|
184
|
-
if (slot === this.selection.
|
|
185
|
-
this.selection.
|
|
338
|
+
if (slot === this.selection.focusSlot && this.selection.focusOffset! >= index) {
|
|
339
|
+
this.selection.setFocus(slot, this.selection.focusOffset! - action.delete)
|
|
186
340
|
}
|
|
187
341
|
}
|
|
188
342
|
} else if (action.attributes) {
|
|
189
343
|
slot.updateState(draft => {
|
|
190
|
-
|
|
344
|
+
if (typeof draft === 'object' && draft !== null) {
|
|
345
|
+
Object.assign(draft, action.attributes)
|
|
346
|
+
} else {
|
|
347
|
+
return action.attributes
|
|
348
|
+
}
|
|
191
349
|
})
|
|
192
350
|
}
|
|
193
351
|
})
|
|
@@ -222,23 +380,22 @@ export class Collaborate implements History {
|
|
|
222
380
|
const isEmpty = delta.length === 1 && delta[0].insert === Slot.emptyPlaceholder
|
|
223
381
|
if (typeof action.content === 'string') {
|
|
224
382
|
length = action.content.length
|
|
225
|
-
content.insert(offset, action.content)
|
|
383
|
+
content.insert(offset, action.content, action.formats || {})
|
|
226
384
|
} else {
|
|
227
385
|
length = 1
|
|
228
|
-
const
|
|
229
|
-
const sharedComponent = this.createSharedComponentByComponent(component)
|
|
386
|
+
const sharedComponent = this.createSharedComponentByComponent(action.ref as ComponentInstance)
|
|
230
387
|
content.insertEmbed(offset, sharedComponent)
|
|
231
388
|
}
|
|
232
|
-
|
|
233
|
-
content.format(offset, length, action.formats)
|
|
234
|
-
}
|
|
389
|
+
|
|
235
390
|
if (isEmpty && offset === 0) {
|
|
236
391
|
content.delete(content.length - 1, 1)
|
|
237
392
|
}
|
|
238
393
|
offset += length
|
|
239
394
|
} else if (action.type === 'delete') {
|
|
240
395
|
const delta = content.toDelta()
|
|
241
|
-
content.
|
|
396
|
+
if (content.length) {
|
|
397
|
+
content.delete(offset, action.count)
|
|
398
|
+
}
|
|
242
399
|
if (content.length === 0) {
|
|
243
400
|
content.insert(0, '\n', delta[0]?.attributes)
|
|
244
401
|
}
|
|
@@ -265,7 +422,11 @@ export class Collaborate implements History {
|
|
|
265
422
|
if (key === 'state') {
|
|
266
423
|
const state = (ev.target as YMap<any>).get('state')
|
|
267
424
|
slot.updateState(draft => {
|
|
268
|
-
|
|
425
|
+
if (typeof draft === 'object' && draft !== null) {
|
|
426
|
+
Object.assign(draft, state)
|
|
427
|
+
} else {
|
|
428
|
+
return state
|
|
429
|
+
}
|
|
269
430
|
})
|
|
270
431
|
}
|
|
271
432
|
})
|
|
@@ -293,8 +454,8 @@ export class Collaborate implements History {
|
|
|
293
454
|
let index = 0
|
|
294
455
|
ev.delta.forEach(action => {
|
|
295
456
|
if (Reflect.has(action, 'retain')) {
|
|
296
|
-
slots.retain(action.retain!)
|
|
297
457
|
index += action.retain
|
|
458
|
+
slots.retain(index)
|
|
298
459
|
} else if (action.insert) {
|
|
299
460
|
(action.insert as Array<YMap<any>>).forEach(item => {
|
|
300
461
|
const slot = this.createSlotBySharedSlot(item)
|
|
@@ -320,8 +481,7 @@ export class Collaborate implements History {
|
|
|
320
481
|
if (action.type === 'retain') {
|
|
321
482
|
index = action.offset
|
|
322
483
|
} else if (action.type === 'insertSlot') {
|
|
323
|
-
const
|
|
324
|
-
const sharedSlot = this.createSharedSlotBySlot(slot)
|
|
484
|
+
const sharedSlot = this.createSharedSlotBySlot(action.ref)
|
|
325
485
|
remoteSlots.insert(index, [sharedSlot])
|
|
326
486
|
index++
|
|
327
487
|
} else if (action.type === 'delete') {
|
|
@@ -350,7 +510,11 @@ export class Collaborate implements History {
|
|
|
350
510
|
if (key === 'state') {
|
|
351
511
|
const state = (ev.target as YMap<any>).get('state')
|
|
352
512
|
component.updateState(draft => {
|
|
353
|
-
|
|
513
|
+
if (typeof draft === 'object' && draft !== null) {
|
|
514
|
+
Object.assign(draft, state)
|
|
515
|
+
} else {
|
|
516
|
+
return state
|
|
517
|
+
}
|
|
354
518
|
})
|
|
355
519
|
}
|
|
356
520
|
})
|
|
@@ -370,7 +534,7 @@ export class Collaborate implements History {
|
|
|
370
534
|
}
|
|
371
535
|
|
|
372
536
|
private runLocalUpdate(fn: () => void) {
|
|
373
|
-
if (this.updateFromRemote) {
|
|
537
|
+
if (this.updateFromRemote || this.controller.readonly) {
|
|
374
538
|
return
|
|
375
539
|
}
|
|
376
540
|
this.updateRemoteActions.push(fn)
|
|
@@ -381,7 +545,11 @@ export class Collaborate implements History {
|
|
|
381
545
|
return
|
|
382
546
|
}
|
|
383
547
|
this.updateFromRemote = true
|
|
384
|
-
|
|
548
|
+
if (tr.origin === this.manager) {
|
|
549
|
+
this.scheduler.historyApplyTransact(fn)
|
|
550
|
+
} else {
|
|
551
|
+
this.scheduler.remoteUpdateTransact(fn)
|
|
552
|
+
}
|
|
385
553
|
this.updateFromRemote = false
|
|
386
554
|
}
|
|
387
555
|
|
|
@@ -437,10 +605,17 @@ export class Collaborate implements History {
|
|
|
437
605
|
slots.push(slot)
|
|
438
606
|
})
|
|
439
607
|
const name = yMap.get('name')
|
|
440
|
-
const
|
|
441
|
-
|
|
608
|
+
const state = yMap.get('state')
|
|
609
|
+
let instance = this.translator.createComponentByData(name, {
|
|
610
|
+
state,
|
|
442
611
|
slots
|
|
443
612
|
})
|
|
613
|
+
if (!instance) {
|
|
614
|
+
instance = this.translatorFallback.createComponentByData(name, {
|
|
615
|
+
state,
|
|
616
|
+
slots
|
|
617
|
+
})
|
|
618
|
+
}
|
|
444
619
|
if (instance) {
|
|
445
620
|
instance.slots.toArray().forEach((slot, index) => {
|
|
446
621
|
let sharedSlot = sharedSlots.get(index)
|
|
@@ -487,6 +662,7 @@ export class Collaborate implements History {
|
|
|
487
662
|
}
|
|
488
663
|
|
|
489
664
|
private cleanSubscriptionsBySlot(slot: Slot) {
|
|
665
|
+
this.contentMap.delete(slot);
|
|
490
666
|
[this.contentSyncCaches.get(slot), this.slotStateSyncCaches.get(slot)].forEach(fn => {
|
|
491
667
|
if (fn) {
|
|
492
668
|
fn()
|
|
@@ -514,7 +690,7 @@ export class Collaborate implements History {
|
|
|
514
690
|
function makeFormats(registry: Registry, attrs?: any) {
|
|
515
691
|
const formats: Formats = []
|
|
516
692
|
if (attrs) {
|
|
517
|
-
Object.keys(attrs).
|
|
693
|
+
Object.keys(attrs).forEach(key => {
|
|
518
694
|
const formatter = registry.getFormatter(key)
|
|
519
695
|
if (formatter) {
|
|
520
696
|
formats.push([formatter, attrs[key]])
|
package/src/public-api.ts
CHANGED
|
@@ -1,2 +1,18 @@
|
|
|
1
|
+
import { History, Module } from '@textbus/core'
|
|
2
|
+
|
|
3
|
+
import { Collaborate } from './collaborate'
|
|
4
|
+
import { CollaborateCursor } from './collaborate-cursor'
|
|
5
|
+
|
|
1
6
|
export * from './collaborate'
|
|
2
7
|
export * from './collaborate-cursor'
|
|
8
|
+
|
|
9
|
+
export const collaborateModule: Module = {
|
|
10
|
+
providers: [
|
|
11
|
+
Collaborate,
|
|
12
|
+
CollaborateCursor,
|
|
13
|
+
{
|
|
14
|
+
provide: History,
|
|
15
|
+
useClass: Collaborate
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|