blob: c6292e37cbe5298dd6ad9dfa363fa75e79e08038 (
plain)
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
import { Deserializable } from "../client/util/SerializationHelper";
import { FieldWaiting } from "./Doc";
import { primitive, serializable } from "serializr";
import { observable, action } from "mobx";
import { DocServer } from "../client/DocServer";
import { RefField } from "./RefField";
import { ObjectField } from "./ObjectField";
import { Id, Copy, ToScriptString } from "./FieldSymbols";
import { scriptingGlobal } from "../client/util/Scripting";
import { Plugins } from "./util";
@Deserializable("proxy")
export class ProxyField<T extends RefField> extends ObjectField {
constructor();
constructor(value: T);
constructor(fieldId: string);
constructor(value?: T | string) {
super();
if (typeof value === "string") {
this.fieldId = value;
} else if (value) {
this.cache = value;
this.fieldId = value[Id];
}
}
[Copy]() {
if (this.cache) return new ProxyField<T>(this.cache);
return new ProxyField<T>(this.fieldId);
}
[ToScriptString]() {
return "invalid";
}
@serializable(primitive())
readonly fieldId: string = "";
// This getter/setter and nested object thing is
// because mobx doesn't play well with observable proxies
@observable.ref
private _cache: { readonly field: T | undefined } = { field: undefined };
private get cache(): T | undefined {
return this._cache.field;
}
private set cache(field: T | undefined) {
this._cache = { field };
}
private failed = false;
private promise?: Promise<any>;
value(): T | undefined | FieldWaiting<T> {
if (this.cache) {
return this.cache;
}
if (this.failed) {
return undefined;
}
if (!this.promise) {
this.promise = DocServer.GetRefField(this.fieldId).then(action((field: any) => {
this.promise = undefined;
this.cache = field;
if (field === undefined) this.failed = true;
return field;
}));
}
return this.promise as any;
}
}
export namespace ProxyField {
let useProxy = true;
export function DisableProxyFields() {
useProxy = false;
}
export function EnableProxyFields() {
useProxy = true;
}
export function WithoutProxy<T>(fn: () => T) {
DisableProxyFields();
try {
return fn();
} finally {
EnableProxyFields();
}
}
export function initPlugin() {
Plugins.addGetterPlugin((doc, _, value) => {
if (useProxy && value instanceof ProxyField) {
return { value: value.value() };
}
});
}
}
function prefetchValue(proxy: PrefetchProxy<RefField>) {
return proxy.value() as any;
}
@scriptingGlobal
@Deserializable("prefetch_proxy", prefetchValue)
export class PrefetchProxy<T extends RefField> extends ProxyField<T> {
}
|