@cocreate/crdt 1.3.14 → 1.3.18
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/CHANGELOG.md +28 -0
- package/package.json +4 -4
- package/src/index.js +52 -56
- package/src/archive/core.1.js +0 -460
- package/src/archive/core.2.js +0 -321
- package/src/archive/index.1.js +0 -225
- package/src/archive/index.2.js +0 -230
- package/src/archive/lib111/y-websocket.js +0 -367
package/src/archive/core.1.js
DELETED
|
@@ -1,460 +0,0 @@
|
|
|
1
|
-
import * as Y from 'yjs'
|
|
2
|
-
import { WebsocketProvider } from 'y-websocket'
|
|
3
|
-
import { fetchUpdates, storeState, IndexeddbPersistence } from 'y-indexeddb'
|
|
4
|
-
import crud from '@cocreate/crud-client';
|
|
5
|
-
import CoCreateCursors from '@cocreate/cursors'
|
|
6
|
-
import { logger } from '@cocreate/utils'
|
|
7
|
-
|
|
8
|
-
let console = logger('off');
|
|
9
|
-
|
|
10
|
-
class CoCreateCrdt {
|
|
11
|
-
constructor(org, ydoc) {
|
|
12
|
-
this.doc = ydoc;
|
|
13
|
-
this.orgName = org;
|
|
14
|
-
this.docs = {};
|
|
15
|
-
this._awarenessListener = null;
|
|
16
|
-
this.character = '_';
|
|
17
|
-
this.listenAwereness = function(){}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
createDoc(id, element) {
|
|
21
|
-
if (!id || id == "") {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
let newInfo = this.parseType(id)
|
|
26
|
-
// console.log(newInfo);
|
|
27
|
-
|
|
28
|
-
const newId = newInfo.id;
|
|
29
|
-
|
|
30
|
-
if (this.docs[newId]) {
|
|
31
|
-
if (element && !this.__checkExistElement(this.docs[newId].elements, element)) {
|
|
32
|
-
this.docs[newId].elements.push(element);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (!this.docs[newId].types.some((type) => type === id)) {
|
|
36
|
-
// register event
|
|
37
|
-
this.docs[newId].types.push(id);
|
|
38
|
-
this.registerUpdateEvent(this.docs[newId], id)
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const yDoc = this.doc
|
|
45
|
-
|
|
46
|
-
const url_socket = this.__getSocketUrl();
|
|
47
|
-
//draw cursor dinamially
|
|
48
|
-
// new UserCursor(socketProvider);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
var socketProvider = new WebsocketProvider(url_socket, newId, yDoc);
|
|
52
|
-
let indexeddbProvider = null;
|
|
53
|
-
if (newInfo.document_id != "null") {
|
|
54
|
-
indexeddbProvider = new IndexeddbPersistence(newId, this.doc)
|
|
55
|
-
indexeddbProvider.whenSynced.then(() => {
|
|
56
|
-
console.log('loaded data from indexed db')
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let awareness = socketProvider.awareness;
|
|
61
|
-
|
|
62
|
-
this._cursors = new Map();
|
|
63
|
-
|
|
64
|
-
this._awarenessListener = event => {
|
|
65
|
-
const f = clientId => {
|
|
66
|
-
// if (clientId !== this.doc.clientID) {
|
|
67
|
-
this.updateRemoteSelection(yDoc, id, yDoc.getText(id), this._cursors, clientId, awareness)
|
|
68
|
-
// }
|
|
69
|
-
}
|
|
70
|
-
event.added.forEach(f)
|
|
71
|
-
event.removed.forEach(f)
|
|
72
|
-
event.updated.forEach(f)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
awareness.on('change', this._awarenessListener);
|
|
76
|
-
/*
|
|
77
|
-
awareness.getStates().forEach((aw, clientId) => {
|
|
78
|
-
console.log("Update --")
|
|
79
|
-
})
|
|
80
|
-
*/
|
|
81
|
-
|
|
82
|
-
this.docs[newId] = {
|
|
83
|
-
id: newId,
|
|
84
|
-
doc: yDoc,
|
|
85
|
-
socket: socketProvider,
|
|
86
|
-
awareness: awareness,
|
|
87
|
-
elements: element ? [element] : [],
|
|
88
|
-
types: [id],
|
|
89
|
-
indexeddb: indexeddbProvider
|
|
90
|
-
}
|
|
91
|
-
this.registerUpdateEvent(this.docs[newId], id)
|
|
92
|
-
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
registerUpdateEvent(docObject, id) {
|
|
97
|
-
const yDoc = docObject.doc;
|
|
98
|
-
const shardType = yDoc.getText(id)
|
|
99
|
-
let _this = this;
|
|
100
|
-
|
|
101
|
-
shardType.observe((event) => {
|
|
102
|
-
_this.__setTypeObserveEvent(event, docObject.elements, id);
|
|
103
|
-
})
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
__checkExistElement(elements, element) {
|
|
107
|
-
for (var i = 0; i < elements.length; i++) {
|
|
108
|
-
if (elements[i].isSameNode(element)) {
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
__getSocketUrl() {
|
|
116
|
-
console.log("get_socket url")
|
|
117
|
-
let w_location = window.location || window.parent.location;
|
|
118
|
-
let w_protocol = w_location.protocol;
|
|
119
|
-
let w_host = w_location.host;
|
|
120
|
-
if (w_location.protocol === "about:") {
|
|
121
|
-
w_protocol = w_location.protocol;
|
|
122
|
-
w_host = document.referrer;
|
|
123
|
-
}
|
|
124
|
-
let protocol = w_protocol === 'http:' ? 'ws' : 'wss';
|
|
125
|
-
|
|
126
|
-
let url_socket = `${protocol}://${w_host}:8080/`;
|
|
127
|
-
if (window.config && window.config.host) {
|
|
128
|
-
if (window.config.host.includes("://")) {
|
|
129
|
-
url_socket = `${window.config.host}/`;
|
|
130
|
-
} else {
|
|
131
|
-
url_socket = `${protocol}://${window.config.host}/`;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
console.log(url_socket)
|
|
136
|
-
url_socket += "crdt/";
|
|
137
|
-
|
|
138
|
-
return url_socket;
|
|
139
|
-
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
__setTypeObserveEvent(event, elements, id) {
|
|
143
|
-
console.log('set crdt event .', event.delta)
|
|
144
|
-
if (!id) return;
|
|
145
|
-
|
|
146
|
-
const eventDelta = event.delta;
|
|
147
|
-
|
|
148
|
-
if (eventDelta.length == 0) {
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
const info = JSON.parse(atob(id));
|
|
152
|
-
let is_save_value = false
|
|
153
|
-
|
|
154
|
-
// let is_crud = eventDelta.attributes && eventDelta.attributes.crud === false ? false : true;
|
|
155
|
-
|
|
156
|
-
const wholestring = event.target.toString()
|
|
157
|
-
const store_event = new CustomEvent('store-content-db', {
|
|
158
|
-
detail: wholestring
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const update_event = new CustomEvent('cocreate-crdt-update', {
|
|
163
|
-
detail: eventDelta,
|
|
164
|
-
})
|
|
165
|
-
const update_event2 = new CustomEvent('cocreate-crdt-update', {
|
|
166
|
-
detail: {eventDelta,...info},
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
window.dispatchEvent(update_event2);
|
|
170
|
-
elements.forEach((el) => {
|
|
171
|
-
if (crud.isReadAttr(el) && el.getAttribute('name') === info.name) {
|
|
172
|
-
el.dispatchEvent(update_event)
|
|
173
|
-
}
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if (typeof info !== 'object') {
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (event.transaction.local) {
|
|
182
|
-
if (elements.length == 0) {
|
|
183
|
-
is_save_value = true;
|
|
184
|
-
}
|
|
185
|
-
elements.forEach((el) => {
|
|
186
|
-
if (crud.isSaveAttr(el) && el.getAttribute('name') === info.name && info.document_id != "null") {
|
|
187
|
-
is_save_value = true;
|
|
188
|
-
el.dispatchEvent(store_event)
|
|
189
|
-
}
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
// if (is_save_value && is_crud) {
|
|
193
|
-
// crud.updateDocument({
|
|
194
|
-
// collection: info.collection,
|
|
195
|
-
// document_id: info.document_id,
|
|
196
|
-
// data: {
|
|
197
|
-
// [info.name]: wholestring
|
|
198
|
-
// },
|
|
199
|
-
// metadata: 'yjs-change'
|
|
200
|
-
// })
|
|
201
|
-
// }
|
|
202
|
-
} else {
|
|
203
|
-
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
deleteDoc(id) {
|
|
208
|
-
const info = this.parseType(id)
|
|
209
|
-
if (this.docs[info.id]) {
|
|
210
|
-
delete this.docs[info.id];
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
generateDocName(collection, document_id, name) {
|
|
215
|
-
const info = {org: this.orgName, collection, document_id, name}
|
|
216
|
-
return btoa(JSON.stringify(info));
|
|
217
|
-
// return this.orgName + "_" + collection + "_" + document_id + "_" + name;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
insertData(id, index, content, attribute) {
|
|
221
|
-
const info = this.parseType(id)
|
|
222
|
-
if (this.docs[info.id]) {
|
|
223
|
-
if (attribute) {
|
|
224
|
-
this.docs[info.id].doc.getText(id).insert(index, content, attribute);
|
|
225
|
-
} else {
|
|
226
|
-
|
|
227
|
-
this.docs[info.id].doc.getText(id).insert(index, content);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
deleteData(id, index, length) {
|
|
233
|
-
const info = this.parseType(id)
|
|
234
|
-
if (this.docs[info.id]) {
|
|
235
|
-
this.docs[info.id].doc.getText(id).delete(index, length);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
getWholeString(id) {
|
|
240
|
-
const info = this.parseType(id)
|
|
241
|
-
if (this.docs[info.id]) {
|
|
242
|
-
// console.log("!Get data")
|
|
243
|
-
return this.docs[info.id].doc.getText(id).toString();
|
|
244
|
-
} else {
|
|
245
|
-
return "--";
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
updateRemoteSelection (y, cm, type, cursors, clientId, awareness) {
|
|
250
|
-
console.log("CHANGE ---- DOCID ",this.doc.clientID,' OTHER CLIENTEID ',clientId)
|
|
251
|
-
// ToDo: blocks character inserts
|
|
252
|
-
if(clientId !== this.doc.clientID){
|
|
253
|
-
|
|
254
|
-
//console.log("TEXT -> updateRemoteSelection ",clientId,awareness,cursor)
|
|
255
|
-
//console.log("AW status",awareness.getLocalState())
|
|
256
|
-
// destroy current text mark
|
|
257
|
-
const m = cursors.get(clientId)
|
|
258
|
-
if (m !== undefined) {
|
|
259
|
-
m.caret.clear()
|
|
260
|
-
if (m.sel !== null) {
|
|
261
|
-
m.sel.clear()
|
|
262
|
-
}
|
|
263
|
-
cursors.delete(clientId)
|
|
264
|
-
}
|
|
265
|
-
// redraw caret and selection for clientId
|
|
266
|
-
const aw = awareness.getStates().get(clientId);
|
|
267
|
-
console.log(aw)
|
|
268
|
-
if (aw === undefined) {
|
|
269
|
-
console.log(" Cursor OUT ",clientId)
|
|
270
|
-
//awareness.setLocalStateField('cursor', null);
|
|
271
|
-
let elements = document.querySelectorAll('[id*="socket_'+clientId+'"]');
|
|
272
|
-
elements.forEach(function (element, index, array) {
|
|
273
|
-
element.parentNode.removeChild(element);
|
|
274
|
-
})
|
|
275
|
-
|
|
276
|
-
let sel_elements = document.querySelectorAll('[id*="sel-'+clientId+'"]');
|
|
277
|
-
sel_elements.forEach(function (sel_element, index, array) {
|
|
278
|
-
sel_element.parentNode.removeChild(sel_element);
|
|
279
|
-
})
|
|
280
|
-
/*
|
|
281
|
-
let element = document.getElementById("socket_"+clientId)
|
|
282
|
-
let sel_element = document.getElementById("sel-"+clientId)
|
|
283
|
-
if(element)
|
|
284
|
-
element.parentNode.removeChild(element);
|
|
285
|
-
if(sel_element)
|
|
286
|
-
sel_element.parentNode.removeChild(sel_element);
|
|
287
|
-
*/
|
|
288
|
-
return
|
|
289
|
-
}
|
|
290
|
-
const user = aw.user || {}
|
|
291
|
-
if (user.color == null) {
|
|
292
|
-
user.color = '#ffa500'
|
|
293
|
-
}
|
|
294
|
-
if (user.name == null) {
|
|
295
|
-
user.name = `User: ${clientId}`
|
|
296
|
-
}
|
|
297
|
-
const cursor = aw.cursor
|
|
298
|
-
console.log("Cursor ",cursor)
|
|
299
|
-
if (cursor == null || cursor.anchor == null || cursor.head == null) {
|
|
300
|
-
//let element = document.getElementById("socket_"+clientId)
|
|
301
|
-
let elements = document.querySelectorAll('[id*="socket_'+clientId+'"]');
|
|
302
|
-
elements.forEach(function (element, index, array) {
|
|
303
|
-
element.parentNode.removeChild(element);
|
|
304
|
-
})
|
|
305
|
-
|
|
306
|
-
//let sel_element = document.getElementById("sel-"+clientId)
|
|
307
|
-
let sel_elements = document.querySelectorAll('[id*="sel-'+clientId+'"]');
|
|
308
|
-
sel_elements.forEach(function (sel_element, index, array) {
|
|
309
|
-
sel_element.parentNode.removeChild(sel_element);
|
|
310
|
-
})
|
|
311
|
-
return
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const anchor = Y.createAbsolutePositionFromRelativePosition(Y.createRelativePositionFromJSON(cursor.anchor), y)
|
|
315
|
-
const head = Y.createAbsolutePositionFromRelativePosition(Y.createRelativePositionFromJSON(cursor.head), y)
|
|
316
|
-
//CoCreate.cursors.draw_cursor(1,11,12,66,{},true);
|
|
317
|
-
//console.log("PRE Draw Cursor ")
|
|
318
|
-
//console.log("anchor ",anchor , " head ",head,' Type ',type)
|
|
319
|
-
//console.log("anchor Type",anchor.type === type)
|
|
320
|
-
//console.log("anchor Type",head.type === type)
|
|
321
|
-
//if (anchor !== null && head !== null && anchor.type === type && head.type === type) {
|
|
322
|
-
if (anchor !== null && head !== null ) {
|
|
323
|
-
let from, to;
|
|
324
|
-
if (head.index < anchor.index) {
|
|
325
|
-
from = head.index
|
|
326
|
-
to = anchor.index
|
|
327
|
-
} else {
|
|
328
|
-
console.log(anchor.index)
|
|
329
|
-
from = anchor.index
|
|
330
|
-
to = head.index
|
|
331
|
-
}
|
|
332
|
-
console.log("Draw Cursor ",from,to,clientId,aw.user)
|
|
333
|
-
let t_info = this.parseTypeName(cursor.anchor['tname']);
|
|
334
|
-
let id_mirror = t_info.document_id + t_info.name+'--mirror-div';
|
|
335
|
-
let json = {};
|
|
336
|
-
let selector = '[collection="'+t_info.collection+'"][document_id="'+t_info.document_id+'"][name="'+t_info.name+'"]'
|
|
337
|
-
selector += ':not(.codemirror):not(.quill):not(.monaco)';
|
|
338
|
-
let elements = document.querySelectorAll(selector);
|
|
339
|
-
let that = this;
|
|
340
|
-
elements.forEach(function (element, index, array) {
|
|
341
|
-
json = {
|
|
342
|
-
element:element,
|
|
343
|
-
startPosition:from,
|
|
344
|
-
selector:selector,
|
|
345
|
-
endPositon:to,
|
|
346
|
-
clientId : clientId,
|
|
347
|
-
user:{
|
|
348
|
-
'color':user.color,
|
|
349
|
-
'name':user.name
|
|
350
|
-
},
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
console.log(json)
|
|
354
|
-
CoCreateCursors.draw_cursor(json);
|
|
355
|
-
//sent custom position
|
|
356
|
-
that.listen(json);
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
changeListenAwereness(callback){
|
|
363
|
-
this.listenAwereness = callback;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
listen(json){
|
|
367
|
-
this.listenAwereness.apply(this,[json])
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
destroyObserver(id, element) {
|
|
371
|
-
const info = this.parseType(id)
|
|
372
|
-
this.docs[info.id].doc.getText(id).unobserve((event) => {});
|
|
373
|
-
|
|
374
|
-
this.docs[info.id].socket.awareness.off('change', this._awarenessListener);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
getProvider(id){
|
|
378
|
-
const info = this.parseType(id)
|
|
379
|
-
if (!this.docs[info.id]) {
|
|
380
|
-
return null;
|
|
381
|
-
}
|
|
382
|
-
return this.docs[info.id].socket;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
getType(id){
|
|
386
|
-
const info = this.parseType(id)
|
|
387
|
-
if (!this.docs[info.id]) {
|
|
388
|
-
return null;
|
|
389
|
-
}
|
|
390
|
-
return this.docs[info.id].doc.getText(id);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
setCursorNull(id){
|
|
394
|
-
const info = this.parseType(id)
|
|
395
|
-
if (!this.docs[info.id]) {
|
|
396
|
-
return null;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
this.docs[info.id].socket.awareness.setLocalStateField('cursor', null);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
setPositionYJS(id, from, to) {
|
|
403
|
-
const info = this.parseType(id)
|
|
404
|
-
const type = this.getType(id);
|
|
405
|
-
console.log("Type ",type)
|
|
406
|
-
if (!type) {
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
var anchor = Y.createRelativePositionFromTypeIndex(type, from)
|
|
410
|
-
var head = Y.createRelativePositionFromTypeIndex(type, to)
|
|
411
|
-
|
|
412
|
-
console.log("Sending Cursor ",{
|
|
413
|
-
anchor,
|
|
414
|
-
head
|
|
415
|
-
},{'to':to,'from':from,'info.id':info.id})
|
|
416
|
-
|
|
417
|
-
this.docs[info.id].socket.awareness.setLocalStateField('cursor', {
|
|
418
|
-
anchor,
|
|
419
|
-
head
|
|
420
|
-
})
|
|
421
|
-
/*
|
|
422
|
-
console.log("Cursor Send")
|
|
423
|
-
*/
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
//send Position Custom
|
|
427
|
-
sendPosition(json) {
|
|
428
|
-
let collection = json['collection'];
|
|
429
|
-
let document_id = json['document_id'];
|
|
430
|
-
let name = json['name'];
|
|
431
|
-
let from = json['startPosition'];
|
|
432
|
-
let to = json['endPositon'];
|
|
433
|
-
let id = this.generateID(config.organization_Id, collection, document_id, name);
|
|
434
|
-
this.setPositionYJS(id,from,to);
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
generateID(org, collection, document_id, name) {
|
|
438
|
-
const info = {org, collection, document_id, name}
|
|
439
|
-
return btoa(JSON.stringify(info));
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
parseTypeName(name) {
|
|
443
|
-
const data = JSON.parse(atob(name));
|
|
444
|
-
return data;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
parseType(id) {
|
|
448
|
-
let data = JSON.parse(atob(id));
|
|
449
|
-
|
|
450
|
-
let newId = {org: data.org, collection: data.collection, document_id: data.document_id}
|
|
451
|
-
return {
|
|
452
|
-
id: btoa(JSON.stringify(newId)),
|
|
453
|
-
name: data.name,
|
|
454
|
-
document_id: data.document_id
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
export default CoCreateCrdt;
|
|
460
|
-
|