@liveblocks/client 0.12.0-beta.8 → 0.12.2
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/README.md +2 -12
- package/lib/cjs/authentication.d.ts +1 -1
- package/lib/cjs/authentication.js +4 -3
- package/lib/cjs/doc.d.ts +182 -11
- package/lib/cjs/doc.js +513 -198
- package/lib/cjs/live.d.ts +1 -0
- package/lib/cjs/position.d.ts +1 -5
- package/lib/cjs/position.js +4 -4
- package/lib/cjs/room.d.ts +3 -0
- package/lib/cjs/room.js +22 -3
- package/lib/cjs/storage.d.ts +2 -0
- package/lib/cjs/storage.js +14 -8
- package/lib/cjs/types.d.ts +13 -6
- package/lib/esm/authentication.d.ts +1 -1
- package/lib/esm/authentication.js +4 -3
- package/lib/esm/doc.d.ts +182 -11
- package/lib/esm/doc.js +513 -198
- package/lib/esm/live.d.ts +1 -0
- package/lib/esm/position.d.ts +1 -5
- package/lib/esm/position.js +4 -4
- package/lib/esm/room.d.ts +3 -0
- package/lib/esm/room.js +22 -3
- package/lib/esm/storage.d.ts +2 -0
- package/lib/esm/storage.js +14 -8
- package/lib/esm/types.d.ts +13 -6
- package/package.json +1 -1
package/lib/esm/doc.js
CHANGED
|
@@ -9,19 +9,23 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _Doc_instances, _Doc_clock, _Doc_items, _Doc_root, _Doc_actor, _Doc_dispatch,
|
|
12
|
+
var _Doc_instances, _Doc_clock, _Doc_opClock, _Doc_items, _Doc_root, _Doc_actor, _Doc_dispatch, _Doc_undoStack, _Doc_redoStack, _Doc_applyOp, _AbstractCrdt_instances, _AbstractCrdt_listeners, _AbstractCrdt_deepListeners, _AbstractCrdt_parent, _AbstractCrdt_doc, _AbstractCrdt_id, _AbstractCrdt_parentKey, _AbstractCrdt_applySetParentKey, _AbstractCrdt_applyRegister, _AbstractCrdt_applyCreateObject, _AbstractCrdt_applyCreateMap, _AbstractCrdt_applyCreateList, _LiveObject_instances, _LiveObject_map, _LiveObject_propToLastUpdate, _LiveObject_applyDeleteObjectKey, _LiveMap_map, _LiveRegister_data, _LiveList_items, _LiveListIterator_innerIterator;
|
|
13
13
|
import { remove } from "./utils";
|
|
14
14
|
import { CrdtType, OpType, } from "./live";
|
|
15
15
|
import { compare, makePosition } from "./position";
|
|
16
16
|
function noOp() { }
|
|
17
|
+
const MAX_UNDO_STACK = 50;
|
|
17
18
|
export class Doc {
|
|
18
19
|
constructor(root, actor = 0, dispatch = noOp) {
|
|
19
20
|
_Doc_instances.add(this);
|
|
20
21
|
_Doc_clock.set(this, 0);
|
|
22
|
+
_Doc_opClock.set(this, 0);
|
|
21
23
|
_Doc_items.set(this, new Map());
|
|
22
24
|
_Doc_root.set(this, void 0);
|
|
23
25
|
_Doc_actor.set(this, void 0);
|
|
24
26
|
_Doc_dispatch.set(this, void 0);
|
|
27
|
+
_Doc_undoStack.set(this, []);
|
|
28
|
+
_Doc_redoStack.set(this, []);
|
|
25
29
|
__classPrivateFieldSet(this, _Doc_root, root, "f");
|
|
26
30
|
__classPrivateFieldSet(this, _Doc_actor, actor, "f");
|
|
27
31
|
__classPrivateFieldSet(this, _Doc_dispatch, dispatch, "f");
|
|
@@ -62,6 +66,7 @@ export class Doc {
|
|
|
62
66
|
return doc;
|
|
63
67
|
}
|
|
64
68
|
dispatch(ops) {
|
|
69
|
+
__classPrivateFieldSet(this, _Doc_redoStack, [], "f");
|
|
65
70
|
__classPrivateFieldGet(this, _Doc_dispatch, "f").call(this, ops);
|
|
66
71
|
}
|
|
67
72
|
addItem(id, item) {
|
|
@@ -73,45 +78,38 @@ export class Doc {
|
|
|
73
78
|
getItem(id) {
|
|
74
79
|
return __classPrivateFieldGet(this, _Doc_items, "f").get(id);
|
|
75
80
|
}
|
|
76
|
-
apply(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
break;
|
|
81
|
-
}
|
|
82
|
-
case OpType.CreateObject: {
|
|
83
|
-
__classPrivateFieldGet(this, _Doc_instances, "m", _Doc_applyCreateObject).call(this, op);
|
|
84
|
-
break;
|
|
85
|
-
}
|
|
86
|
-
case OpType.CreateMap: {
|
|
87
|
-
__classPrivateFieldGet(this, _Doc_instances, "m", _Doc_applyCreateMap).call(this, op);
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
case OpType.CreateList: {
|
|
91
|
-
__classPrivateFieldGet(this, _Doc_instances, "m", _Doc_applyCreateList).call(this, op);
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
case OpType.DeleteCrdt: {
|
|
95
|
-
__classPrivateFieldGet(this, _Doc_instances, "m", _Doc_applyDeleteRecord).call(this, op);
|
|
96
|
-
break;
|
|
97
|
-
}
|
|
98
|
-
case OpType.SetParentKey: {
|
|
99
|
-
__classPrivateFieldGet(this, _Doc_instances, "m", _Doc_applySetParentKey).call(this, op);
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
case OpType.DeleteObjectKey: {
|
|
103
|
-
__classPrivateFieldGet(this, _Doc_instances, "m", _Doc_applyDeleteRecordKey).call(this, op);
|
|
104
|
-
break;
|
|
105
|
-
}
|
|
106
|
-
case OpType.CreateRegister: {
|
|
107
|
-
__classPrivateFieldGet(this, _Doc_instances, "m", _Doc_applyCreateRegister).call(this, op);
|
|
108
|
-
break;
|
|
109
|
-
}
|
|
81
|
+
apply(ops) {
|
|
82
|
+
const reverse = [];
|
|
83
|
+
for (const op of ops) {
|
|
84
|
+
reverse.push(...__classPrivateFieldGet(this, _Doc_instances, "m", _Doc_applyOp).call(this, op));
|
|
110
85
|
}
|
|
86
|
+
return reverse;
|
|
111
87
|
}
|
|
112
88
|
get root() {
|
|
113
89
|
return __classPrivateFieldGet(this, _Doc_root, "f");
|
|
114
90
|
}
|
|
91
|
+
addToUndoStack(ops) {
|
|
92
|
+
if (__classPrivateFieldGet(this, _Doc_undoStack, "f").length >= MAX_UNDO_STACK) {
|
|
93
|
+
__classPrivateFieldGet(this, _Doc_undoStack, "f").shift();
|
|
94
|
+
}
|
|
95
|
+
__classPrivateFieldGet(this, _Doc_undoStack, "f").push(ops);
|
|
96
|
+
}
|
|
97
|
+
undo() {
|
|
98
|
+
const ops = __classPrivateFieldGet(this, _Doc_undoStack, "f").pop();
|
|
99
|
+
if (ops == null) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
__classPrivateFieldGet(this, _Doc_redoStack, "f").push(this.apply(ops));
|
|
103
|
+
__classPrivateFieldGet(this, _Doc_dispatch, "f").call(this, ops);
|
|
104
|
+
}
|
|
105
|
+
redo() {
|
|
106
|
+
const ops = __classPrivateFieldGet(this, _Doc_redoStack, "f").pop();
|
|
107
|
+
if (ops == null) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
__classPrivateFieldGet(this, _Doc_undoStack, "f").push(this.apply(ops));
|
|
111
|
+
__classPrivateFieldGet(this, _Doc_dispatch, "f").call(this, ops);
|
|
112
|
+
}
|
|
115
113
|
count() {
|
|
116
114
|
return __classPrivateFieldGet(this, _Doc_items, "f").size;
|
|
117
115
|
}
|
|
@@ -119,81 +117,47 @@ export class Doc {
|
|
|
119
117
|
var _a, _b;
|
|
120
118
|
return `${__classPrivateFieldGet(this, _Doc_actor, "f")}:${__classPrivateFieldSet(this, _Doc_clock, (_b = __classPrivateFieldGet(this, _Doc_clock, "f"), _a = _b++, _b), "f"), _a}`;
|
|
121
119
|
}
|
|
120
|
+
generateOpId() {
|
|
121
|
+
var _a, _b;
|
|
122
|
+
return `${__classPrivateFieldGet(this, _Doc_actor, "f")}:${__classPrivateFieldSet(this, _Doc_opClock, (_b = __classPrivateFieldGet(this, _Doc_opClock, "f"), _a = _b++, _b), "f"), _a}`;
|
|
123
|
+
}
|
|
122
124
|
}
|
|
123
|
-
_Doc_clock = new WeakMap(), _Doc_items = new WeakMap(), _Doc_root = new WeakMap(), _Doc_actor = new WeakMap(), _Doc_dispatch = new WeakMap(), _Doc_instances = new WeakSet(),
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
const newMap = new LiveMap();
|
|
149
|
-
parent._attachChild(op.id, op.parentKey, newMap);
|
|
150
|
-
}, _Doc_applyCreateList = function _Doc_applyCreateList(op) {
|
|
151
|
-
const parent = __classPrivateFieldGet(this, _Doc_items, "f").get(op.parentId);
|
|
152
|
-
if (parent == null) {
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
const list = new LiveList();
|
|
156
|
-
parent._attachChild(op.id, op.parentKey, list);
|
|
157
|
-
}, _Doc_applyCreateObject = function _Doc_applyCreateObject(op) {
|
|
158
|
-
if (op.parentId && op.parentKey) {
|
|
159
|
-
const parent = __classPrivateFieldGet(this, _Doc_items, "f").get(op.parentId);
|
|
160
|
-
if (parent == null) {
|
|
161
|
-
return;
|
|
125
|
+
_Doc_clock = new WeakMap(), _Doc_opClock = new WeakMap(), _Doc_items = new WeakMap(), _Doc_root = new WeakMap(), _Doc_actor = new WeakMap(), _Doc_dispatch = new WeakMap(), _Doc_undoStack = new WeakMap(), _Doc_redoStack = new WeakMap(), _Doc_instances = new WeakSet(), _Doc_applyOp = function _Doc_applyOp(op) {
|
|
126
|
+
switch (op.type) {
|
|
127
|
+
case OpType.DeleteObjectKey:
|
|
128
|
+
case OpType.UpdateObject:
|
|
129
|
+
case OpType.DeleteCrdt:
|
|
130
|
+
case OpType.SetParentKey: {
|
|
131
|
+
const item = __classPrivateFieldGet(this, _Doc_items, "f").get(op.id);
|
|
132
|
+
if (item == null) {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
return item._apply(op);
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
case OpType.CreateList:
|
|
139
|
+
case OpType.CreateObject:
|
|
140
|
+
case OpType.CreateMap:
|
|
141
|
+
case OpType.CreateRegister: {
|
|
142
|
+
const parent = __classPrivateFieldGet(this, _Doc_items, "f").get(op.parentId);
|
|
143
|
+
if (parent == null) {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
return parent._apply(op);
|
|
147
|
+
break;
|
|
162
148
|
}
|
|
163
|
-
const newObj = new LiveObject(op.data);
|
|
164
|
-
parent._attachChild(op.id, op.parentKey, newObj);
|
|
165
|
-
}
|
|
166
|
-
}, _Doc_applyDeleteRecord = function _Doc_applyDeleteRecord(op) {
|
|
167
|
-
const item = __classPrivateFieldGet(this, _Doc_items, "f").get(op.id);
|
|
168
|
-
if (item == null) {
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
const parent = item._parent;
|
|
172
|
-
if (parent == null) {
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
if (parent) {
|
|
176
|
-
parent._detachChild(item);
|
|
177
|
-
}
|
|
178
|
-
}, _Doc_applySetParentKey = function _Doc_applySetParentKey(op) {
|
|
179
|
-
const item = __classPrivateFieldGet(this, _Doc_items, "f").get(op.id);
|
|
180
|
-
if (item == null) {
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
if (item._parent == null) {
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
if (item._parent instanceof LiveList) {
|
|
187
|
-
item._parent._setChildKey(op.parentKey, item);
|
|
188
149
|
}
|
|
150
|
+
return [];
|
|
189
151
|
};
|
|
190
152
|
class AbstractCrdt {
|
|
191
153
|
constructor() {
|
|
154
|
+
_AbstractCrdt_instances.add(this);
|
|
192
155
|
_AbstractCrdt_listeners.set(this, []);
|
|
193
156
|
_AbstractCrdt_deepListeners.set(this, []);
|
|
194
157
|
_AbstractCrdt_parent.set(this, void 0);
|
|
195
158
|
_AbstractCrdt_doc.set(this, void 0);
|
|
196
159
|
_AbstractCrdt_id.set(this, void 0);
|
|
160
|
+
_AbstractCrdt_parentKey.set(this, void 0);
|
|
197
161
|
}
|
|
198
162
|
/**
|
|
199
163
|
* INTERNAL
|
|
@@ -216,10 +180,45 @@ class AbstractCrdt {
|
|
|
216
180
|
/**
|
|
217
181
|
* INTERNAL
|
|
218
182
|
*/
|
|
219
|
-
|
|
220
|
-
|
|
183
|
+
get _parentKey() {
|
|
184
|
+
return __classPrivateFieldGet(this, _AbstractCrdt_parentKey, "f");
|
|
185
|
+
}
|
|
186
|
+
_apply(op) {
|
|
187
|
+
switch (op.type) {
|
|
188
|
+
case OpType.DeleteCrdt: {
|
|
189
|
+
if (this._parent != null && this._parentKey != null) {
|
|
190
|
+
const reverse = this._serialize(this._parent._id, this._parentKey);
|
|
191
|
+
this._parent._detachChild(this);
|
|
192
|
+
return reverse;
|
|
193
|
+
}
|
|
194
|
+
return [];
|
|
195
|
+
}
|
|
196
|
+
case OpType.CreateObject: {
|
|
197
|
+
return __classPrivateFieldGet(this, _AbstractCrdt_instances, "m", _AbstractCrdt_applyCreateObject).call(this, op);
|
|
198
|
+
}
|
|
199
|
+
case OpType.CreateMap: {
|
|
200
|
+
return __classPrivateFieldGet(this, _AbstractCrdt_instances, "m", _AbstractCrdt_applyCreateMap).call(this, op);
|
|
201
|
+
}
|
|
202
|
+
case OpType.CreateRegister: {
|
|
203
|
+
return __classPrivateFieldGet(this, _AbstractCrdt_instances, "m", _AbstractCrdt_applyRegister).call(this, op);
|
|
204
|
+
}
|
|
205
|
+
case OpType.CreateList: {
|
|
206
|
+
return __classPrivateFieldGet(this, _AbstractCrdt_instances, "m", _AbstractCrdt_applyCreateList).call(this, op);
|
|
207
|
+
}
|
|
208
|
+
case OpType.SetParentKey: {
|
|
209
|
+
return __classPrivateFieldGet(this, _AbstractCrdt_instances, "m", _AbstractCrdt_applySetParentKey).call(this, op);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return [];
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* INTERNAL
|
|
216
|
+
*/
|
|
217
|
+
_setParentLink(parent, key) {
|
|
218
|
+
if (__classPrivateFieldGet(this, _AbstractCrdt_parent, "f") != null && __classPrivateFieldGet(this, _AbstractCrdt_parent, "f") !== parent) {
|
|
221
219
|
throw new Error("Cannot attach parent if it already exist");
|
|
222
220
|
}
|
|
221
|
+
__classPrivateFieldSet(this, _AbstractCrdt_parentKey, key, "f");
|
|
223
222
|
__classPrivateFieldSet(this, _AbstractCrdt_parent, parent, "f");
|
|
224
223
|
}
|
|
225
224
|
/**
|
|
@@ -243,19 +242,34 @@ class AbstractCrdt {
|
|
|
243
242
|
__classPrivateFieldSet(this, _AbstractCrdt_parent, undefined, "f");
|
|
244
243
|
__classPrivateFieldSet(this, _AbstractCrdt_doc, undefined, "f");
|
|
245
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* Subscribes to updates.
|
|
247
|
+
*/
|
|
246
248
|
subscribe(listener) {
|
|
247
249
|
__classPrivateFieldGet(this, _AbstractCrdt_listeners, "f").push(listener);
|
|
248
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* Subscribes to updates and children updates.
|
|
253
|
+
*/
|
|
249
254
|
subscribeDeep(listener) {
|
|
250
255
|
__classPrivateFieldGet(this, _AbstractCrdt_deepListeners, "f").push(listener);
|
|
251
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* Unsubscribes to updates.
|
|
259
|
+
*/
|
|
252
260
|
unsubscribe(listener) {
|
|
253
261
|
remove(__classPrivateFieldGet(this, _AbstractCrdt_listeners, "f"), listener);
|
|
254
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* Unsubscribes to updates and children updates.
|
|
265
|
+
*/
|
|
255
266
|
unsubscribeDeep(listener) {
|
|
256
267
|
remove(__classPrivateFieldGet(this, _AbstractCrdt_deepListeners, "f"), listener);
|
|
257
268
|
}
|
|
258
|
-
|
|
269
|
+
/**
|
|
270
|
+
* INTERNAL
|
|
271
|
+
*/
|
|
272
|
+
_notify(onlyDeep = false) {
|
|
259
273
|
if (onlyDeep === false) {
|
|
260
274
|
for (const listener of __classPrivateFieldGet(this, _AbstractCrdt_listeners, "f")) {
|
|
261
275
|
listener();
|
|
@@ -265,19 +279,70 @@ class AbstractCrdt {
|
|
|
265
279
|
listener();
|
|
266
280
|
}
|
|
267
281
|
if (this._parent) {
|
|
268
|
-
this._parent.
|
|
282
|
+
this._parent._notify(true);
|
|
269
283
|
}
|
|
270
284
|
}
|
|
271
285
|
}
|
|
272
|
-
_AbstractCrdt_listeners = new WeakMap(), _AbstractCrdt_deepListeners = new WeakMap(), _AbstractCrdt_parent = new WeakMap(), _AbstractCrdt_doc = new WeakMap(), _AbstractCrdt_id = new WeakMap()
|
|
286
|
+
_AbstractCrdt_listeners = new WeakMap(), _AbstractCrdt_deepListeners = new WeakMap(), _AbstractCrdt_parent = new WeakMap(), _AbstractCrdt_doc = new WeakMap(), _AbstractCrdt_id = new WeakMap(), _AbstractCrdt_parentKey = new WeakMap(), _AbstractCrdt_instances = new WeakSet(), _AbstractCrdt_applySetParentKey = function _AbstractCrdt_applySetParentKey(op) {
|
|
287
|
+
if (this._parent == null) {
|
|
288
|
+
return [];
|
|
289
|
+
}
|
|
290
|
+
if (this._parent instanceof LiveList) {
|
|
291
|
+
const previousKey = this._parentKey;
|
|
292
|
+
this._parent._setChildKey(op.parentKey, this);
|
|
293
|
+
return [
|
|
294
|
+
{ type: OpType.SetParentKey, id: this._id, parentKey: previousKey },
|
|
295
|
+
];
|
|
296
|
+
}
|
|
297
|
+
return [];
|
|
298
|
+
}, _AbstractCrdt_applyRegister = function _AbstractCrdt_applyRegister(op) {
|
|
299
|
+
if (this._doc == null) {
|
|
300
|
+
throw new Error("Internal: doc should exist");
|
|
301
|
+
}
|
|
302
|
+
if (this._doc.getItem(op.id) != null) {
|
|
303
|
+
return [];
|
|
304
|
+
}
|
|
305
|
+
return this._attachChild(op.id, op.parentKey, new LiveRegister(op.data));
|
|
306
|
+
}, _AbstractCrdt_applyCreateObject = function _AbstractCrdt_applyCreateObject(op) {
|
|
307
|
+
if (this._doc == null) {
|
|
308
|
+
throw new Error("Internal: doc should exist");
|
|
309
|
+
}
|
|
310
|
+
if (this._doc.getItem(op.id) != null) {
|
|
311
|
+
return [];
|
|
312
|
+
}
|
|
313
|
+
return this._attachChild(op.id, op.parentKey, new LiveObject(op.data));
|
|
314
|
+
}, _AbstractCrdt_applyCreateMap = function _AbstractCrdt_applyCreateMap(op) {
|
|
315
|
+
if (this._doc == null) {
|
|
316
|
+
throw new Error("Internal: doc should exist");
|
|
317
|
+
}
|
|
318
|
+
if (this._doc.getItem(op.id) != null) {
|
|
319
|
+
return [];
|
|
320
|
+
}
|
|
321
|
+
return this._attachChild(op.id, op.parentKey, new LiveMap());
|
|
322
|
+
}, _AbstractCrdt_applyCreateList = function _AbstractCrdt_applyCreateList(op) {
|
|
323
|
+
if (this._doc == null) {
|
|
324
|
+
throw new Error("Internal: doc should exist");
|
|
325
|
+
}
|
|
326
|
+
if (this._doc.getItem(op.id) != null) {
|
|
327
|
+
return [];
|
|
328
|
+
}
|
|
329
|
+
return this._attachChild(op.id, op.parentKey, new LiveList());
|
|
330
|
+
};
|
|
331
|
+
/**
|
|
332
|
+
* The LiveObject class is similar to a JavaScript object that is synchronized on all clients.
|
|
333
|
+
* Keys should be a string, and values should be serializable to JSON.
|
|
334
|
+
* If multiple clients update the same property simultaneously, the last modification received by the Liveblocks servers is the winner.
|
|
335
|
+
*/
|
|
273
336
|
export class LiveObject extends AbstractCrdt {
|
|
274
337
|
constructor(object = {}) {
|
|
275
338
|
super();
|
|
339
|
+
_LiveObject_instances.add(this);
|
|
276
340
|
_LiveObject_map.set(this, void 0);
|
|
341
|
+
_LiveObject_propToLastUpdate.set(this, new Map());
|
|
277
342
|
for (const key in object) {
|
|
278
343
|
const value = object[key];
|
|
279
344
|
if (value instanceof AbstractCrdt) {
|
|
280
|
-
value.
|
|
345
|
+
value._setParentLink(this, key);
|
|
281
346
|
}
|
|
282
347
|
}
|
|
283
348
|
__classPrivateFieldSet(this, _LiveObject_map, new Map(Object.entries(object)), "f");
|
|
@@ -295,7 +360,7 @@ export class LiveObject extends AbstractCrdt {
|
|
|
295
360
|
type: OpType.CreateObject,
|
|
296
361
|
parentId,
|
|
297
362
|
parentKey,
|
|
298
|
-
data: {}
|
|
363
|
+
data: {},
|
|
299
364
|
};
|
|
300
365
|
ops.push(op);
|
|
301
366
|
for (const [key, value] of __classPrivateFieldGet(this, _LiveObject_map, "f")) {
|
|
@@ -327,7 +392,7 @@ export class LiveObject extends AbstractCrdt {
|
|
|
327
392
|
throw new Error("Tried to deserialize a crdt but it does not have a parentKey and is not the root");
|
|
328
393
|
}
|
|
329
394
|
const child = deserialize(entry, parentToChildren, doc);
|
|
330
|
-
child.
|
|
395
|
+
child._setParentLink(object, crdt.parentKey);
|
|
331
396
|
__classPrivateFieldGet(object, _LiveObject_map, "f").set(crdt.parentKey, child);
|
|
332
397
|
}
|
|
333
398
|
return object;
|
|
@@ -351,13 +416,30 @@ export class LiveObject extends AbstractCrdt {
|
|
|
351
416
|
throw new Error("Can't attach child if doc is not present");
|
|
352
417
|
}
|
|
353
418
|
const previousValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
419
|
+
let result;
|
|
354
420
|
if (isCrdt(previousValue)) {
|
|
421
|
+
result = previousValue._serialize(this._id, key);
|
|
355
422
|
previousValue._detach();
|
|
356
423
|
}
|
|
424
|
+
else if (previousValue === undefined) {
|
|
425
|
+
result = [
|
|
426
|
+
{ type: OpType.DeleteObjectKey, id: this._id, key: key },
|
|
427
|
+
];
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
result = [
|
|
431
|
+
{
|
|
432
|
+
type: OpType.UpdateObject,
|
|
433
|
+
id: this._id,
|
|
434
|
+
data: { [key]: previousValue },
|
|
435
|
+
},
|
|
436
|
+
];
|
|
437
|
+
}
|
|
357
438
|
__classPrivateFieldGet(this, _LiveObject_map, "f").set(key, child);
|
|
358
|
-
child.
|
|
439
|
+
child._setParentLink(this, key);
|
|
359
440
|
child._attach(id, this._doc);
|
|
360
|
-
this.
|
|
441
|
+
this._notify();
|
|
442
|
+
return result;
|
|
361
443
|
}
|
|
362
444
|
/**
|
|
363
445
|
* INTERNAL
|
|
@@ -371,7 +453,7 @@ export class LiveObject extends AbstractCrdt {
|
|
|
371
453
|
if (child) {
|
|
372
454
|
child._detach();
|
|
373
455
|
}
|
|
374
|
-
this.
|
|
456
|
+
this._notify();
|
|
375
457
|
}
|
|
376
458
|
/**
|
|
377
459
|
* INTERNAL
|
|
@@ -388,8 +470,36 @@ export class LiveObject extends AbstractCrdt {
|
|
|
388
470
|
* INTERNAL
|
|
389
471
|
*/
|
|
390
472
|
_apply(op) {
|
|
473
|
+
var _a;
|
|
391
474
|
if (op.type === OpType.UpdateObject) {
|
|
475
|
+
const reverse = [];
|
|
476
|
+
const reverseUpdate = {
|
|
477
|
+
type: OpType.UpdateObject,
|
|
478
|
+
id: this._id,
|
|
479
|
+
data: {},
|
|
480
|
+
};
|
|
481
|
+
reverse.push(reverseUpdate);
|
|
482
|
+
for (const key in op.data) {
|
|
483
|
+
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
484
|
+
if (oldValue !== undefined) {
|
|
485
|
+
reverseUpdate.data[key] = oldValue;
|
|
486
|
+
}
|
|
487
|
+
else if (oldValue === undefined) {
|
|
488
|
+
reverse.push({ type: OpType.DeleteObjectKey, id: this._id, key });
|
|
489
|
+
}
|
|
490
|
+
}
|
|
392
491
|
for (const key in op.data) {
|
|
492
|
+
if (op.opId == null) {
|
|
493
|
+
op.opId = (_a = this._doc) === null || _a === void 0 ? void 0 : _a.generateOpId();
|
|
494
|
+
}
|
|
495
|
+
const lastOpId = __classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key);
|
|
496
|
+
if (lastOpId === op.opId) {
|
|
497
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").delete(key);
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
else if (lastOpId != null) {
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
393
503
|
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
394
504
|
if (isCrdt(oldValue)) {
|
|
395
505
|
oldValue._detach();
|
|
@@ -397,85 +507,127 @@ export class LiveObject extends AbstractCrdt {
|
|
|
397
507
|
const value = op.data[key];
|
|
398
508
|
__classPrivateFieldGet(this, _LiveObject_map, "f").set(key, value);
|
|
399
509
|
}
|
|
400
|
-
this.
|
|
510
|
+
this._notify();
|
|
511
|
+
return reverse;
|
|
401
512
|
}
|
|
402
513
|
else if (op.type === OpType.DeleteObjectKey) {
|
|
403
|
-
|
|
404
|
-
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
405
|
-
if (isCrdt(oldValue)) {
|
|
406
|
-
oldValue._detach();
|
|
407
|
-
}
|
|
408
|
-
__classPrivateFieldGet(this, _LiveObject_map, "f").delete(key);
|
|
409
|
-
this.notify();
|
|
514
|
+
return __classPrivateFieldGet(this, _LiveObject_instances, "m", _LiveObject_applyDeleteObjectKey).call(this, op);
|
|
410
515
|
}
|
|
516
|
+
return super._apply(op);
|
|
411
517
|
}
|
|
518
|
+
/**
|
|
519
|
+
* Transform the LiveObject into a javascript object
|
|
520
|
+
*/
|
|
412
521
|
toObject() {
|
|
413
522
|
return Object.fromEntries(__classPrivateFieldGet(this, _LiveObject_map, "f"));
|
|
414
523
|
}
|
|
524
|
+
/**
|
|
525
|
+
* Adds or updates a property with a specified key and a value.
|
|
526
|
+
* @param key The key of the property to add
|
|
527
|
+
* @param value The value of the property to add
|
|
528
|
+
*/
|
|
415
529
|
set(key, value) {
|
|
416
530
|
// TODO: Find out why typescript complains
|
|
417
531
|
this.update({ [key]: value });
|
|
418
532
|
}
|
|
533
|
+
/**
|
|
534
|
+
* Returns a specified property from the LiveObject.
|
|
535
|
+
* @param key The key of the property to get
|
|
536
|
+
*/
|
|
419
537
|
get(key) {
|
|
420
538
|
return __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
421
539
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
// item.detach();
|
|
427
|
-
// }
|
|
428
|
-
// this.doc.dispatch([
|
|
429
|
-
// { type: OpType.DeleteObjectKey, id: this.id, key: key as string },
|
|
430
|
-
// ]);
|
|
431
|
-
// }
|
|
432
|
-
// this._map.delete(key as string);
|
|
433
|
-
// this.notify();
|
|
434
|
-
// }
|
|
540
|
+
/**
|
|
541
|
+
* Adds or updates multiple properties at once with an object.
|
|
542
|
+
* @param overrides The object used to overrides properties
|
|
543
|
+
*/
|
|
435
544
|
update(overrides) {
|
|
436
|
-
if (this._doc
|
|
437
|
-
const ops = [];
|
|
438
|
-
const updateOp = {
|
|
439
|
-
id: this._id,
|
|
440
|
-
type: OpType.UpdateObject,
|
|
441
|
-
data: {}
|
|
442
|
-
};
|
|
443
|
-
ops.push(updateOp);
|
|
545
|
+
if (this._doc == null || this._id == null) {
|
|
444
546
|
for (const key in overrides) {
|
|
445
547
|
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
446
|
-
if (oldValue instanceof
|
|
548
|
+
if (oldValue instanceof AbstractCrdt) {
|
|
447
549
|
oldValue._detach();
|
|
448
550
|
}
|
|
449
551
|
const newValue = overrides[key];
|
|
450
552
|
if (newValue instanceof AbstractCrdt) {
|
|
451
|
-
newValue.
|
|
452
|
-
newValue._attach(this._doc.generateId(), this._doc);
|
|
453
|
-
ops.push(...newValue._serialize(this._id, key));
|
|
454
|
-
}
|
|
455
|
-
else {
|
|
456
|
-
updateOp.data[key] = newValue;
|
|
553
|
+
newValue._setParentLink(this, key);
|
|
457
554
|
}
|
|
458
555
|
__classPrivateFieldGet(this, _LiveObject_map, "f").set(key, newValue);
|
|
459
556
|
}
|
|
460
|
-
this.
|
|
461
|
-
this.notify();
|
|
557
|
+
this._notify();
|
|
462
558
|
return;
|
|
463
559
|
}
|
|
560
|
+
const ops = [];
|
|
561
|
+
const reverseOps = [];
|
|
562
|
+
const opId = this._doc.generateOpId();
|
|
563
|
+
const updateOp = {
|
|
564
|
+
opId,
|
|
565
|
+
id: this._id,
|
|
566
|
+
type: OpType.UpdateObject,
|
|
567
|
+
data: {},
|
|
568
|
+
};
|
|
569
|
+
ops.push(updateOp);
|
|
570
|
+
const reverseUpdateOp = {
|
|
571
|
+
id: this._id,
|
|
572
|
+
type: OpType.UpdateObject,
|
|
573
|
+
data: {},
|
|
574
|
+
};
|
|
575
|
+
reverseOps.push(reverseUpdateOp);
|
|
464
576
|
for (const key in overrides) {
|
|
577
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
|
|
465
578
|
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
466
579
|
if (oldValue instanceof AbstractCrdt) {
|
|
580
|
+
reverseOps.push(...oldValue._serialize(this._id, key));
|
|
467
581
|
oldValue._detach();
|
|
468
582
|
}
|
|
583
|
+
else if (oldValue === undefined) {
|
|
584
|
+
reverseOps.push({ type: OpType.DeleteObjectKey, id: this._id, key });
|
|
585
|
+
}
|
|
586
|
+
else {
|
|
587
|
+
reverseUpdateOp.data[key] = oldValue;
|
|
588
|
+
}
|
|
469
589
|
const newValue = overrides[key];
|
|
470
590
|
if (newValue instanceof AbstractCrdt) {
|
|
471
|
-
newValue.
|
|
591
|
+
newValue._setParentLink(this, key);
|
|
592
|
+
newValue._attach(this._doc.generateId(), this._doc);
|
|
593
|
+
ops.push(...newValue._serialize(this._id, key));
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
updateOp.data[key] = newValue;
|
|
472
597
|
}
|
|
473
598
|
__classPrivateFieldGet(this, _LiveObject_map, "f").set(key, newValue);
|
|
474
599
|
}
|
|
475
|
-
this.
|
|
600
|
+
this._doc.addToUndoStack(reverseOps);
|
|
601
|
+
this._doc.dispatch(ops);
|
|
602
|
+
this._notify();
|
|
476
603
|
}
|
|
477
604
|
}
|
|
478
|
-
_LiveObject_map = new WeakMap()
|
|
605
|
+
_LiveObject_map = new WeakMap(), _LiveObject_propToLastUpdate = new WeakMap(), _LiveObject_instances = new WeakSet(), _LiveObject_applyDeleteObjectKey = function _LiveObject_applyDeleteObjectKey(op) {
|
|
606
|
+
const key = op.key;
|
|
607
|
+
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
608
|
+
let result = [];
|
|
609
|
+
if (isCrdt(oldValue)) {
|
|
610
|
+
result = oldValue._serialize(this._id, op.key);
|
|
611
|
+
oldValue._detach();
|
|
612
|
+
}
|
|
613
|
+
else if (oldValue !== undefined) {
|
|
614
|
+
result = [
|
|
615
|
+
{
|
|
616
|
+
type: OpType.UpdateObject,
|
|
617
|
+
id: this._id,
|
|
618
|
+
data: { [key]: oldValue },
|
|
619
|
+
},
|
|
620
|
+
];
|
|
621
|
+
}
|
|
622
|
+
__classPrivateFieldGet(this, _LiveObject_map, "f").delete(key);
|
|
623
|
+
this._notify();
|
|
624
|
+
return result;
|
|
625
|
+
};
|
|
626
|
+
/**
|
|
627
|
+
* The LiveMap class is similar to a JavaScript Map that is synchronized on all clients.
|
|
628
|
+
* Keys should be a string, and values should be serializable to JSON.
|
|
629
|
+
* If multiple clients update the same property simultaneously, the last modification received by the Liveblocks servers is the winner.
|
|
630
|
+
*/
|
|
479
631
|
export class LiveMap extends AbstractCrdt {
|
|
480
632
|
constructor(entries) {
|
|
481
633
|
super();
|
|
@@ -484,7 +636,7 @@ export class LiveMap extends AbstractCrdt {
|
|
|
484
636
|
const mappedEntries = [];
|
|
485
637
|
for (const entry of entries) {
|
|
486
638
|
const value = selfOrRegister(entry[1]);
|
|
487
|
-
value.
|
|
639
|
+
value._setParentLink(this, entry[0]);
|
|
488
640
|
mappedEntries.push([entry[0], value]);
|
|
489
641
|
}
|
|
490
642
|
__classPrivateFieldSet(this, _LiveMap_map, new Map(mappedEntries), "f");
|
|
@@ -535,7 +687,7 @@ export class LiveMap extends AbstractCrdt {
|
|
|
535
687
|
throw new Error("Tried to deserialize a crdt but it does not have a parentKey and is not the root");
|
|
536
688
|
}
|
|
537
689
|
const child = deserialize(entry, parentToChildren, doc);
|
|
538
|
-
child.
|
|
690
|
+
child._setParentLink(map, crdt.parentKey);
|
|
539
691
|
__classPrivateFieldGet(map, _LiveMap_map, "f").set(crdt.parentKey, child);
|
|
540
692
|
}
|
|
541
693
|
return map;
|
|
@@ -559,13 +711,19 @@ export class LiveMap extends AbstractCrdt {
|
|
|
559
711
|
throw new Error("Can't attach child if doc is not present");
|
|
560
712
|
}
|
|
561
713
|
const previousValue = __classPrivateFieldGet(this, _LiveMap_map, "f").get(key);
|
|
714
|
+
let result;
|
|
562
715
|
if (previousValue) {
|
|
716
|
+
result = previousValue._serialize(this._id, key);
|
|
563
717
|
previousValue._detach();
|
|
564
718
|
}
|
|
565
|
-
|
|
719
|
+
else {
|
|
720
|
+
result = [{ type: OpType.DeleteCrdt, id }];
|
|
721
|
+
}
|
|
722
|
+
child._setParentLink(this, key);
|
|
566
723
|
child._attach(id, this._doc);
|
|
567
724
|
__classPrivateFieldGet(this, _LiveMap_map, "f").set(key, child);
|
|
568
|
-
this.
|
|
725
|
+
this._notify();
|
|
726
|
+
return result;
|
|
569
727
|
}
|
|
570
728
|
/**
|
|
571
729
|
* INTERNAL
|
|
@@ -586,8 +744,13 @@ export class LiveMap extends AbstractCrdt {
|
|
|
586
744
|
}
|
|
587
745
|
}
|
|
588
746
|
child._detach();
|
|
589
|
-
this.
|
|
747
|
+
this._notify();
|
|
590
748
|
}
|
|
749
|
+
/**
|
|
750
|
+
* Returns a specified element from the LiveMap.
|
|
751
|
+
* @param key The key of the element to return.
|
|
752
|
+
* @returns The element associated with the specified key, or undefined if the key can't be found in the LiveMap.
|
|
753
|
+
*/
|
|
591
754
|
get(key) {
|
|
592
755
|
const value = __classPrivateFieldGet(this, _LiveMap_map, "f").get(key);
|
|
593
756
|
if (value == undefined) {
|
|
@@ -595,27 +758,47 @@ export class LiveMap extends AbstractCrdt {
|
|
|
595
758
|
}
|
|
596
759
|
return selfOrRegisterValue(value);
|
|
597
760
|
}
|
|
761
|
+
/**
|
|
762
|
+
* Adds or updates an element with a specified key and a value.
|
|
763
|
+
* @param key The key of the element to add. Should be a string.
|
|
764
|
+
* @param value The value of the element to add. Should be serializable to JSON.
|
|
765
|
+
*/
|
|
598
766
|
set(key, value) {
|
|
599
767
|
const oldValue = __classPrivateFieldGet(this, _LiveMap_map, "f").get(key);
|
|
600
768
|
if (oldValue) {
|
|
601
769
|
oldValue._detach();
|
|
602
770
|
}
|
|
603
771
|
const item = selfOrRegister(value);
|
|
604
|
-
item.
|
|
772
|
+
item._setParentLink(this, key);
|
|
605
773
|
__classPrivateFieldGet(this, _LiveMap_map, "f").set(key, item);
|
|
606
774
|
if (this._doc && this._id) {
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
this._doc.
|
|
775
|
+
const id = this._doc.generateId();
|
|
776
|
+
item._attach(id, this._doc);
|
|
777
|
+
this._doc.addToUndoStack(oldValue
|
|
778
|
+
? oldValue._serialize(this._id, key)
|
|
779
|
+
: [{ type: OpType.DeleteCrdt, id }]);
|
|
780
|
+
this._doc.dispatch(item._serialize(this._id, key));
|
|
610
781
|
}
|
|
611
|
-
this.
|
|
782
|
+
this._notify();
|
|
612
783
|
}
|
|
784
|
+
/**
|
|
785
|
+
* Returns the number of elements in the LiveMap.
|
|
786
|
+
*/
|
|
613
787
|
get size() {
|
|
614
788
|
return __classPrivateFieldGet(this, _LiveMap_map, "f").size;
|
|
615
789
|
}
|
|
790
|
+
/**
|
|
791
|
+
* Returns a boolean indicating whether an element with the specified key exists or not.
|
|
792
|
+
* @param key The key of the element to test for presence.
|
|
793
|
+
*/
|
|
616
794
|
has(key) {
|
|
617
795
|
return __classPrivateFieldGet(this, _LiveMap_map, "f").has(key);
|
|
618
796
|
}
|
|
797
|
+
/**
|
|
798
|
+
* Removes the specified element by key.
|
|
799
|
+
* @param key The key of the element to remove.
|
|
800
|
+
* @returns true if an element existed and has been removed, or false if the element does not exist.
|
|
801
|
+
*/
|
|
619
802
|
delete(key) {
|
|
620
803
|
const item = __classPrivateFieldGet(this, _LiveMap_map, "f").get(key);
|
|
621
804
|
if (item == null) {
|
|
@@ -623,12 +806,16 @@ export class LiveMap extends AbstractCrdt {
|
|
|
623
806
|
}
|
|
624
807
|
item._detach();
|
|
625
808
|
if (this._doc && item._id) {
|
|
809
|
+
this._doc.addToUndoStack(item._serialize(this._id, key));
|
|
626
810
|
this._doc.dispatch([{ type: OpType.DeleteCrdt, id: item._id }]);
|
|
627
811
|
}
|
|
628
812
|
__classPrivateFieldGet(this, _LiveMap_map, "f").delete(key);
|
|
629
|
-
this.
|
|
813
|
+
this._notify();
|
|
630
814
|
return true;
|
|
631
815
|
}
|
|
816
|
+
/**
|
|
817
|
+
* Returns a new Iterator object that contains the [key, value] pairs for each element.
|
|
818
|
+
*/
|
|
632
819
|
entries() {
|
|
633
820
|
const innerIterator = __classPrivateFieldGet(this, _LiveMap_map, "f").entries();
|
|
634
821
|
return {
|
|
@@ -650,12 +837,21 @@ export class LiveMap extends AbstractCrdt {
|
|
|
650
837
|
},
|
|
651
838
|
};
|
|
652
839
|
}
|
|
840
|
+
/**
|
|
841
|
+
* Same function object as the initial value of the entries method.
|
|
842
|
+
*/
|
|
653
843
|
[(_LiveMap_map = new WeakMap(), Symbol.iterator)]() {
|
|
654
844
|
return this.entries();
|
|
655
845
|
}
|
|
846
|
+
/**
|
|
847
|
+
* Returns a new Iterator object that contains the keys for each element.
|
|
848
|
+
*/
|
|
656
849
|
keys() {
|
|
657
850
|
return __classPrivateFieldGet(this, _LiveMap_map, "f").keys();
|
|
658
851
|
}
|
|
852
|
+
/**
|
|
853
|
+
* Returns a new Iterator object that contains the values for each element.
|
|
854
|
+
*/
|
|
659
855
|
values() {
|
|
660
856
|
const innerIterator = __classPrivateFieldGet(this, _LiveMap_map, "f").values();
|
|
661
857
|
return {
|
|
@@ -676,12 +872,19 @@ export class LiveMap extends AbstractCrdt {
|
|
|
676
872
|
},
|
|
677
873
|
};
|
|
678
874
|
}
|
|
875
|
+
/**
|
|
876
|
+
* Executes a provided function once per each key/value pair in the Map object, in insertion order.
|
|
877
|
+
* @param callback Function to execute for each entry in the map.
|
|
878
|
+
*/
|
|
679
879
|
forEach(callback) {
|
|
680
880
|
for (const entry of this) {
|
|
681
881
|
callback(entry[1], entry[0], this);
|
|
682
882
|
}
|
|
683
883
|
}
|
|
684
884
|
}
|
|
885
|
+
/**
|
|
886
|
+
* INTERNAL
|
|
887
|
+
*/
|
|
685
888
|
class LiveRegister extends AbstractCrdt {
|
|
686
889
|
constructor(data) {
|
|
687
890
|
super();
|
|
@@ -709,13 +912,15 @@ class LiveRegister extends AbstractCrdt {
|
|
|
709
912
|
if (this._id == null || parentId == null || parentKey == null) {
|
|
710
913
|
throw new Error("Cannot serialize register if parentId or parentKey is undefined");
|
|
711
914
|
}
|
|
712
|
-
return [
|
|
915
|
+
return [
|
|
916
|
+
{
|
|
713
917
|
type: OpType.CreateRegister,
|
|
714
918
|
id: this._id,
|
|
715
919
|
parentId,
|
|
716
920
|
parentKey,
|
|
717
|
-
data: this.data
|
|
718
|
-
}
|
|
921
|
+
data: this.data,
|
|
922
|
+
},
|
|
923
|
+
];
|
|
719
924
|
}
|
|
720
925
|
_attachChild(id, key, crdt) {
|
|
721
926
|
throw new Error("Method not implemented.");
|
|
@@ -723,12 +928,18 @@ class LiveRegister extends AbstractCrdt {
|
|
|
723
928
|
_detachChild(crdt) {
|
|
724
929
|
throw new Error("Method not implemented.");
|
|
725
930
|
}
|
|
931
|
+
_apply(op) {
|
|
932
|
+
return super._apply(op);
|
|
933
|
+
}
|
|
726
934
|
}
|
|
727
935
|
_LiveRegister_data = new WeakMap();
|
|
936
|
+
/**
|
|
937
|
+
* The LiveList class represents an ordered collection of items that is synchorinized across clients.
|
|
938
|
+
*/
|
|
728
939
|
export class LiveList extends AbstractCrdt {
|
|
729
940
|
constructor(items = []) {
|
|
730
941
|
super();
|
|
731
|
-
// TODO: Naive array at first, find a better data structure
|
|
942
|
+
// TODO: Naive array at first, find a better data structure. Maybe an Order statistics tree?
|
|
732
943
|
_LiveList_items.set(this, []);
|
|
733
944
|
let position = undefined;
|
|
734
945
|
for (let i = 0; i < items.length; i++) {
|
|
@@ -750,9 +961,9 @@ export class LiveList extends AbstractCrdt {
|
|
|
750
961
|
}
|
|
751
962
|
for (const entry of children) {
|
|
752
963
|
const child = deserialize(entry, parentToChildren, doc);
|
|
753
|
-
child.
|
|
964
|
+
child._setParentLink(list, entry[1].parentKey);
|
|
754
965
|
__classPrivateFieldGet(list, _LiveList_items, "f").push([child, entry[1].parentKey]);
|
|
755
|
-
__classPrivateFieldGet(list, _LiveList_items, "f").sort((itemA, itemB) => compare(
|
|
966
|
+
__classPrivateFieldGet(list, _LiveList_items, "f").sort((itemA, itemB) => compare(itemA[1], itemB[1]));
|
|
756
967
|
}
|
|
757
968
|
return list;
|
|
758
969
|
}
|
|
@@ -801,15 +1012,21 @@ export class LiveList extends AbstractCrdt {
|
|
|
801
1012
|
* INTERNAL
|
|
802
1013
|
*/
|
|
803
1014
|
_attachChild(id, key, child) {
|
|
1015
|
+
var _a;
|
|
804
1016
|
if (this._doc == null) {
|
|
805
1017
|
throw new Error("Can't attach child if doc is not present");
|
|
806
1018
|
}
|
|
807
1019
|
child._attach(id, this._doc);
|
|
808
|
-
child.
|
|
809
|
-
|
|
1020
|
+
child._setParentLink(this, key);
|
|
1021
|
+
const index = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((entry) => entry[1] === key);
|
|
1022
|
+
// Assign a temporary position until we get the fix from the backend
|
|
1023
|
+
if (index !== -1) {
|
|
1024
|
+
__classPrivateFieldGet(this, _LiveList_items, "f")[index][1] = makePosition(key, (_a = __classPrivateFieldGet(this, _LiveList_items, "f")[index + 1]) === null || _a === void 0 ? void 0 : _a[1]);
|
|
1025
|
+
}
|
|
810
1026
|
__classPrivateFieldGet(this, _LiveList_items, "f").push([child, key]);
|
|
811
|
-
__classPrivateFieldGet(this, _LiveList_items, "f").sort((itemA, itemB) => compare(
|
|
812
|
-
this.
|
|
1027
|
+
__classPrivateFieldGet(this, _LiveList_items, "f").sort((itemA, itemB) => compare(itemA[1], itemB[1]));
|
|
1028
|
+
this._notify();
|
|
1029
|
+
return [{ type: OpType.DeleteCrdt, id }];
|
|
813
1030
|
}
|
|
814
1031
|
/**
|
|
815
1032
|
* INTERNAL
|
|
@@ -820,49 +1037,74 @@ export class LiveList extends AbstractCrdt {
|
|
|
820
1037
|
if (child) {
|
|
821
1038
|
child._detach();
|
|
822
1039
|
}
|
|
823
|
-
this.
|
|
1040
|
+
this._notify();
|
|
824
1041
|
}
|
|
825
1042
|
/**
|
|
826
1043
|
* INTERNAL
|
|
827
1044
|
*/
|
|
828
1045
|
_setChildKey(key, child) {
|
|
1046
|
+
var _a;
|
|
1047
|
+
child._setParentLink(this, key);
|
|
1048
|
+
const index = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((entry) => entry[1] === key);
|
|
1049
|
+
// Assign a temporary position until we get the fix from the backend
|
|
1050
|
+
if (index !== -1) {
|
|
1051
|
+
__classPrivateFieldGet(this, _LiveList_items, "f")[index][1] = makePosition(key, (_a = __classPrivateFieldGet(this, _LiveList_items, "f")[index + 1]) === null || _a === void 0 ? void 0 : _a[1]);
|
|
1052
|
+
}
|
|
829
1053
|
const item = __classPrivateFieldGet(this, _LiveList_items, "f").find((item) => item[0] === child);
|
|
830
1054
|
if (item) {
|
|
831
1055
|
item[1] = key;
|
|
832
1056
|
}
|
|
833
|
-
__classPrivateFieldGet(this, _LiveList_items, "f").sort((itemA, itemB) => compare(
|
|
834
|
-
this.
|
|
1057
|
+
__classPrivateFieldGet(this, _LiveList_items, "f").sort((itemA, itemB) => compare(itemA[1], itemB[1]));
|
|
1058
|
+
this._notify();
|
|
835
1059
|
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
1060
|
+
/**
|
|
1061
|
+
* INTERNAL
|
|
1062
|
+
*/
|
|
1063
|
+
_apply(op) {
|
|
1064
|
+
return super._apply(op);
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
1067
|
+
* Returns the number of elements.
|
|
1068
|
+
*/
|
|
1069
|
+
get length() {
|
|
1070
|
+
return __classPrivateFieldGet(this, _LiveList_items, "f").length;
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* Adds one element to the end of the LiveList.
|
|
1074
|
+
* @param element The element to add to the end of the LiveList.
|
|
1075
|
+
*/
|
|
1076
|
+
push(element) {
|
|
1077
|
+
return this.insert(element, this.length);
|
|
848
1078
|
}
|
|
849
|
-
|
|
1079
|
+
/**
|
|
1080
|
+
* Inserts one element at a specified index.
|
|
1081
|
+
* @param element The element to insert.
|
|
1082
|
+
* @param index The index at which you want to insert the element.
|
|
1083
|
+
*/
|
|
1084
|
+
insert(element, index) {
|
|
850
1085
|
if (index < 0 || index > __classPrivateFieldGet(this, _LiveList_items, "f").length) {
|
|
851
1086
|
throw new Error(`Cannot delete list item at index "${index}". index should be between 0 and ${__classPrivateFieldGet(this, _LiveList_items, "f").length}`);
|
|
852
1087
|
}
|
|
853
1088
|
let before = __classPrivateFieldGet(this, _LiveList_items, "f")[index - 1] ? __classPrivateFieldGet(this, _LiveList_items, "f")[index - 1][1] : undefined;
|
|
854
1089
|
let after = __classPrivateFieldGet(this, _LiveList_items, "f")[index] ? __classPrivateFieldGet(this, _LiveList_items, "f")[index][1] : undefined;
|
|
855
1090
|
const position = makePosition(before, after);
|
|
856
|
-
const value = selfOrRegister(
|
|
857
|
-
value.
|
|
1091
|
+
const value = selfOrRegister(element);
|
|
1092
|
+
value._setParentLink(this, position);
|
|
858
1093
|
__classPrivateFieldGet(this, _LiveList_items, "f").push([value, position]);
|
|
859
|
-
__classPrivateFieldGet(this, _LiveList_items, "f").sort((itemA, itemB) => compare(
|
|
860
|
-
this.
|
|
1094
|
+
__classPrivateFieldGet(this, _LiveList_items, "f").sort((itemA, itemB) => compare(itemA[1], itemB[1]));
|
|
1095
|
+
this._notify();
|
|
861
1096
|
if (this._doc && this._id) {
|
|
862
|
-
|
|
1097
|
+
const id = this._doc.generateId();
|
|
1098
|
+
value._attach(id, this._doc);
|
|
1099
|
+
this._doc.addToUndoStack([{ type: OpType.DeleteCrdt, id }]);
|
|
863
1100
|
this._doc.dispatch(value._serialize(this._id, position));
|
|
864
1101
|
}
|
|
865
1102
|
}
|
|
1103
|
+
/**
|
|
1104
|
+
* Move one element from one index to another.
|
|
1105
|
+
* @param index The index of the element to move
|
|
1106
|
+
* @param targetIndex The index where the element should be after moving.
|
|
1107
|
+
*/
|
|
866
1108
|
move(index, targetIndex) {
|
|
867
1109
|
if (targetIndex < 0) {
|
|
868
1110
|
throw new Error("targetIndex cannot be less than 0");
|
|
@@ -892,17 +1134,32 @@ export class LiveList extends AbstractCrdt {
|
|
|
892
1134
|
}
|
|
893
1135
|
const position = makePosition(beforePosition, afterPosition);
|
|
894
1136
|
const item = __classPrivateFieldGet(this, _LiveList_items, "f")[index];
|
|
1137
|
+
const previousPosition = item[1];
|
|
895
1138
|
item[1] = position;
|
|
896
|
-
|
|
897
|
-
this.
|
|
1139
|
+
item[0]._setParentLink(this, position);
|
|
1140
|
+
__classPrivateFieldGet(this, _LiveList_items, "f").sort((itemA, itemB) => compare(itemA[1], itemB[1]));
|
|
1141
|
+
this._notify();
|
|
898
1142
|
if (this._doc && this._id) {
|
|
899
|
-
this._doc.
|
|
1143
|
+
this._doc.addToUndoStack([
|
|
1144
|
+
{
|
|
1145
|
+
type: OpType.SetParentKey,
|
|
1146
|
+
id: item[0]._id,
|
|
1147
|
+
parentKey: previousPosition,
|
|
1148
|
+
},
|
|
1149
|
+
]);
|
|
1150
|
+
this._doc.dispatch([
|
|
1151
|
+
{
|
|
900
1152
|
type: OpType.SetParentKey,
|
|
901
1153
|
id: item[0]._id,
|
|
902
1154
|
parentKey: position,
|
|
903
|
-
},
|
|
1155
|
+
},
|
|
1156
|
+
]);
|
|
904
1157
|
}
|
|
905
1158
|
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Deletes an element at the specified index
|
|
1161
|
+
* @param index The index of the element to delete
|
|
1162
|
+
*/
|
|
906
1163
|
delete(index) {
|
|
907
1164
|
if (index < 0 || index >= __classPrivateFieldGet(this, _LiveList_items, "f").length) {
|
|
908
1165
|
throw new Error(`Cannot delete list item at index "${index}". index should be between 0 and ${__classPrivateFieldGet(this, _LiveList_items, "f").length - 1}`);
|
|
@@ -913,6 +1170,7 @@ export class LiveList extends AbstractCrdt {
|
|
|
913
1170
|
if (this._doc) {
|
|
914
1171
|
const childRecordId = item[0]._id;
|
|
915
1172
|
if (childRecordId) {
|
|
1173
|
+
this._doc.addToUndoStack(item[0]._serialize(this._id, item[1]));
|
|
916
1174
|
this._doc.dispatch([
|
|
917
1175
|
{
|
|
918
1176
|
id: childRecordId,
|
|
@@ -921,38 +1179,95 @@ export class LiveList extends AbstractCrdt {
|
|
|
921
1179
|
]);
|
|
922
1180
|
}
|
|
923
1181
|
}
|
|
924
|
-
this.
|
|
1182
|
+
this._notify();
|
|
925
1183
|
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Returns an Array of all the elements in the LiveList.
|
|
1186
|
+
*/
|
|
926
1187
|
toArray() {
|
|
927
1188
|
return __classPrivateFieldGet(this, _LiveList_items, "f").map((entry) => selfOrRegisterValue(entry[0]));
|
|
928
1189
|
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Tests whether all elements pass the test implemented by the provided function.
|
|
1192
|
+
* @param predicate Function to test for each element, taking two arguments (the element and its index).
|
|
1193
|
+
* @returns true if the predicate function returns a truthy value for every element. Otherwise, false.
|
|
1194
|
+
*/
|
|
929
1195
|
every(predicate) {
|
|
930
1196
|
return this.toArray().every(predicate);
|
|
931
1197
|
}
|
|
1198
|
+
/**
|
|
1199
|
+
* Creates an array with all elements that pass the test implemented by the provided function.
|
|
1200
|
+
* @param predicate Function to test each element of the LiveList. Return a value that coerces to true to keep the element, or to false otherwise.
|
|
1201
|
+
* @returns An array with the elements that pass the test.
|
|
1202
|
+
*/
|
|
932
1203
|
filter(predicate) {
|
|
933
1204
|
return this.toArray().filter(predicate);
|
|
934
1205
|
}
|
|
1206
|
+
/**
|
|
1207
|
+
* Returns the first element that satisfies the provided testing function.
|
|
1208
|
+
* @param predicate Function to execute on each value.
|
|
1209
|
+
* @returns The value of the first element in the LiveList that satisfies the provided testing function. Otherwise, undefined is returned.
|
|
1210
|
+
*/
|
|
935
1211
|
find(predicate) {
|
|
936
1212
|
return this.toArray().find(predicate);
|
|
937
1213
|
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Returns the index of the first element in the LiveList that satisfies the provided testing function.
|
|
1216
|
+
* @param predicate Function to execute on each value until the function returns true, indicating that the satisfying element was found.
|
|
1217
|
+
* @returns The index of the first element in the LiveList that passes the test. Otherwise, -1.
|
|
1218
|
+
*/
|
|
938
1219
|
findIndex(predicate) {
|
|
939
1220
|
return this.toArray().findIndex(predicate);
|
|
940
1221
|
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Executes a provided function once for each element.
|
|
1224
|
+
* @param callbackfn Function to execute on each element.
|
|
1225
|
+
*/
|
|
941
1226
|
forEach(callbackfn) {
|
|
942
1227
|
return this.toArray().forEach(callbackfn);
|
|
943
1228
|
}
|
|
1229
|
+
/**
|
|
1230
|
+
* Get the element at the specified index.
|
|
1231
|
+
* @param index The index on the element to get.
|
|
1232
|
+
* @returns The element at the specified index or undefined.
|
|
1233
|
+
*/
|
|
944
1234
|
get(index) {
|
|
1235
|
+
if (index < 0 || index >= __classPrivateFieldGet(this, _LiveList_items, "f").length) {
|
|
1236
|
+
return undefined;
|
|
1237
|
+
}
|
|
945
1238
|
return selfOrRegisterValue(__classPrivateFieldGet(this, _LiveList_items, "f")[index][0]);
|
|
946
1239
|
}
|
|
1240
|
+
/**
|
|
1241
|
+
* Returns the first index at which a given element can be found in the LiveList, or -1 if it is not present.
|
|
1242
|
+
* @param searchElement Element to locate.
|
|
1243
|
+
* @param fromIndex The index to start the search at.
|
|
1244
|
+
* @returns The first index of the element in the LiveList; -1 if not found.
|
|
1245
|
+
*/
|
|
947
1246
|
indexOf(searchElement, fromIndex) {
|
|
948
1247
|
return this.toArray().indexOf(searchElement, fromIndex);
|
|
949
1248
|
}
|
|
1249
|
+
/**
|
|
1250
|
+
* Returns the last index at which a given element can be found in the LiveList, or -1 if it is not present. The LiveLsit is searched backwards, starting at fromIndex.
|
|
1251
|
+
* @param searchElement Element to locate.
|
|
1252
|
+
* @param fromIndex The index at which to start searching backwards.
|
|
1253
|
+
* @returns
|
|
1254
|
+
*/
|
|
950
1255
|
lastIndexOf(searchElement, fromIndex) {
|
|
951
1256
|
return this.toArray().lastIndexOf(searchElement, fromIndex);
|
|
952
1257
|
}
|
|
1258
|
+
/**
|
|
1259
|
+
* Creates an array populated with the results of calling a provided function on every element.
|
|
1260
|
+
* @param callback Function that is called for every element.
|
|
1261
|
+
* @returns An array with each element being the result of the callback function.
|
|
1262
|
+
*/
|
|
953
1263
|
map(callback) {
|
|
954
1264
|
return __classPrivateFieldGet(this, _LiveList_items, "f").map((entry, i) => callback(selfOrRegisterValue(entry[0]), i));
|
|
955
1265
|
}
|
|
1266
|
+
/**
|
|
1267
|
+
* Tests whether at least one element in the LiveList passes the test implemented by the provided function.
|
|
1268
|
+
* @param predicate Function to test for each element.
|
|
1269
|
+
* @returns true if the callback function returns a truthy value for at least one element. Otherwise, false.
|
|
1270
|
+
*/
|
|
956
1271
|
some(predicate) {
|
|
957
1272
|
return this.toArray().some(predicate);
|
|
958
1273
|
}
|