1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
import { UndoManager } from "../client/util/UndoManager";
import { Update, OnUpdate, Parent, ObjectField, RefField, Doc, Id, Field } from "./Doc";
import { SerializationHelper } from "../client/util/SerializationHelper";
import { ProxyField } from "./Proxy";
export function setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean {
if (SerializationHelper.IsSerializing()) {
target[prop] = value;
return true;
}
if (typeof prop === "symbol") {
target[prop] = value;
return true;
}
const curValue = target.__fields[prop];
if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value[Id])) {
// TODO This kind of checks correctly in the case that curValue is a ProxyField and value is a RefField, but technically
// curValue should get filled in with value if it isn't already filled in, in case we fetched the referenced field some other way
return true;
}
if (value instanceof RefField) {
value = new ProxyField(value);
}
if (value instanceof ObjectField) {
if (value[Parent] && value[Parent] !== target) {
throw new Error("Can't put the same object in multiple documents at the same time");
}
value[Parent] = target;
value[OnUpdate] = (diff?: any) => {
if (!diff) diff = SerializationHelper.Serialize(value);
target[Update]({ [prop]: diff });
};
}
if (curValue instanceof ObjectField) {
delete curValue[Parent];
delete curValue[OnUpdate];
}
target.__fields[prop] = value;
target[Update]({ ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) });
UndoManager.AddEvent({
redo: () => receiver[prop] = value,
undo: () => receiver[prop] = curValue
});
return true;
}
export function getter(target: any, prop: string | symbol | number, receiver: any): any {
if (typeof prop === "symbol") {
return target.__fields[prop] || target[prop];
}
if (SerializationHelper.IsSerializing()) {
return target[prop];
}
return getField(target, prop, receiver);
}
export function getField(target: any, prop: string | number, ignoreProto: boolean = false, callback?: (field: Field | undefined) => void): any {
const field = target.__fields[prop];
if (field instanceof ProxyField) {
return field.value(callback);
}
if (field === undefined && !ignoreProto) {
const proto = getField(target, "prototype", true);
if (proto instanceof Doc) {
let field = proto[prop];
callback && callback(field === null ? undefined : field);
return field;
}
}
callback && callback(field);
return field;
}
|