@cocreate/crdt 1.18.11 → 1.18.13

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/src/index.js CHANGED
@@ -1,471 +1,471 @@
1
- /*globals config, atob, btoa, localStorage, CustomEvent*/
2
- import crud from '@cocreate/crud-client';
3
- import message from '@cocreate/message-client';
4
- import uuid from '@cocreate/uuid';
5
- import localStorage from '@cocreate/local-storage';
6
-
7
- const docs = new Map();
8
- const clientId = crud.socket.clientId || uuid.generate(12);
9
- const checkedDb = new Map();
10
- const isInit = new Map();
11
-
12
- function init(data){
13
- getText(data).then(value => {
14
- data.value = value;
15
- data.start = 0;
16
- data['clientId'] = clientId;
17
- localChange(data);
18
- });
19
- }
20
-
21
- async function getDoc(data) {
22
- try {
23
- if (['_id', 'organization_id'].includes(data.name))
24
- return
25
- let docName = getDocName(data);
26
- let doc = docs.get(docName);
27
-
28
- if (!doc) {
29
- docs.set(docName, new Map());
30
- doc = docs.get(docName);
31
- }
32
-
33
- if (!doc.has('changeLog')) {
34
- let changeLog = [];
35
- doc.set('undoLog', new Map())
36
- doc.set('redoLog', new Map())
37
-
38
- if (data.read != 'false') {
39
- if (!data.newDocument) {
40
- let response = await crud.readDocument({
41
- collection: "crdt-transactions",
42
- filter: {
43
- query: [{
44
- name: 'docName',
45
- operator: "$eq",
46
- value: docName
47
- }]
48
- }
49
- });
50
- if (response.document && response.document[0] && response.document[0].changeLog) {
51
- changeLog = response.document[0].changeLog;
52
- }
53
- }
54
- doc.set('changeLog', changeLog);
55
- await generateText(data, true);
56
- }
57
- }
58
- else if (!doc.has('text')){
59
- await generateText(data, false);
60
- }
61
- return doc;
62
- }
63
- catch (e) {
64
- console.log('Invalid param', e);
65
- }
66
- }
67
-
68
- String.prototype.customSplice = function (index, absIndex, string) {
69
- return this.slice(0, index) + string+ this.slice(index + Math.abs(absIndex));
70
- };
71
-
72
- async function generateText(data, flag) {
73
- try {
74
- let doc = docs.get(getDocName(data))
75
-
76
- let string = '';
77
- let changeLog = doc.get('changeLog');
78
- for (let change of changeLog) {
79
- if (change || change !== null ) {
80
- string = string.customSplice(change.start, change.length, change.value);
81
- }
82
- }
83
- if (string === '' && data.read !== 'false') {
84
- string = await checkDb(data, flag);
85
- }
86
- doc.set('text', string);
87
- return;
88
- }
89
- catch (e) {
90
- console.error(e);
91
- }
92
- }
93
-
94
- async function checkDb(data, flag) {
95
- let { collection, document_id, name } = data;
96
- if (checkedDb.get(`${collection}${document_id}${name}`)) return;
97
- checkedDb.set(`${collection}${document_id}${name}`, true);
98
-
99
- let string = ''
100
- if (data.newDocument)
101
- string = data.newDocument
102
- else {
103
- let response = await crud.readDocument({ collection, document: {_id: document_id, name}});
104
- string = crud.getValueFromObject(response.document[0], name);
105
- }
106
- if (string && typeof string !== 'string')
107
- string = ""
108
- if (string && typeof string === 'string' && flag != false) {
109
- data.value = string;
110
- data.start = 0;
111
- data.clientId = clientId;
112
- insertChange(data);
113
- }
114
- return string || '';
115
- }
116
-
117
- function insertChange(data, flag) {
118
- let docName = getDocName(data);
119
- let doc = docs.get(docName);
120
- let changeLog = doc.get('changeLog');
121
- if (!changeLog)
122
- return
123
-
124
- let type = 'insert';
125
- if (data.start == undefined) return;
126
- if (!data.value)
127
- type = 'delete';
128
-
129
- let change = {
130
- datetime: data.datetime || new Date().toISOString(),
131
- value: data.value || '',
132
- start: data.start,
133
- end: data.end,
134
- length: data.length || 0,
135
- clientId: data.clientId || clientId,
136
- user_id: data.user_id || localStorage.getItem("user_id"),
137
- type
138
- };
139
-
140
- let lastChange = changeLog[changeLog.length - 1];
141
- if (lastChange && change.datetime && lastChange.datetime){
142
- if (change.datetime < lastChange.datetime){
143
- // TODO: insert change at index position and update start and end postions for every element after insert
144
- console.log('requires changeLog rebuild');
145
- }
146
- if (flag != 'replace') {
147
- if (lastChange && change.start == lastChange.start) {
148
- let date1 = new Date(lastChange.datetime);
149
- let date2 = new Date(change.datetime);
150
- let diff = date2.getTime() - date1.getTime();
151
- if (diff < 500) {
152
- if (change.value.length == 1) {
153
- change.start = lastChange.start + lastChange.value.length;
154
- data.start = change.start;
155
- }
156
- if (change.length == 1) {
157
- change.start = lastChange.start - lastChange.length;
158
- data.start = change.start;
159
- }
160
- }
161
- }
162
- }
163
- }
164
- if (!change || change == null ) {
165
- console.log('null change')
166
- return
167
- }
168
- let string = doc.get('text') || '';
169
- if (change.length > 0)
170
- change.removedValue = string.substring(change.start, change.length);
171
-
172
- if (flag == 'replace') {
173
- // TODO get current string and create new changeLog array then push new change
174
- changeLog = [change];
175
- doc.set('changeLog', changeLog)
176
- } else {
177
- changeLog.push(change);
178
- }
179
-
180
- doc.set('text', string.customSplice(change.start, change.length, change.value));
181
- string = doc.get('text');
182
-
183
- if (!data.clientId){
184
- data['datetime'] = change.datetime;
185
- data['clientId'] = change.clientId;
186
-
187
- broadcastChange(data);
188
- localChange(data, string);
189
- }
190
- else
191
- localChange(data, string);
192
-
193
- if (data.clientId == clientId && data.save != "false")
194
- persistChange(data);
195
- }
196
-
197
- function broadcastChange(data){
198
- message.send({
199
- room: "",
200
- broadcastSender: 'false',
201
- broadcastBrowser: 'once',
202
- message: "crdt",
203
- data
204
- });
205
- }
206
-
207
- function localChange(data, string) {
208
- const localChange = new CustomEvent('cocreate-crdt-update', {
209
- detail: { ...data, string },
210
- });
211
- window.dispatchEvent(localChange);
212
- }
213
-
214
- function persistChange(data) {
215
- let docName = getDocName(data);
216
- let doc = docs.get(docName);
217
- let changeLog = doc.get('changeLog');
218
- let text = doc.get('text');
219
- let Data = {
220
- collection: 'crdt-transactions',
221
- document: {
222
- _id: data.document_id,
223
- docName,
224
- changeLog,
225
- text,
226
- crud: {
227
- collection: data.collection,
228
- document_id: data.document_id,
229
- name: data.name
230
- }
231
- },
232
- upsert: true,
233
- namespace: data.namespace,
234
- room: data.room,
235
- broadcast: data.broadcast,
236
- broadcastSender: data.broadcastSender,
237
- metadata: 'crdt-change'
238
- }
239
-
240
- crud.updateDocument(Data);
241
- }
242
-
243
- message.listen('crdt', function(response) {
244
- let data = response.data
245
- let docName = getDocName(data);
246
- let doc = docs.get(docName);
247
-
248
- if (doc){
249
- if (data.clientId !== clientId){
250
- insertChange(data);
251
- }
252
- }
253
- });
254
-
255
- crud.listen('sync', function(data) {
256
- if (data.collection.includes('crdt-transactions')) {
257
- if (data.document && data.document[0]) {
258
- let Data = data.document[0];
259
- let docName = Data.docName;
260
- let doc = docs.get(docName);
261
- if (doc && Data.crud) {
262
- Data.crud.value = Data.text
263
- Data.crud.start = 0
264
- Data.crud.length = doc.get('text').length
265
-
266
- doc.set('changeLog', Data.changeLog)
267
- doc.set('text', Data.text)
268
- // TODO: compare modified dates to check if arrays need to merged and orderd by date or if we just use server
269
- localChange(Data.crud, Data.text)
270
- console.log('crdtSync')
271
- }
272
- }
273
- }
274
- });
275
-
276
-
277
- /*
278
- crdt.getText({
279
- collection: 'modules',
280
- document_id: '5e4802ce3ed96d38e71fc7e5',
281
- name: 'name'
282
- })
283
- */
284
- async function getText(data) {
285
- try {
286
- let doc = await getDoc(data);
287
- if (doc) {
288
- let value = doc.get('text')
289
- return value;
290
- }
291
- else {
292
- console.log('undefined')
293
- }
294
- }
295
- catch (e) {
296
- console.error(e);
297
- return "";
298
- }
299
- }
300
-
301
-
302
- /*
303
- crdt.replaceText({
304
- collection: "module",
305
- document_id: "",
306
- name: "",
307
- value: "",
308
- crud: true | false,
309
- element: dom_object,
310
- metadata: "xxxx"
311
- })
312
- */
313
- async function replaceText(data) {
314
- try {
315
- let doc = await getDoc(data);
316
- if (doc) {
317
- let oldValue = await getText(data);
318
- if (oldValue)
319
- data.length = oldValue.length;
320
- else
321
- data.length = 0;
322
-
323
- data.start = 0;
324
- updateText(data, 'replace');
325
- }
326
- }
327
- catch (e) {
328
- console.error(e);
329
- }
330
- }
331
-
332
- /*
333
- crdt.updateText({
334
- collection: 'module_activities',
335
- document_id: '5e4802ce3ed96d38e71fc7e5',
336
- name: 'name',
337
- value: 'T',
338
- start: '8',
339
- attributes: {bold: true}
340
- length: 2, // length is used to define charcters that will be deleted
341
- })
342
- */
343
- async function updateText(data, flag) {
344
- let doc = await getDoc(data);
345
- if (doc) {
346
-
347
- insertChange(data, flag);
348
-
349
- if (data.crud != 'false' && data.save != 'false') {
350
- let wholestring = await getText(data);
351
- crud.updateDocument({
352
- collection: data.collection,
353
- document: {
354
- _id: data.document_id,
355
- [data.name]: wholestring
356
- },
357
- upsert: data.upsert,
358
- namespace: data.namespace,
359
- room: data.room,
360
- broadcast: data.broadcast,
361
- broadcastSender: data.broadcastSender,
362
- metadata: 'crdt-updateDocument'
363
- });
364
- }
365
- }
366
- }
367
-
368
- function createChange(data, change){
369
- if (change.value && change.length == 0) {
370
- change.length = change.value.length
371
- change.removedValue = change.value
372
- change.value = '';
373
- change.type = 'delete';
374
- } else {
375
- change.value = change.removedValue
376
- change.length = 0;
377
- change.type = 'insert';
378
- }
379
- data = {...data, ...change};
380
- delete data.clientId
381
- delete data.datetime
382
- delete change.clientId
383
- delete change.datetime
384
- return {data, change}
385
- }
386
-
387
- function undoText(data){
388
- let docName = getDocName(data);
389
- let doc = docs.get(docName);
390
- let changeLog = doc.get('changeLog');
391
- let undoLog = doc.get('undoLog')
392
-
393
- for (let index = changeLog.length - 1; index >= 0; index--) {
394
- let change = Object.assign({}, changeLog[index]);
395
- if (change && change.clientId == clientId){
396
- let log = undoLog.get(index)
397
- if (!log) {
398
- if (log != 'undo') {
399
- undoLog.set(index, 'undo')
400
- change.index = changeLog.length += 1;
401
- let updated = createChange(data, change);
402
- undoLog.set(updated.change.index, updated.change)
403
- updateText(updated.data)
404
- return
405
- }
406
- }
407
- }
408
- }
409
- }
410
-
411
- function redoText(data){
412
- let docName = getDocName(data);
413
- let doc = docs.get(docName);
414
- let redoLog = doc.get('redoLog')
415
- let undoLog = Array.from(doc.get('undoLog').values());
416
-
417
- for (let index = undoLog.length - 1; index >= 0; index--) {
418
- let change = Object.assign({}, undoLog[index]);
419
- if (change && change != 'undo') {
420
- let log = redoLog.get(change.index)
421
-
422
- if (!log) {
423
- if (log != 'redo') {
424
- let updated = createChange(data, change);
425
- redoLog.set(updated.change.index, updated.change)
426
- updateText(updated.data)
427
- return
428
- }
429
- }
430
- }
431
- }
432
- }
433
-
434
- async function viewVersion(data) {
435
- try {
436
- let docName = getDocName(data);
437
- let doc = docs.get(docName);
438
- let changeLog = doc.get('changeLog');
439
- let string = '';
440
-
441
- let log = changeLog.slice(0, data.version)
442
- for (let change of log) {
443
- if (change || change !== null ) {
444
- string = string.customSplice(change.start, change.length, change.value);
445
- }
446
- }
447
- return { ...data, ...string }
448
- }
449
- catch (e) {
450
- console.error(e);
451
- }
452
- }
453
-
454
-
455
-
456
- // function deleteDoc(docName) {
457
- // if (this.docs[docName]) {
458
- // delete this.docs[docName];
459
- // }
460
- // }
461
-
462
- // function destroyObserver(docName, typeName) {
463
- // this.docs[docName].doc.getText(typeName).unobserve((event) => {});
464
- // this.docs[docName].socket.awareness.off('change', this._awarenessListener);
465
- // }
466
-
467
- function getDocName(data) {
468
- return `${data.collection}${data.document_id}${data.name}`;
469
- }
470
-
471
- export default { init, getText, updateText, replaceText, undoText, redoText, viewVersion };
1
+ /*globals config, atob, btoa, localStorage, CustomEvent*/
2
+ import crud from '@cocreate/crud-client';
3
+ import message from '@cocreate/message-client';
4
+ import uuid from '@cocreate/uuid';
5
+ import localStorage from '@cocreate/local-storage';
6
+
7
+ const docs = new Map();
8
+ const clientId = crud.socket.clientId || uuid.generate(12);
9
+ const checkedDb = new Map();
10
+ const isInit = new Map();
11
+
12
+ function init(data){
13
+ getText(data).then(value => {
14
+ data.value = value;
15
+ data.start = 0;
16
+ data['clientId'] = clientId;
17
+ localChange(data);
18
+ });
19
+ }
20
+
21
+ async function getDoc(data) {
22
+ try {
23
+ if (['_id', 'organization_id'].includes(data.name))
24
+ return
25
+ let docName = getDocName(data);
26
+ let doc = docs.get(docName);
27
+
28
+ if (!doc) {
29
+ docs.set(docName, new Map());
30
+ doc = docs.get(docName);
31
+ }
32
+
33
+ if (!doc.has('changeLog')) {
34
+ let changeLog = [];
35
+ doc.set('undoLog', new Map())
36
+ doc.set('redoLog', new Map())
37
+
38
+ if (data.read != 'false') {
39
+ if (!data.newDocument) {
40
+ let response = await crud.readDocument({
41
+ collection: "crdt-transactions",
42
+ filter: {
43
+ query: [{
44
+ name: 'docName',
45
+ operator: "$eq",
46
+ value: docName
47
+ }]
48
+ }
49
+ });
50
+ if (response.document && response.document[0] && response.document[0].changeLog) {
51
+ changeLog = response.document[0].changeLog;
52
+ }
53
+ }
54
+ doc.set('changeLog', changeLog);
55
+ await generateText(data, true);
56
+ }
57
+ }
58
+ else if (!doc.has('text')){
59
+ await generateText(data, false);
60
+ }
61
+ return doc;
62
+ }
63
+ catch (e) {
64
+ console.log('Invalid param', e);
65
+ }
66
+ }
67
+
68
+ String.prototype.customSplice = function (index, absIndex, string) {
69
+ return this.slice(0, index) + string+ this.slice(index + Math.abs(absIndex));
70
+ };
71
+
72
+ async function generateText(data, flag) {
73
+ try {
74
+ let doc = docs.get(getDocName(data))
75
+
76
+ let string = '';
77
+ let changeLog = doc.get('changeLog');
78
+ for (let change of changeLog) {
79
+ if (change || change !== null ) {
80
+ string = string.customSplice(change.start, change.length, change.value);
81
+ }
82
+ }
83
+ if (string === '' && data.read !== 'false') {
84
+ string = await checkDb(data, flag);
85
+ }
86
+ doc.set('text', string);
87
+ return;
88
+ }
89
+ catch (e) {
90
+ console.error(e);
91
+ }
92
+ }
93
+
94
+ async function checkDb(data, flag) {
95
+ let { collection, document_id, name } = data;
96
+ if (checkedDb.get(`${collection}${document_id}${name}`)) return;
97
+ checkedDb.set(`${collection}${document_id}${name}`, true);
98
+
99
+ let string = ''
100
+ if (data.newDocument)
101
+ string = data.newDocument
102
+ else {
103
+ let response = await crud.readDocument({ collection, document: {_id: document_id, name}});
104
+ string = crud.getValueFromObject(response.document[0], name);
105
+ }
106
+ if (string && typeof string !== 'string')
107
+ string = ""
108
+ if (string && typeof string === 'string' && flag != false) {
109
+ data.value = string;
110
+ data.start = 0;
111
+ data.clientId = clientId;
112
+ insertChange(data);
113
+ }
114
+ return string || '';
115
+ }
116
+
117
+ function insertChange(data, flag) {
118
+ let docName = getDocName(data);
119
+ let doc = docs.get(docName);
120
+ let changeLog = doc.get('changeLog');
121
+ if (!changeLog)
122
+ return
123
+
124
+ let type = 'insert';
125
+ if (data.start == undefined) return;
126
+ if (!data.value)
127
+ type = 'delete';
128
+
129
+ let change = {
130
+ datetime: data.datetime || new Date().toISOString(),
131
+ value: data.value || '',
132
+ start: data.start,
133
+ end: data.end,
134
+ length: data.length || 0,
135
+ clientId: data.clientId || clientId,
136
+ user_id: data.user_id || localStorage.getItem("user_id"),
137
+ type
138
+ };
139
+
140
+ let lastChange = changeLog[changeLog.length - 1];
141
+ if (lastChange && change.datetime && lastChange.datetime){
142
+ if (change.datetime < lastChange.datetime){
143
+ // TODO: insert change at index position and update start and end postions for every element after insert
144
+ console.log('requires changeLog rebuild');
145
+ }
146
+ if (flag != 'replace') {
147
+ if (lastChange && change.start == lastChange.start) {
148
+ let date1 = new Date(lastChange.datetime);
149
+ let date2 = new Date(change.datetime);
150
+ let diff = date2.getTime() - date1.getTime();
151
+ if (diff < 500) {
152
+ if (change.value.length == 1) {
153
+ change.start = lastChange.start + lastChange.value.length;
154
+ data.start = change.start;
155
+ }
156
+ if (change.length == 1) {
157
+ change.start = lastChange.start - lastChange.length;
158
+ data.start = change.start;
159
+ }
160
+ }
161
+ }
162
+ }
163
+ }
164
+ if (!change || change == null ) {
165
+ console.log('null change')
166
+ return
167
+ }
168
+ let string = doc.get('text') || '';
169
+ if (change.length > 0)
170
+ change.removedValue = string.substring(change.start, change.length);
171
+
172
+ if (flag == 'replace') {
173
+ // TODO get current string and create new changeLog array then push new change
174
+ changeLog = [change];
175
+ doc.set('changeLog', changeLog)
176
+ } else {
177
+ changeLog.push(change);
178
+ }
179
+
180
+ doc.set('text', string.customSplice(change.start, change.length, change.value));
181
+ string = doc.get('text');
182
+
183
+ if (!data.clientId){
184
+ data['datetime'] = change.datetime;
185
+ data['clientId'] = change.clientId;
186
+
187
+ broadcastChange(data);
188
+ localChange(data, string);
189
+ }
190
+ else
191
+ localChange(data, string);
192
+
193
+ if (data.clientId == clientId && data.save != "false")
194
+ persistChange(data);
195
+ }
196
+
197
+ function broadcastChange(data){
198
+ message.send({
199
+ room: "",
200
+ broadcastSender: 'false',
201
+ broadcastBrowser: 'once',
202
+ message: "crdt",
203
+ data
204
+ });
205
+ }
206
+
207
+ function localChange(data, string) {
208
+ const localChange = new CustomEvent('cocreate-crdt-update', {
209
+ detail: { ...data, string },
210
+ });
211
+ window.dispatchEvent(localChange);
212
+ }
213
+
214
+ function persistChange(data) {
215
+ let docName = getDocName(data);
216
+ let doc = docs.get(docName);
217
+ let changeLog = doc.get('changeLog');
218
+ let text = doc.get('text');
219
+ let Data = {
220
+ collection: 'crdt-transactions',
221
+ document: {
222
+ _id: data.document_id,
223
+ docName,
224
+ changeLog,
225
+ text,
226
+ crud: {
227
+ collection: data.collection,
228
+ document_id: data.document_id,
229
+ name: data.name
230
+ }
231
+ },
232
+ upsert: true,
233
+ namespace: data.namespace,
234
+ room: data.room,
235
+ broadcast: data.broadcast,
236
+ broadcastSender: data.broadcastSender,
237
+ metadata: 'crdt-change'
238
+ }
239
+
240
+ crud.updateDocument(Data);
241
+ }
242
+
243
+ message.listen('crdt', function(response) {
244
+ let data = response.data
245
+ let docName = getDocName(data);
246
+ let doc = docs.get(docName);
247
+
248
+ if (doc){
249
+ if (data.clientId !== clientId){
250
+ insertChange(data);
251
+ }
252
+ }
253
+ });
254
+
255
+ crud.listen('sync', function(data) {
256
+ if (data.collection.includes('crdt-transactions')) {
257
+ if (data.document && data.document[0]) {
258
+ let Data = data.document[0];
259
+ let docName = Data.docName;
260
+ let doc = docs.get(docName);
261
+ if (doc && Data.crud) {
262
+ Data.crud.value = Data.text
263
+ Data.crud.start = 0
264
+ Data.crud.length = doc.get('text').length
265
+
266
+ doc.set('changeLog', Data.changeLog)
267
+ doc.set('text', Data.text)
268
+ // TODO: compare modified dates to check if arrays need to merged and orderd by date or if we just use server
269
+ localChange(Data.crud, Data.text)
270
+ console.log('crdtSync')
271
+ }
272
+ }
273
+ }
274
+ });
275
+
276
+
277
+ /*
278
+ crdt.getText({
279
+ collection: 'modules',
280
+ document_id: '5e4802ce3ed96d38e71fc7e5',
281
+ name: 'name'
282
+ })
283
+ */
284
+ async function getText(data) {
285
+ try {
286
+ let doc = await getDoc(data);
287
+ if (doc) {
288
+ let value = doc.get('text')
289
+ return value;
290
+ }
291
+ else {
292
+ console.log('undefined')
293
+ }
294
+ }
295
+ catch (e) {
296
+ console.error(e);
297
+ return "";
298
+ }
299
+ }
300
+
301
+
302
+ /*
303
+ crdt.replaceText({
304
+ collection: "module",
305
+ document_id: "",
306
+ name: "",
307
+ value: "",
308
+ crud: true | false,
309
+ element: dom_object,
310
+ metadata: "xxxx"
311
+ })
312
+ */
313
+ async function replaceText(data) {
314
+ try {
315
+ let doc = await getDoc(data);
316
+ if (doc) {
317
+ let oldValue = await getText(data);
318
+ if (oldValue)
319
+ data.length = oldValue.length;
320
+ else
321
+ data.length = 0;
322
+
323
+ data.start = 0;
324
+ updateText(data, 'replace');
325
+ }
326
+ }
327
+ catch (e) {
328
+ console.error(e);
329
+ }
330
+ }
331
+
332
+ /*
333
+ crdt.updateText({
334
+ collection: 'module_activities',
335
+ document_id: '5e4802ce3ed96d38e71fc7e5',
336
+ name: 'name',
337
+ value: 'T',
338
+ start: '8',
339
+ attributes: {bold: true}
340
+ length: 2, // length is used to define charcters that will be deleted
341
+ })
342
+ */
343
+ async function updateText(data, flag) {
344
+ let doc = await getDoc(data);
345
+ if (doc) {
346
+
347
+ insertChange(data, flag);
348
+
349
+ if (data.crud != 'false' && data.save != 'false') {
350
+ let wholestring = await getText(data);
351
+ crud.updateDocument({
352
+ collection: data.collection,
353
+ document: {
354
+ _id: data.document_id,
355
+ [data.name]: wholestring
356
+ },
357
+ upsert: data.upsert,
358
+ namespace: data.namespace,
359
+ room: data.room,
360
+ broadcast: data.broadcast,
361
+ broadcastSender: data.broadcastSender,
362
+ metadata: 'crdt-updateDocument'
363
+ });
364
+ }
365
+ }
366
+ }
367
+
368
+ function createChange(data, change){
369
+ if (change.value && change.length == 0) {
370
+ change.length = change.value.length
371
+ change.removedValue = change.value
372
+ change.value = '';
373
+ change.type = 'delete';
374
+ } else {
375
+ change.value = change.removedValue
376
+ change.length = 0;
377
+ change.type = 'insert';
378
+ }
379
+ data = {...data, ...change};
380
+ delete data.clientId
381
+ delete data.datetime
382
+ delete change.clientId
383
+ delete change.datetime
384
+ return {data, change}
385
+ }
386
+
387
+ function undoText(data){
388
+ let docName = getDocName(data);
389
+ let doc = docs.get(docName);
390
+ let changeLog = doc.get('changeLog');
391
+ let undoLog = doc.get('undoLog')
392
+
393
+ for (let index = changeLog.length - 1; index >= 0; index--) {
394
+ let change = Object.assign({}, changeLog[index]);
395
+ if (change && change.clientId == clientId){
396
+ let log = undoLog.get(index)
397
+ if (!log) {
398
+ if (log != 'undo') {
399
+ undoLog.set(index, 'undo')
400
+ change.index = changeLog.length += 1;
401
+ let updated = createChange(data, change);
402
+ undoLog.set(updated.change.index, updated.change)
403
+ updateText(updated.data)
404
+ return
405
+ }
406
+ }
407
+ }
408
+ }
409
+ }
410
+
411
+ function redoText(data){
412
+ let docName = getDocName(data);
413
+ let doc = docs.get(docName);
414
+ let redoLog = doc.get('redoLog')
415
+ let undoLog = Array.from(doc.get('undoLog').values());
416
+
417
+ for (let index = undoLog.length - 1; index >= 0; index--) {
418
+ let change = Object.assign({}, undoLog[index]);
419
+ if (change && change != 'undo') {
420
+ let log = redoLog.get(change.index)
421
+
422
+ if (!log) {
423
+ if (log != 'redo') {
424
+ let updated = createChange(data, change);
425
+ redoLog.set(updated.change.index, updated.change)
426
+ updateText(updated.data)
427
+ return
428
+ }
429
+ }
430
+ }
431
+ }
432
+ }
433
+
434
+ async function viewVersion(data) {
435
+ try {
436
+ let docName = getDocName(data);
437
+ let doc = docs.get(docName);
438
+ let changeLog = doc.get('changeLog');
439
+ let string = '';
440
+
441
+ let log = changeLog.slice(0, data.version)
442
+ for (let change of log) {
443
+ if (change || change !== null ) {
444
+ string = string.customSplice(change.start, change.length, change.value);
445
+ }
446
+ }
447
+ return { ...data, ...string }
448
+ }
449
+ catch (e) {
450
+ console.error(e);
451
+ }
452
+ }
453
+
454
+
455
+
456
+ // function deleteDoc(docName) {
457
+ // if (this.docs[docName]) {
458
+ // delete this.docs[docName];
459
+ // }
460
+ // }
461
+
462
+ // function destroyObserver(docName, typeName) {
463
+ // this.docs[docName].doc.getText(typeName).unobserve((event) => {});
464
+ // this.docs[docName].socket.awareness.off('change', this._awarenessListener);
465
+ // }
466
+
467
+ function getDocName(data) {
468
+ return `${data.collection}${data.document_id}${data.name}`;
469
+ }
470
+
471
+ export default { init, getText, updateText, replaceText, undoText, redoText, viewVersion };