multyx-client 0.1.5 → 0.1.7
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/dist/controller.js +30 -31
- package/dist/index.d.ts +2 -1
- package/dist/index.js +9 -5
- package/dist/items/index.js +6 -3
- package/dist/items/list.d.ts +13 -6
- package/dist/items/list.js +71 -20
- package/dist/items/object.d.ts +10 -4
- package/dist/items/object.js +57 -14
- package/dist/items/value.d.ts +1 -1
- package/dist/items/value.js +2 -1
- package/dist/message.d.ts +3 -15
- package/dist/message.js +4 -4
- package/multyx.js +1 -1
- package/package.json +1 -1
- package/src/controller.ts +67 -67
- package/src/index.ts +10 -7
- package/src/items/list.ts +87 -27
- package/src/items/object.ts +64 -16
- package/src/items/value.ts +3 -3
- package/src/message.ts +4 -4
- package/tsconfig.json +5 -0
package/dist/controller.js
CHANGED
|
@@ -19,7 +19,7 @@ class Controller {
|
|
|
19
19
|
};
|
|
20
20
|
document.addEventListener('keydown', e => {
|
|
21
21
|
if (this.preventDefault)
|
|
22
|
-
e.preventDefault;
|
|
22
|
+
e.preventDefault();
|
|
23
23
|
const key = e.key.toLowerCase();
|
|
24
24
|
// When holding down key
|
|
25
25
|
if (this.keys[key] && this.listening.has('keyhold')) {
|
|
@@ -40,7 +40,7 @@ class Controller {
|
|
|
40
40
|
});
|
|
41
41
|
document.addEventListener('keyup', e => {
|
|
42
42
|
if (this.preventDefault)
|
|
43
|
-
e.preventDefault;
|
|
43
|
+
e.preventDefault();
|
|
44
44
|
const key = e.key.toLowerCase();
|
|
45
45
|
delete this.keys[key];
|
|
46
46
|
delete this.keys[e.code];
|
|
@@ -52,7 +52,7 @@ class Controller {
|
|
|
52
52
|
// Mouse input events
|
|
53
53
|
document.addEventListener('mousedown', e => {
|
|
54
54
|
if (this.preventDefault)
|
|
55
|
-
e.preventDefault;
|
|
55
|
+
e.preventDefault();
|
|
56
56
|
if (this.mouseGetter) {
|
|
57
57
|
const mouse = this.mouseGetter();
|
|
58
58
|
this.mouse.x = mouse.x;
|
|
@@ -70,7 +70,7 @@ class Controller {
|
|
|
70
70
|
});
|
|
71
71
|
document.addEventListener('mouseup', e => {
|
|
72
72
|
if (this.preventDefault)
|
|
73
|
-
e.preventDefault;
|
|
73
|
+
e.preventDefault();
|
|
74
74
|
if (this.mouseGetter) {
|
|
75
75
|
const mouse = this.mouseGetter();
|
|
76
76
|
this.mouse.x = mouse.x;
|
|
@@ -88,7 +88,7 @@ class Controller {
|
|
|
88
88
|
});
|
|
89
89
|
document.addEventListener('mousemove', e => {
|
|
90
90
|
if (this.preventDefault)
|
|
91
|
-
e.preventDefault;
|
|
91
|
+
e.preventDefault();
|
|
92
92
|
if (this.mouseGetter) {
|
|
93
93
|
const mouse = this.mouseGetter();
|
|
94
94
|
this.mouse.x = mouse.x;
|
|
@@ -115,7 +115,6 @@ class Controller {
|
|
|
115
115
|
* @param anchor Anchor the origin at a specific spot on the canvas
|
|
116
116
|
*/
|
|
117
117
|
mapCanvasPosition(canvas, position) {
|
|
118
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
119
118
|
const t = 'top' in position;
|
|
120
119
|
const b = 'bottom' in position;
|
|
121
120
|
const l = 'left' in position;
|
|
@@ -180,12 +179,12 @@ class Controller {
|
|
|
180
179
|
return error(true, 'bottom');
|
|
181
180
|
position.bottom = 0;
|
|
182
181
|
if (l) {
|
|
183
|
-
|
|
184
|
-
|
|
182
|
+
position.top = Math.abs(hToW * position.left * 2);
|
|
183
|
+
position.right = -position.left;
|
|
185
184
|
}
|
|
186
185
|
else if (r) {
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
position.top = Math.abs(hToW * position.right * 2);
|
|
187
|
+
position.left = -position.right;
|
|
189
188
|
}
|
|
190
189
|
else {
|
|
191
190
|
position.left = -Math.abs(wToH * position.top / 2);
|
|
@@ -199,12 +198,12 @@ class Controller {
|
|
|
199
198
|
return error(true, 'top');
|
|
200
199
|
position.top = 0;
|
|
201
200
|
if (l) {
|
|
202
|
-
|
|
203
|
-
|
|
201
|
+
position.bottom = Math.abs(hToW * position.left * 2);
|
|
202
|
+
position.right = -position.left;
|
|
204
203
|
}
|
|
205
204
|
else if (r) {
|
|
206
|
-
|
|
207
|
-
|
|
205
|
+
position.bottom = Math.abs(hToW * position.right * 2);
|
|
206
|
+
position.left = -position.right;
|
|
208
207
|
}
|
|
209
208
|
else {
|
|
210
209
|
position.left = -Math.abs(wToH * position.bottom / 2);
|
|
@@ -218,12 +217,12 @@ class Controller {
|
|
|
218
217
|
return error(true, 'left');
|
|
219
218
|
position.left = 0;
|
|
220
219
|
if (t) {
|
|
221
|
-
|
|
222
|
-
|
|
220
|
+
position.right = -Math.abs(wToH * position.top * 2);
|
|
221
|
+
position.bottom = -position.top;
|
|
223
222
|
}
|
|
224
223
|
else if (b) {
|
|
225
|
-
|
|
226
|
-
|
|
224
|
+
position.right = Math.abs(wToH * position.bottom * 2);
|
|
225
|
+
position.top = -position.bottom;
|
|
227
226
|
}
|
|
228
227
|
else {
|
|
229
228
|
position.top = -Math.abs(hToW * position.right / 2);
|
|
@@ -237,12 +236,12 @@ class Controller {
|
|
|
237
236
|
return error(true, 'right');
|
|
238
237
|
position.right = 0;
|
|
239
238
|
if (t) {
|
|
240
|
-
|
|
241
|
-
|
|
239
|
+
position.left = -Math.abs(wToH * position.top * 2);
|
|
240
|
+
position.bottom = -position.top;
|
|
242
241
|
}
|
|
243
242
|
else if (b) {
|
|
244
|
-
|
|
245
|
-
|
|
243
|
+
position.left = Math.abs(wToH * position.bottom * 2);
|
|
244
|
+
position.top = -position.bottom;
|
|
246
245
|
}
|
|
247
246
|
else {
|
|
248
247
|
position.top = -Math.abs(hToW * position.right / 2);
|
|
@@ -294,14 +293,14 @@ class Controller {
|
|
|
294
293
|
position.left = Math.abs(wToH * position.top);
|
|
295
294
|
}
|
|
296
295
|
const ctx = canvas.getContext("2d");
|
|
297
|
-
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
296
|
+
ctx === null || ctx === void 0 ? void 0 : ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
298
297
|
canvas.width = Math.floor(Math.abs(position.right - position.left));
|
|
299
298
|
canvas.height = Math.floor(Math.abs(position.bottom - position.top));
|
|
300
299
|
if (position.right < position.left)
|
|
301
|
-
ctx.scale(-1, 1);
|
|
300
|
+
ctx === null || ctx === void 0 ? void 0 : ctx.scale(-1, 1);
|
|
302
301
|
if (position.top > position.bottom)
|
|
303
|
-
ctx.scale(1, -1);
|
|
304
|
-
ctx.translate(-position.left, -position.top);
|
|
302
|
+
ctx === null || ctx === void 0 ? void 0 : ctx.scale(1, -1);
|
|
303
|
+
ctx === null || ctx === void 0 ? void 0 : ctx.translate(-position.left, -position.top);
|
|
305
304
|
}
|
|
306
305
|
/**
|
|
307
306
|
* @param centerX Anchor x-value corresponding to mouse position x-value of 0
|
|
@@ -329,15 +328,15 @@ class Controller {
|
|
|
329
328
|
*/
|
|
330
329
|
mapMouseToCanvas(canvas) {
|
|
331
330
|
const ctx = canvas.getContext("2d");
|
|
332
|
-
const transform = ctx.getTransform();
|
|
331
|
+
const transform = ctx === null || ctx === void 0 ? void 0 : ctx.getTransform();
|
|
333
332
|
const bounding = canvas.getBoundingClientRect();
|
|
334
333
|
// Ratio between canvas scale to unit pixels
|
|
335
334
|
const canvasRatioX = bounding.width / canvas.width;
|
|
336
335
|
const canvasRatioY = bounding.height / canvas.height;
|
|
337
|
-
this.mouse.centerX = bounding.left + transform.e * canvasRatioX;
|
|
338
|
-
this.mouse.centerY = bounding.top + transform.f * canvasRatioY;
|
|
339
|
-
this.mouse.scaleX = canvasRatioX * transform.a;
|
|
340
|
-
this.mouse.scaleY = canvasRatioY * transform.d;
|
|
336
|
+
this.mouse.centerX = bounding.left + (transform === null || transform === void 0 ? void 0 : transform.e) * canvasRatioX;
|
|
337
|
+
this.mouse.centerY = bounding.top + (transform === null || transform === void 0 ? void 0 : transform.f) * canvasRatioY;
|
|
338
|
+
this.mouse.scaleX = canvasRatioX * (transform === null || transform === void 0 ? void 0 : transform.a);
|
|
339
|
+
this.mouse.scaleY = canvasRatioY * (transform === null || transform === void 0 ? void 0 : transform.d);
|
|
341
340
|
}
|
|
342
341
|
/**
|
|
343
342
|
* Utilize mouse coordinates of another object
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Add, Done } from './utils';
|
|
1
|
+
import { Add, Done, Interpolate } from './utils';
|
|
2
2
|
import { RawObject } from "./types";
|
|
3
3
|
import { Controller } from "./controller";
|
|
4
4
|
import { MultyxClientObject } from "./items";
|
|
@@ -27,6 +27,7 @@ export default class Multyx {
|
|
|
27
27
|
static Native: symbol;
|
|
28
28
|
static Custom: symbol;
|
|
29
29
|
static Any: symbol;
|
|
30
|
+
static Interpolate: typeof Interpolate;
|
|
30
31
|
constructor(options?: Options, callback?: () => void);
|
|
31
32
|
/**
|
|
32
33
|
* Listen for a message from the server
|
package/dist/index.js
CHANGED
|
@@ -12,8 +12,10 @@ class Multyx {
|
|
|
12
12
|
// Queue of functions to be called after each frame
|
|
13
13
|
this[_a] = [];
|
|
14
14
|
this.options = Object.assign(Object.assign({}, options_1.DefaultOptions), options);
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
if (!this.options.uri)
|
|
16
|
+
throw new Error('URI is required');
|
|
17
|
+
const uri = `ws${this.options.secure ? 's' : ''}://${this.options.uri.split('/')[0]}:${this.options.port}/${(_b = this.options.uri.split('/')[1]) !== null && _b !== void 0 ? _b : ''}`;
|
|
18
|
+
this.ws = new WebSocket(uri);
|
|
17
19
|
this.ping = 0;
|
|
18
20
|
this.space = 'default';
|
|
19
21
|
this.events = new Map();
|
|
@@ -108,7 +110,7 @@ class Multyx {
|
|
|
108
110
|
* @param msg Message to parse
|
|
109
111
|
*/
|
|
110
112
|
parseNativeEvent(msg) {
|
|
111
|
-
var _b, _c, _d, _e;
|
|
113
|
+
var _b, _c, _d, _e, _f;
|
|
112
114
|
msg.data = msg.data.map(message_1.UncompressUpdate);
|
|
113
115
|
if (this.options.logUpdateFrame)
|
|
114
116
|
console.log(msg.data);
|
|
@@ -172,9 +174,10 @@ class Multyx {
|
|
|
172
174
|
}
|
|
173
175
|
// Response to client
|
|
174
176
|
case 'resp': {
|
|
175
|
-
const promiseResolve = this.events.get(Symbol.for("_" + update.name))[0];
|
|
177
|
+
const promiseResolve = (_f = this.events.get(Symbol.for("_" + update.name))) === null || _f === void 0 ? void 0 : _f[0];
|
|
176
178
|
this.events.delete(Symbol.for("_" + update.name));
|
|
177
|
-
|
|
179
|
+
if (promiseResolve)
|
|
180
|
+
this[utils_1.Done].push(() => promiseResolve(update.response));
|
|
178
181
|
break;
|
|
179
182
|
}
|
|
180
183
|
default: {
|
|
@@ -256,4 +259,5 @@ Multyx.Edit = Symbol('edit');
|
|
|
256
259
|
Multyx.Native = Symbol('native');
|
|
257
260
|
Multyx.Custom = Symbol('custom');
|
|
258
261
|
Multyx.Any = Symbol('any');
|
|
262
|
+
Multyx.Interpolate = utils_1.Interpolate;
|
|
259
263
|
exports.default = Multyx;
|
package/dist/items/index.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.MultyxClientValue = exports.MultyxClientObject = exports.MultyxClientList = void 0;
|
|
4
7
|
exports.IsMultyxClientItem = IsMultyxClientItem;
|
|
5
|
-
const list_1 = require("./list");
|
|
8
|
+
const list_1 = __importDefault(require("./list"));
|
|
6
9
|
exports.MultyxClientList = list_1.default;
|
|
7
|
-
const object_1 = require("./object");
|
|
10
|
+
const object_1 = __importDefault(require("./object"));
|
|
8
11
|
exports.MultyxClientObject = object_1.default;
|
|
9
|
-
const value_1 = require("./value");
|
|
12
|
+
const value_1 = __importDefault(require("./value"));
|
|
10
13
|
exports.MultyxClientValue = value_1.default;
|
|
11
14
|
function IsMultyxClientItem(value) {
|
|
12
15
|
return value instanceof list_1.default || value instanceof object_1.default || value instanceof value_1.default;
|
package/dist/items/list.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import Multyx from '../';
|
|
2
2
|
import { type MultyxClientItem, type MultyxClientObject, MultyxClientValue } from '.';
|
|
3
|
-
import { EditWrapper, Unpack } from '../utils';
|
|
3
|
+
import { Edit, EditWrapper, Unpack } from '../utils';
|
|
4
4
|
export default class MultyxClientList {
|
|
5
|
+
readonly type = "list";
|
|
5
6
|
protected list: MultyxClientItem[];
|
|
6
7
|
private multyx;
|
|
7
8
|
propertyPath: string[];
|
|
@@ -21,9 +22,10 @@ export default class MultyxClientList {
|
|
|
21
22
|
* @param shift Shift amount, positive for right, negative for left
|
|
22
23
|
*/
|
|
23
24
|
private handleShiftOperation;
|
|
24
|
-
|
|
25
|
+
[index: number]: MultyxClientItem | undefined;
|
|
26
|
+
constructor(multyx: Multyx, list: any[] | EditWrapper<any[]>, propertyPath: string[] | undefined, editable: boolean);
|
|
25
27
|
has(index: number): boolean;
|
|
26
|
-
get(index: number | string[]): MultyxClientItem;
|
|
28
|
+
get(index: number | string[]): MultyxClientItem | undefined;
|
|
27
29
|
private recursiveSet;
|
|
28
30
|
set(index: number | string[], value: any): boolean;
|
|
29
31
|
delete(index: number, native?: boolean): boolean;
|
|
@@ -34,9 +36,9 @@ export default class MultyxClientList {
|
|
|
34
36
|
*/
|
|
35
37
|
await(index: number): Promise<unknown>;
|
|
36
38
|
push(...items: any): number;
|
|
37
|
-
pop(): MultyxClientItem |
|
|
39
|
+
pop(): MultyxClientItem | undefined;
|
|
38
40
|
unshift(...items: any[]): number;
|
|
39
|
-
shift(): MultyxClientList | MultyxClientObject | MultyxClientValue;
|
|
41
|
+
shift(): MultyxClientList | MultyxClientObject | MultyxClientValue | undefined;
|
|
40
42
|
slice(start?: number, end?: number): (MultyxClientList | MultyxClientObject | MultyxClientValue)[];
|
|
41
43
|
splice(start: number, deleteCount?: number, ...items: any[]): (MultyxClientList | MultyxClientObject | MultyxClientValue)[];
|
|
42
44
|
setSplice(start: number, deleteCount?: number, ...items: any[]): void;
|
|
@@ -51,13 +53,18 @@ export default class MultyxClientList {
|
|
|
51
53
|
forEach(callbackfn: (value: any, index: number, array: MultyxClientList) => void): void;
|
|
52
54
|
every(predicate: (value: any, index: number, array: MultyxClientList) => boolean): boolean;
|
|
53
55
|
some(predicate: (value: any, index: number, array: MultyxClientList) => boolean): boolean;
|
|
54
|
-
find(predicate: (value: any, index: number, array: MultyxClientList) => boolean): MultyxClientList | MultyxClientObject | MultyxClientValue;
|
|
56
|
+
find(predicate: (value: any, index: number, array: MultyxClientList) => boolean): MultyxClientList | MultyxClientObject | MultyxClientValue | undefined;
|
|
55
57
|
findIndex(predicate: (value: any, index: number, array: MultyxClientList) => boolean): number;
|
|
56
58
|
entries(): [any, number][];
|
|
57
59
|
keys(): number[];
|
|
60
|
+
[Edit](): void;
|
|
58
61
|
[Unpack](constraints: any[]): void;
|
|
59
62
|
[Symbol.iterator](): Iterator<MultyxClientItem>;
|
|
60
63
|
toString: () => string;
|
|
61
64
|
valueOf: () => any[];
|
|
62
65
|
[Symbol.toPrimitive]: () => any[];
|
|
66
|
+
hydrateFromServer(values: any[]): void;
|
|
67
|
+
private tryApplyServerValue;
|
|
68
|
+
private notifyIndexWaiters;
|
|
69
|
+
private enqueueEditCallbacks;
|
|
63
70
|
}
|
package/dist/items/list.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
var _a;
|
|
3
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
7
|
const _1 = require(".");
|
|
5
8
|
const utils_1 = require("../utils");
|
|
6
|
-
const router_1 = require("./router");
|
|
9
|
+
const router_1 = __importDefault(require("./router"));
|
|
7
10
|
const message_1 = require("../message");
|
|
11
|
+
const isPlainObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
8
12
|
class MultyxClientList {
|
|
9
13
|
addEditCallback(callback) {
|
|
10
14
|
this.editCallbacks.push(callback);
|
|
@@ -70,6 +74,7 @@ class MultyxClientList {
|
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
76
|
constructor(multyx, list, propertyPath = [], editable) {
|
|
77
|
+
this.type = 'list';
|
|
73
78
|
this.editCallbacks = [];
|
|
74
79
|
this.toString = () => this.value.toString();
|
|
75
80
|
this.valueOf = () => this.value;
|
|
@@ -148,6 +153,9 @@ class MultyxClientList {
|
|
|
148
153
|
this.set(parseInt(path[0]), new utils_1.EditWrapper({}));
|
|
149
154
|
next = this.get(parseInt(path[0]));
|
|
150
155
|
}
|
|
156
|
+
if (!next || next instanceof _1.MultyxClientValue) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
151
159
|
return next.set(path.slice(1), value);
|
|
152
160
|
}
|
|
153
161
|
set(index, value) {
|
|
@@ -156,31 +164,28 @@ class MultyxClientList {
|
|
|
156
164
|
const oldValue = this.get(index);
|
|
157
165
|
const serverSet = value instanceof utils_1.EditWrapper;
|
|
158
166
|
const allowed = serverSet || this.editable;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
if (value === undefined)
|
|
167
|
+
const incoming = (serverSet || (0, _1.IsMultyxClientItem)(value)) ? value.value : value;
|
|
168
|
+
if (incoming === undefined)
|
|
162
169
|
return this.delete(index, serverSet);
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
170
|
+
if (serverSet && this.tryApplyServerValue(index, incoming, oldValue)) {
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
// If value is a MultyxClientValue, set the value directly
|
|
174
|
+
if (this.list[index] instanceof _1.MultyxClientValue && (typeof incoming !== 'object' || incoming === null)) {
|
|
175
|
+
const result = this.list[index].set(serverSet ? new utils_1.EditWrapper(incoming) : incoming);
|
|
176
|
+
this.enqueueEditCallbacks(index, oldValue);
|
|
177
|
+
return result;
|
|
166
178
|
}
|
|
167
179
|
// Attempting to edit property not editable to client
|
|
168
180
|
if (!allowed) {
|
|
169
181
|
if (this.multyx.options.verbose) {
|
|
170
|
-
console.error(`Attempting to set property that is not editable. Setting '${this.propertyPath.join('.') + '.' + index}' to ${
|
|
182
|
+
console.error(`Attempting to set property that is not editable. Setting '${this.propertyPath.join('.') + '.' + index}' to ${incoming}`);
|
|
171
183
|
}
|
|
172
184
|
return false;
|
|
173
185
|
}
|
|
174
|
-
this.list[index] = new ((0, router_1.default)(
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
this.multyx[utils_1.Done].push(...this.multyx.events.get(propSymbol).map(e => () => e(this.list[index])));
|
|
178
|
-
}
|
|
179
|
-
// We have to push into queue, since object may not be fully created
|
|
180
|
-
// and there may still be more updates to parse
|
|
181
|
-
for (const listener of this.editCallbacks) {
|
|
182
|
-
this.multyx[utils_1.Add](() => listener(index, this.get(index), oldValue));
|
|
183
|
-
}
|
|
186
|
+
this.list[index] = new ((0, router_1.default)(incoming))(this.multyx, serverSet ? new utils_1.EditWrapper(incoming) : incoming, [...this.propertyPath, index.toString()], this.editable);
|
|
187
|
+
this.notifyIndexWaiters(index);
|
|
188
|
+
this.enqueueEditCallbacks(index, oldValue);
|
|
184
189
|
return true;
|
|
185
190
|
}
|
|
186
191
|
delete(index, native = false) {
|
|
@@ -225,7 +230,7 @@ class MultyxClientList {
|
|
|
225
230
|
}
|
|
226
231
|
pop() {
|
|
227
232
|
if (this.length === 0)
|
|
228
|
-
return
|
|
233
|
+
return undefined;
|
|
229
234
|
const res = this.get(this.length);
|
|
230
235
|
this.delete(this.length);
|
|
231
236
|
return res;
|
|
@@ -255,7 +260,7 @@ class MultyxClientList {
|
|
|
255
260
|
return this.list.slice(start, end);
|
|
256
261
|
}
|
|
257
262
|
splice(start, deleteCount, ...items) {
|
|
258
|
-
return this.list.splice(start, deleteCount, ...items);
|
|
263
|
+
return this.list.splice(start, deleteCount !== null && deleteCount !== void 0 ? deleteCount : 0, ...items);
|
|
259
264
|
}
|
|
260
265
|
setSplice(start, deleteCount, ...items) {
|
|
261
266
|
if (deleteCount === undefined) {
|
|
@@ -385,6 +390,7 @@ class MultyxClientList {
|
|
|
385
390
|
keys() {
|
|
386
391
|
return Array(this.length).fill(0).map((_, i) => i);
|
|
387
392
|
}
|
|
393
|
+
[utils_1.Edit]() { }
|
|
388
394
|
[utils_1.Unpack](constraints) {
|
|
389
395
|
var _b;
|
|
390
396
|
for (let i = 0; i < this.length; i++) {
|
|
@@ -398,6 +404,51 @@ class MultyxClientList {
|
|
|
398
404
|
values[i] = this.get(i);
|
|
399
405
|
return values[Symbol.iterator]();
|
|
400
406
|
}
|
|
407
|
+
hydrateFromServer(values) {
|
|
408
|
+
if (!Array.isArray(values))
|
|
409
|
+
return;
|
|
410
|
+
for (let i = 0; i < values.length; i++) {
|
|
411
|
+
this.set(i, new utils_1.EditWrapper(values[i]));
|
|
412
|
+
}
|
|
413
|
+
for (let i = values.length; i < this.length; i++) {
|
|
414
|
+
this.delete(i, true);
|
|
415
|
+
}
|
|
416
|
+
this.length = values.length;
|
|
417
|
+
}
|
|
418
|
+
tryApplyServerValue(index, incoming, oldValue) {
|
|
419
|
+
const current = this.list[index];
|
|
420
|
+
if (!current)
|
|
421
|
+
return false;
|
|
422
|
+
if (current instanceof _1.MultyxClientValue && (typeof incoming !== 'object' || incoming === null)) {
|
|
423
|
+
current.set(new utils_1.EditWrapper(incoming));
|
|
424
|
+
this.enqueueEditCallbacks(index, oldValue);
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
427
|
+
const canHydrate = typeof (current === null || current === void 0 ? void 0 : current.hydrateFromServer) === 'function';
|
|
428
|
+
if (Array.isArray(incoming) && canHydrate && current.type === 'list') {
|
|
429
|
+
current.hydrateFromServer(incoming);
|
|
430
|
+
this.enqueueEditCallbacks(index, oldValue);
|
|
431
|
+
return true;
|
|
432
|
+
}
|
|
433
|
+
if (isPlainObject(incoming) && canHydrate && current.type === 'object') {
|
|
434
|
+
current.hydrateFromServer(incoming);
|
|
435
|
+
this.enqueueEditCallbacks(index, oldValue);
|
|
436
|
+
return true;
|
|
437
|
+
}
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
notifyIndexWaiters(index) {
|
|
441
|
+
var _b, _c;
|
|
442
|
+
const propSymbol = Symbol.for("_" + this.propertyPath.join('.') + '.' + index);
|
|
443
|
+
if (this.multyx.events.has(propSymbol)) {
|
|
444
|
+
this.multyx[utils_1.Done].push(...((_c = (_b = this.multyx.events.get(propSymbol)) === null || _b === void 0 ? void 0 : _b.map(e => () => e(this.list[index]))) !== null && _c !== void 0 ? _c : []));
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
enqueueEditCallbacks(index, oldValue) {
|
|
448
|
+
for (const listener of this.editCallbacks) {
|
|
449
|
+
this.multyx[utils_1.Add](() => listener(index, this.get(index), oldValue));
|
|
450
|
+
}
|
|
451
|
+
}
|
|
401
452
|
}
|
|
402
453
|
_a = Symbol.toPrimitive;
|
|
403
454
|
exports.default = MultyxClientList;
|
package/dist/items/object.d.ts
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import { RawObject } from '../types';
|
|
2
2
|
import { Edit, EditWrapper, Unpack } from "../utils";
|
|
3
3
|
import type Multyx from '../index';
|
|
4
|
-
import { type MultyxClientItem } from ".";
|
|
4
|
+
import { type MultyxClientList, type MultyxClientItem } from ".";
|
|
5
|
+
import MultyxClientValue from "./value";
|
|
5
6
|
export default class MultyxClientObject {
|
|
7
|
+
readonly type = "object";
|
|
6
8
|
protected object: RawObject<MultyxClientItem>;
|
|
7
9
|
private multyx;
|
|
8
10
|
propertyPath: string[];
|
|
9
11
|
editable: boolean;
|
|
10
12
|
private editCallbacks;
|
|
11
|
-
get value():
|
|
13
|
+
get value(): RawObject<MultyxClientList | MultyxClientObject | MultyxClientValue>;
|
|
12
14
|
addEditCallback(callback: (key: any, value: any) => void): void;
|
|
13
15
|
[Edit](updatePath: string[], value: any): void;
|
|
14
|
-
|
|
16
|
+
[key: string]: any;
|
|
17
|
+
constructor(multyx: Multyx, object: RawObject | EditWrapper<RawObject>, propertyPath: string[] | undefined, editable: boolean);
|
|
15
18
|
has(property: any): boolean;
|
|
16
|
-
get(property: string | string[]): MultyxClientItem;
|
|
19
|
+
get(property: string | string[]): MultyxClientItem | undefined;
|
|
17
20
|
private recursiveSet;
|
|
18
21
|
set(property: string | string[], value: any): boolean;
|
|
19
22
|
delete(property: any, native?: boolean): boolean;
|
|
@@ -31,4 +34,7 @@ export default class MultyxClientObject {
|
|
|
31
34
|
* @param constraints Packed constraints object mirroring MultyxClientObject shape
|
|
32
35
|
*/
|
|
33
36
|
[Unpack](constraints: RawObject): void;
|
|
37
|
+
hydrateFromServer(value: RawObject): void;
|
|
38
|
+
private applyServerValue;
|
|
39
|
+
private notifyPropertyWaiters;
|
|
34
40
|
}
|
package/dist/items/object.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
const message_1 = require("../message");
|
|
4
7
|
const utils_1 = require("../utils");
|
|
5
8
|
const _1 = require(".");
|
|
6
|
-
const router_1 = require("./router");
|
|
7
|
-
const value_1 = require("./value");
|
|
9
|
+
const router_1 = __importDefault(require("./router"));
|
|
10
|
+
const value_1 = __importDefault(require("./value"));
|
|
11
|
+
const isPlainObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
8
12
|
class MultyxClientObject {
|
|
9
13
|
get value() {
|
|
10
14
|
const parsed = {};
|
|
@@ -16,6 +20,7 @@ class MultyxClientObject {
|
|
|
16
20
|
this.editCallbacks.push(callback);
|
|
17
21
|
}
|
|
18
22
|
[utils_1.Edit](updatePath, value) {
|
|
23
|
+
var _a;
|
|
19
24
|
if (updatePath.length == 1) {
|
|
20
25
|
this.set(updatePath[0], new utils_1.EditWrapper(value));
|
|
21
26
|
return;
|
|
@@ -26,9 +31,10 @@ class MultyxClientObject {
|
|
|
26
31
|
if (!this.has(updatePath[0])) {
|
|
27
32
|
this.set(updatePath[0], new utils_1.EditWrapper({}));
|
|
28
33
|
}
|
|
29
|
-
this.get(updatePath[0])[utils_1.Edit](updatePath.slice(1), value);
|
|
34
|
+
(_a = this.get(updatePath[0])) === null || _a === void 0 ? void 0 : _a[utils_1.Edit](updatePath.slice(1), value);
|
|
30
35
|
}
|
|
31
36
|
constructor(multyx, object, propertyPath = [], editable) {
|
|
37
|
+
this.type = 'object';
|
|
32
38
|
this.editCallbacks = [];
|
|
33
39
|
this.object = {};
|
|
34
40
|
this.propertyPath = propertyPath;
|
|
@@ -109,27 +115,26 @@ class MultyxClientObject {
|
|
|
109
115
|
return this.recursiveSet(property, value);
|
|
110
116
|
const serverSet = value instanceof utils_1.EditWrapper;
|
|
111
117
|
const allowed = serverSet || this.editable;
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (value === undefined)
|
|
118
|
+
const incoming = (serverSet || (0, _1.IsMultyxClientItem)(value)) ? value.value : value;
|
|
119
|
+
if (incoming === undefined)
|
|
115
120
|
return this.delete(property, serverSet);
|
|
121
|
+
if (serverSet && this.applyServerValue(property, incoming)) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
116
124
|
// Only create new MultyxClientItem when needed
|
|
117
|
-
if (this.object[property] instanceof value_1.default && typeof
|
|
118
|
-
return this.object[property].set(serverSet ? new utils_1.EditWrapper(
|
|
125
|
+
if (this.object[property] instanceof value_1.default && (typeof incoming !== 'object' || incoming === null)) {
|
|
126
|
+
return this.object[property].set(serverSet ? new utils_1.EditWrapper(incoming) : incoming);
|
|
119
127
|
}
|
|
120
128
|
// Attempting to edit property not editable to client
|
|
121
129
|
if (!allowed) {
|
|
122
130
|
if (this.multyx.options.verbose) {
|
|
123
|
-
console.error(`Attempting to set property that is not editable. Setting '${this.propertyPath.join('.') + '.' + property}' to ${
|
|
131
|
+
console.error(`Attempting to set property that is not editable. Setting '${this.propertyPath.join('.') + '.' + property}' to ${incoming}`);
|
|
124
132
|
}
|
|
125
133
|
return false;
|
|
126
134
|
}
|
|
127
135
|
// Creating a new value
|
|
128
|
-
this.object[property] = new ((0, router_1.default)(
|
|
129
|
-
|
|
130
|
-
if (this.multyx.events.has(propSymbol)) {
|
|
131
|
-
this.multyx[utils_1.Done].push(...this.multyx.events.get(propSymbol).map(e => () => e(this.object[property])));
|
|
132
|
-
}
|
|
136
|
+
this.object[property] = new ((0, router_1.default)(incoming))(this.multyx, serverSet ? new utils_1.EditWrapper(incoming) : incoming, [...this.propertyPath, property], this.editable);
|
|
137
|
+
this.notifyPropertyWaiters(property);
|
|
133
138
|
return true;
|
|
134
139
|
}
|
|
135
140
|
delete(property, native = false) {
|
|
@@ -184,5 +189,43 @@ class MultyxClientObject {
|
|
|
184
189
|
(_a = this.object[prop]) === null || _a === void 0 ? void 0 : _a[utils_1.Unpack](constraints[prop]);
|
|
185
190
|
}
|
|
186
191
|
}
|
|
192
|
+
hydrateFromServer(value) {
|
|
193
|
+
if (!isPlainObject(value))
|
|
194
|
+
return;
|
|
195
|
+
const remaining = new Set(Object.keys(this.object));
|
|
196
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
197
|
+
remaining.delete(key);
|
|
198
|
+
this.set(key, new utils_1.EditWrapper(entry));
|
|
199
|
+
}
|
|
200
|
+
for (const key of remaining) {
|
|
201
|
+
this.delete(key, true);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
applyServerValue(property, incoming) {
|
|
205
|
+
const current = this.object[property];
|
|
206
|
+
if (!current)
|
|
207
|
+
return false;
|
|
208
|
+
if (current instanceof value_1.default && (typeof incoming !== 'object' || incoming === null)) {
|
|
209
|
+
current.set(new utils_1.EditWrapper(incoming));
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
const canHydrate = typeof (current === null || current === void 0 ? void 0 : current.hydrateFromServer) === 'function';
|
|
213
|
+
if (Array.isArray(incoming) && canHydrate && current.type === 'list') {
|
|
214
|
+
current.hydrateFromServer(incoming);
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
if (isPlainObject(incoming) && canHydrate && current.type === 'object') {
|
|
218
|
+
current.hydrateFromServer(incoming);
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
notifyPropertyWaiters(property) {
|
|
224
|
+
var _a, _b;
|
|
225
|
+
const propSymbol = Symbol.for("_" + this.propertyPath.join('.') + '.' + property);
|
|
226
|
+
if (this.multyx.events.has(propSymbol)) {
|
|
227
|
+
this.multyx[utils_1.Done].push(...((_b = (_a = this.multyx.events.get(propSymbol)) === null || _a === void 0 ? void 0 : _a.map(e => () => e(this.object[property]))) !== null && _b !== void 0 ? _b : []));
|
|
228
|
+
}
|
|
229
|
+
}
|
|
187
230
|
}
|
|
188
231
|
exports.default = MultyxClientObject;
|
package/dist/items/value.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export default class MultyxClientValue {
|
|
|
16
16
|
addReadModifier(modifier: (value: Value) => Value): void;
|
|
17
17
|
addEditCallback(callback: (value: Value, previousValue: Value) => void): void;
|
|
18
18
|
[Edit](updatePath: string[], value: any): void;
|
|
19
|
-
constructor(multyx: Multyx, value: Value | EditWrapper<Value>, propertyPath: string[], editable: boolean);
|
|
19
|
+
constructor(multyx: Multyx, value: Value | EditWrapper<Value>, propertyPath: string[] | undefined, editable: boolean);
|
|
20
20
|
set(value: Value | EditWrapper<Value>): boolean;
|
|
21
21
|
bindElement(element: HTMLElement): void;
|
|
22
22
|
/**
|
package/dist/items/value.js
CHANGED
|
@@ -22,6 +22,7 @@ class MultyxClientValue {
|
|
|
22
22
|
this.set(new utils_1.EditWrapper(value));
|
|
23
23
|
}
|
|
24
24
|
constructor(multyx, value, propertyPath = [], editable) {
|
|
25
|
+
var _b, _c;
|
|
25
26
|
this.readModifiers = [];
|
|
26
27
|
this.editCallbacks = [];
|
|
27
28
|
/* Native methods to allow MultyxValue to be treated as primitive */
|
|
@@ -35,7 +36,7 @@ class MultyxClientValue {
|
|
|
35
36
|
this.set(value);
|
|
36
37
|
const propSymbol = Symbol.for("_" + this.propertyPath.join('.'));
|
|
37
38
|
if (this.multyx.events.has(propSymbol)) {
|
|
38
|
-
this.multyx[utils_1.Done].push(...this.multyx.events.get(propSymbol).map(e => () => e(this.value)));
|
|
39
|
+
this.multyx[utils_1.Done].push(...((_c = (_b = this.multyx.events.get(propSymbol)) === null || _b === void 0 ? void 0 : _b.map(e => () => e(this.value))) !== null && _c !== void 0 ? _c : []));
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
set(value) {
|