aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/DocServer.ts56
-rw-r--r--src/client/documents/Documents.ts10
-rw-r--r--src/client/util/LinkManager.ts13
-rw-r--r--src/client/util/SerializationHelper.ts4
-rw-r--r--src/client/views/TemplateMenu.tsx2
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx28
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx2
-rw-r--r--src/client/views/nodes/ImageBox.tsx31
-rw-r--r--src/client/views/nodes/KeyValuePair.tsx17
-rw-r--r--src/debug/Test.tsx88
-rw-r--r--src/new_fields/Doc.ts13
-rw-r--r--src/new_fields/Proxy.ts29
-rw-r--r--src/new_fields/ScriptField.ts12
-rw-r--r--src/new_fields/util.ts5
14 files changed, 153 insertions, 157 deletions
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index fc39fa364..87a87be92 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -124,13 +124,12 @@ export namespace DocServer {
// future .proto calls on the Doc won't have to go farther than the cache to get their actual value.
const deserializeField = getSerializedField.then(async fieldJson => {
// deserialize
- const field = await SerializationHelper.Deserialize(fieldJson, val => {
- if (val !== undefined) {
- _cache[id] = val;
- } else {
- delete _cache[id];
- }
- });
+ const field = await SerializationHelper.Deserialize(fieldJson);
+ if (field !== undefined) {
+ _cache[id] = field;
+ } else {
+ delete _cache[id];
+ }
return field;
// either way, overwrite or delete any promises cached at this id (that we inserted as flags
// to indicate that the field was in the process of being fetched). Now everything
@@ -214,36 +213,37 @@ export namespace DocServer {
// future .proto calls on the Doc won't have to go farther than the cache to get their actual value.
const deserializeFields = getSerializedFields.then(async fields => {
const fieldMap: { [id: string]: RefField } = {};
- // const protosToLoad: any = [];
- const proms: Promise<RefField>[] = [];
+ const proms: Promise<void>[] = [];
for (const field of fields) {
if (field !== undefined) {
// deserialize
- let prom = SerializationHelper.Deserialize(field, val => {
- if (val !== undefined) {
- _cache[field.id] = field;
+ let prom = SerializationHelper.Deserialize(field).then(deserialized => {
+ fieldMap[field.id] = deserialized;
+
+ //overwrite or delete any promises (that we inserted as flags
+ // to indicate that the field was in the process of being fetched). Now everything
+ // should be an actual value within or entirely absent from the cache.
+ if (deserialized !== undefined) {
+ _cache[field.id] = deserialized;
} else {
delete _cache[field.id];
}
- }).then(deserialized => fieldMap[field.id] = deserialized);
- proms.push(prom);
+ return deserialized;
+ });
+ // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache)
+ // we set the value at the field's id to a promise that will resolve to the field.
+ // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method).
+ // The mapping in the .then call ensures that when other callers await these promises, they'll
+ // get the resolved field
+ _cache[field.id] = prom;
// adds to a list of promises that will be awaited asynchronously
- // protosToLoad.push(deserialized.proto);
+ proms.push(prom);
}
}
await Promise.all(proms);
- // this actually handles the loading of prototypes
- // await Promise.all(protosToLoad);
return fieldMap;
});
- // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache)
- // we set the value at the field's id to a promise that will resolve to the field.
- // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method).
- // The mapping in the .then call ensures that when other callers await these promises, they'll
- // get the resolved field
- requestedIds.forEach(id => _cache[id] = deserializeFields.then(fields => fields[id]));
-
// 5) at this point, all fields have a) been returned from the server and b) been deserialized into actual Field objects whose
// prototype documents, if any, have also been fetched and cached.
const fields = await deserializeFields;
@@ -253,14 +253,6 @@ export namespace DocServer {
// id to the soon-to-be-returned field mapping.
requestedIds.forEach(id => {
const field = fields[id];
- // either way, overwrite or delete any promises (that we inserted as flags
- // to indicate that the field was in the process of being fetched). Now everything
- // should be an actual value within or entirely absent from the cache.
- if (field !== undefined) {
- _cache[id] = field;
- } else {
- delete _cache[id];
- }
map[id] = field;
});
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 5d1b6b382..09bafcf43 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -38,9 +38,11 @@ import { CollectionDockingView } from "../views/collections/CollectionDockingVie
import { LinkManager } from "../util/LinkManager";
import { DocumentManager } from "../util/DocumentManager";
import DirectoryImportBox from "../util/Import & Export/DirectoryImportBox";
-import { Scripting } from "../util/Scripting";
+import { Scripting, CompileScript } from "../util/Scripting";
import { ButtonBox } from "../views/nodes/ButtonBox";
import { SchemaHeaderField, RandomPastel } from "../../new_fields/SchemaHeaderField";
+import { ComputedField } from "../../new_fields/ScriptField";
+import { ProxyField } from "../../new_fields/Proxy";
var requestImageSize = require('../util/request-image-size');
var path = require('path');
@@ -193,6 +195,8 @@ export namespace Docs {
* haven't been initialized, the newly initialized prototype document.
*/
export async function initialize(): Promise<void> {
+ ProxyField.initPlugin();
+ ComputedField.initPlugin();
// non-guid string ids for each document prototype
let prototypeIds = Object.values(DocumentType).filter(type => type !== DocumentType.NONE).map(type => type + suffix);
// fetch the actual prototype documents from the server
@@ -618,6 +622,10 @@ export namespace DocUtils {
LinkManager.Instance.addLink(linkDocProto);
+ let script = `return links(this)};`;
+ let computed = CompileScript(script, { params: { this: "Doc" }, typecheck: false });
+ computed.compiled && (Doc.GetProto(source).links = new ComputedField(computed));
+ computed.compiled && (Doc.GetProto(target).links = new ComputedField(computed));
}, "make link");
return linkDoc;
}
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index a647f22c1..448a8e9cf 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -6,6 +6,7 @@ import { List } from "../../new_fields/List";
import { Id } from "../../new_fields/FieldSymbols";
import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
import { Docs } from "../documents/Documents";
+import { Scripting } from "./Scripting";
/*
@@ -42,7 +43,12 @@ export class LinkManager {
}
public getAllLinks(): Doc[] {
- return LinkManager.Instance.LinkManagerDoc ? LinkManager.Instance.LinkManagerDoc.allLinks ? DocListCast(LinkManager.Instance.LinkManagerDoc.allLinks) : [] : [];
+ let ldoc = LinkManager.Instance.LinkManagerDoc;
+ if (ldoc) {
+ let docs = DocListCast(ldoc.allLinks);
+ return docs;
+ }
+ return [];
}
public addLink(linkDoc: Doc): boolean {
@@ -242,4 +248,7 @@ export class LinkManager {
return Cast(linkDoc.anchor1, Doc, null);
}
}
-} \ No newline at end of file
+}
+Scripting.addGlobal(function links(doc: any) {
+ return new List(LinkManager.Instance.getAllRelatedLinks(doc));
+});
diff --git a/src/client/util/SerializationHelper.ts b/src/client/util/SerializationHelper.ts
index 13302be21..ff048f647 100644
--- a/src/client/util/SerializationHelper.ts
+++ b/src/client/util/SerializationHelper.ts
@@ -34,7 +34,7 @@ export namespace SerializationHelper {
return json;
}
- export async function Deserialize(obj: any, cb: (val: any) => void = emptyFunction): Promise<any> {
+ export async function Deserialize(obj: any): Promise<any> {
if (obj === undefined || obj === null) {
return undefined;
}
@@ -57,7 +57,7 @@ export namespace SerializationHelper {
}
const type = serializationTypes[obj.__type];
- const value = await new Promise(res => cb(deserialize(type.ctor, obj, (err, result) => res(result))));
+ const value = await new Promise(res => deserialize(type.ctor, obj, (err, result) => res(result)));
if (type.afterDeserialize) {
await type.afterDeserialize(value);
}
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index c413650f0..e654a0644 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -39,7 +39,7 @@ export interface TemplateMenuProps {
@observer
export class TemplateMenu extends React.Component<TemplateMenuProps> {
@observable private _hidden: boolean = true;
- dragRef = React.createRef<HTMLDivElement>();
+ dragRef = React.createRef<HTMLUListElement>();
constructor(props: TemplateMenuProps) {
super(props);
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 7f5d78313..02b2583cd 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -27,6 +27,7 @@ import "./CollectionTreeView.scss";
import React = require("react");
import { ComputedField } from '../../../new_fields/ScriptField';
import { KeyValueBox } from '../nodes/KeyValueBox';
+import { exportNamedDeclaration } from 'babel-types';
export interface TreeViewProps {
@@ -79,11 +80,17 @@ class TreeView extends React.Component<TreeViewProps> {
return splits.length > 1 ? splits[1].split("\"")[0] : "data";
}
@computed get childDocs() {
- let layout = this.props.document.layout as Doc;
+ let layout = this.props.document.layout instanceof Doc ? this.props.document.layout : undefined;
return (this.props.dataDoc ? Cast(this.props.dataDoc[this.fieldKey], listSpec(Doc)) : undefined) ||
(layout ? Cast(layout[this.fieldKey], listSpec(Doc)) : undefined) ||
Cast(this.props.document[this.fieldKey], listSpec(Doc));
}
+ @computed get childLinks() {
+ let layout = this.props.document.layout instanceof Doc ? this.props.document.layout : undefined;
+ return (this.props.dataDoc ? Cast(this.props.dataDoc.links, listSpec(Doc)) : undefined) ||
+ (layout instanceof Doc ? Cast(layout.links, listSpec(Doc)) : undefined) ||
+ Cast(this.props.document.links, listSpec(Doc));
+ }
@computed get resolvedDataDoc() {
if (this.props.dataDoc === undefined && this.props.document.layout instanceof Doc) {
// if there is no dataDoc (ie, we're not rendering a template layout), but this document
@@ -276,13 +283,15 @@ class TreeView extends React.Component<TreeViewProps> {
noOverlays = (doc: Doc) => ({ title: "", caption: "" });
@computed get renderContent() {
- if (this.treeViewExpandedView === this.fieldKey) {
- let remDoc = (doc: Doc) => this.remove(doc, this.fieldKey);
- let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc, addBefore, before);
- return <ul key={this.fieldKey + "more"}>
- {!this.childDocs ? (null) :
- TreeView.GetChildElements(this.childDocs as Doc[], this.props.treeViewId, this.props.document.layout as Doc,
- this.resolvedDataDoc, this.fieldKey, addDoc, remDoc, this.move,
+ const expandKey = this.treeViewExpandedView === this.fieldKey ? this.fieldKey : this.treeViewExpandedView === "links" ? "links" : undefined;
+ if (expandKey !== undefined) {
+ let remDoc = (doc: Doc) => this.remove(doc, expandKey);
+ let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before);
+ let docs = expandKey === "links" ? this.childLinks : this.childDocs;
+ return <ul key={expandKey + "more"}>
+ {!docs ? (null) :
+ TreeView.GetChildElements(docs as Doc[], this.props.treeViewId, this.props.document.layout as Doc,
+ this.resolvedDataDoc, expandKey, addDoc, remDoc, this.move,
this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform,
this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth)}
</ul >;
@@ -334,7 +343,8 @@ class TreeView extends React.Component<TreeViewProps> {
onPointerDown={action(() => {
this.props.document.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? "fields" :
this.treeViewExpandedView === "fields" && this.props.document.layout ? "layout" :
- this.childDocs ? this.fieldKey : "fields";
+ this.treeViewExpandedView === "layout" && this.props.document.links ? "links" :
+ this.childDocs ? this.fieldKey : "fields";
this._collapsed = false;
})}>
{this.treeViewExpandedView}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 3ff816c46..232ac22c9 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -537,7 +537,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
const width = Cast(viewDef.width, "number");
const height = Cast(viewDef.height, "number");
const fontSize = Cast(viewDef.fontSize, "number");
- if ([text, x, y, z, width, height].some(val => val === undefined)) {
+ if ([text, x, y, width, height].some(val => val === undefined)) {
return undefined;
}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 9a0615d68..17dc4184a 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -1,42 +1,39 @@
import { library } from '@fortawesome/fontawesome-svg-core';
-import { faImage, faFileAudio, faPaintBrush, faAsterisk } from '@fortawesome/free-solid-svg-icons';
-import { action, observable, computed, runInAction } from 'mobx';
+import { faEye } from '@fortawesome/free-regular-svg-icons';
+import { faAsterisk, faFileAudio, faImage, faPaintBrush } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, observable, runInAction } from 'mobx';
import { observer } from "mobx-react";
import Lightbox from 'react-image-lightbox';
import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
-import { Doc, HeightSym, WidthSym, DocListCast } from '../../../new_fields/Doc';
+import { Doc, DocListCast, HeightSym, WidthSym } from '../../../new_fields/Doc';
import { List } from '../../../new_fields/List';
import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema';
-import { Cast, FieldValue, NumCast, StrCast, BoolCast } from '../../../new_fields/Types';
-import { ImageField, AudioField } from '../../../new_fields/URLField';
+import { ComputedField } from '../../../new_fields/ScriptField';
+import { BoolCast, Cast, FieldValue, NumCast, StrCast } from '../../../new_fields/Types';
+import { AudioField, ImageField } from '../../../new_fields/URLField';
+import { RouteStore } from '../../../server/RouteStore';
import { Utils } from '../../../Utils';
+import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices';
+import { Docs } from '../../documents/Documents';
import { DragManager } from '../../util/DragManager';
+import { CompileScript } from '../../util/Scripting';
import { undoBatch } from '../../util/UndoManager';
import { ContextMenu } from "../../views/ContextMenu";
import { ContextMenuProps } from '../ContextMenuItem';
import { DocComponent } from '../DocComponent';
import { InkingControl } from '../InkingControl';
import { positionSchema } from './DocumentView';
+import FaceRectangles from './FaceRectangles';
import { FieldView, FieldViewProps } from './FieldView';
import "./ImageBox.scss";
import React = require("react");
-import { RouteStore } from '../../../server/RouteStore';
-import { Docs, DocumentType } from '../../documents/Documents';
-import { DocServer } from '../../DocServer';
-import { Font } from '@react-pdf/renderer';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { CognitiveServices, Service, Tag, Confidence } from '../../cognitive_services/CognitiveServices';
-import FaceRectangles from './FaceRectangles';
-import { faEye } from '@fortawesome/free-regular-svg-icons';
-import { ComputedField } from '../../../new_fields/ScriptField';
-import { CompileScript } from '../../util/Scripting';
-import { thisExpression } from 'babel-types';
var requestImageSize = require('../../util/request-image-size');
var path = require('path');
const { Howl } = require('howler');
-library.add(faImage, faEye, faPaintBrush);
+library.add(faImage, faEye as any, faPaintBrush);
library.add(faFileAudio, faAsterisk);
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 3775f0f47..534a42efc 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -1,22 +1,19 @@
import { action, observable } from 'mobx';
import { observer } from "mobx-react";
import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
-import { emptyFunction, returnFalse, returnZero, returnTrue, returnOne } from '../../../Utils';
-import { CompileScript, CompiledScript, ScriptOptions } from "../../util/Scripting";
+import { Doc, Field } from '../../../new_fields/Doc';
+import { emptyFunction, returnFalse, returnOne, returnZero } from '../../../Utils';
+import { Docs } from '../../documents/Documents';
import { Transform } from '../../util/Transform';
+import { undoBatch } from '../../util/UndoManager';
+import { CollectionDockingView } from '../collections/CollectionDockingView';
+import { ContextMenu } from '../ContextMenu';
import { EditableView } from "../EditableView";
import { FieldView, FieldViewProps } from './FieldView';
+import { KeyValueBox } from './KeyValueBox';
import "./KeyValueBox.scss";
import "./KeyValuePair.scss";
import React = require("react");
-import { Doc, Opt, Field } from '../../../new_fields/Doc';
-import { FieldValue } from '../../../new_fields/Types';
-import { KeyValueBox } from './KeyValueBox';
-import { DragManager, SetupDrag } from '../../util/DragManager';
-import { ContextMenu } from '../ContextMenu';
-import { Docs } from '../../documents/Documents';
-import { CollectionDockingView } from '../collections/CollectionDockingView';
-import { undoBatch } from '../../util/UndoManager';
// Represents one row in a key value plane
diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx
index 0dca4b4b1..79f87f4ac 100644
--- a/src/debug/Test.tsx
+++ b/src/debug/Test.tsx
@@ -1,81 +1,39 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
-import { SerializationHelper } from '../client/util/SerializationHelper';
-import { createSchema, makeInterface, makeStrictInterface, listSpec } from '../new_fields/Schema';
-import { ImageField } from '../new_fields/URLField';
+import { DocServer } from '../client/DocServer';
import { Doc } from '../new_fields/Doc';
-import { List } from '../new_fields/List';
-
-const schema1 = createSchema({
- hello: "number",
- test: "string",
- fields: "boolean",
- url: ImageField,
- testDoc: Doc
-});
-
-type TestDoc = makeInterface<[typeof schema1]>;
-const TestDoc: (doc?: Doc) => TestDoc = makeInterface(schema1);
-
-const schema2 = createSchema({
- hello: ImageField,
- test: "boolean",
- fields: listSpec("number"),
- url: "number",
- testDoc: ImageField
-});
-
-const Test2Doc = makeStrictInterface(schema2);
-type Test2Doc = makeStrictInterface<typeof schema2>;
-
-const assert = (bool: boolean) => {
- if (!bool) throw new Error();
-};
+const protoId = "protoDoc";
+const delegateId = "delegateDoc";
class Test extends React.Component {
- onClick = () => {
- const url = new ImageField(new URL("http://google.com"));
- const doc = new Doc();
- const doc2 = new Doc();
- doc.hello = 5;
- doc.fields = "test";
- doc.test = "hello doc";
- doc.url = url;
- //doc.testDoc = doc2;
-
+ onCreateClick = () => {
+ const proto = new Doc(protoId, true);
+ const delegate = Doc.MakeDelegate(proto, delegateId);
+ }
- const test1: TestDoc = TestDoc(doc);
- assert(test1.hello === 5);
- assert(test1.fields === undefined);
- assert(test1.test === "hello doc");
- assert(test1.url === url);
- assert(test1.testDoc === doc2);
- test1.myField = 20;
- assert(test1.myField === 20);
+ onReadClick = async () => {
+ console.log("reading");
+ const docs = await DocServer.GetRefFields([delegateId, protoId]);
+ console.log("done");
+ console.log(docs);
+ }
- const test2: Test2Doc = Test2Doc(doc);
- assert(test2.hello === undefined);
- // assert(test2.fields === "test");
- assert(test2.test === undefined);
- assert(test2.url === undefined);
- assert(test2.testDoc === undefined);
- test2.url = 35;
- assert(test2.url === 35);
- const l = new List<Doc>();
- //TODO push, and other array functions don't go through the proxy
- l.push(doc2);
- //TODO currently length, and any other string fields will get serialized
- doc.list = l;
- console.log(l.slice());
+ onDeleteClick = () => {
+ DocServer.DeleteDocuments([protoId, delegateId]);
}
render() {
- return <div><button onClick={this.onClick}>Click me</button>
- {/* <input onKeyPress={this.onEnter}></input> */}
- </div>;
+ return (
+ <div>
+ <button onClick={this.onCreateClick}>Create Docs</button>
+ <button onClick={this.onReadClick}>Read Docs</button>
+ <button onClick={this.onDeleteClick}>Delete Docs</button>
+ </div>
+ );
}
}
+DocServer.init(window.location.protocol, window.location.hostname, 4321, "test");
ReactDOM.render(
<Test />,
document.getElementById('root')
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 84b8589dd..b70951040 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -12,7 +12,7 @@ import { scriptingGlobal } from "../client/util/Scripting";
import { List } from "./List";
import { DocumentType } from "../client/documents/Documents";
import { ComputedField } from "./ScriptField";
-import { PrefetchProxy } from "./Proxy";
+import { PrefetchProxy, ProxyField } from "./Proxy";
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
@@ -420,7 +420,7 @@ export namespace Doc {
export function MakeCopy(doc: Doc, copyProto: boolean = false): Doc {
const copy = new Doc;
Object.keys(doc).forEach(key => {
- const field = doc[key];
+ const field = ProxyField.WithoutProxy(() => doc[key]);
if (key === "proto" && copyProto) {
if (field instanceof Doc) {
copy[key] = Doc.MakeCopy(field);
@@ -431,7 +431,7 @@ export namespace Doc {
} else if (field instanceof ObjectField) {
copy[key] = ObjectField.MakeCopy(field);
} else if (field instanceof Promise) {
- field.then(f => (copy[key] === undefined) && (copy[key] = f)); //TODO what should we do here?
+ debugger; //This shouldn't happend...
} else {
copy[key] = field;
}
@@ -525,17 +525,14 @@ export namespace Doc {
}
export function UseDetailLayout(d: Doc) {
runInAction(async () => {
- let detailLayout1 = await PromiseValue(d.detailedLayout);
- let detailLayout = await PromiseValue(d.detailedLayout);
+ let detailLayout = await d.detailedLayout;
if (detailLayout) {
d.layout = detailLayout;
d.nativeWidth = d.nativeHeight = undefined;
if (detailLayout instanceof Doc) {
let delegDetailLayout = Doc.MakeDelegate(detailLayout) as Doc;
d.layout = delegDetailLayout;
- let subDetailLayout1 = await PromiseValue(delegDetailLayout.detailedLayout);
- let subDetailLayout = await PromiseValue(delegDetailLayout.detailedLayout);
- delegDetailLayout.layout = subDetailLayout;
+ delegDetailLayout.layout = await delegDetailLayout.detailedLayout;
}
}
});
diff --git a/src/new_fields/Proxy.ts b/src/new_fields/Proxy.ts
index b3e8d6467..c6292e37c 100644
--- a/src/new_fields/Proxy.ts
+++ b/src/new_fields/Proxy.ts
@@ -7,6 +7,7 @@ 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 {
@@ -68,6 +69,34 @@ export class ProxyField<T extends RefField> extends ObjectField {
}
}
+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;
}
diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts
index 6d52525b8..83fb52d07 100644
--- a/src/new_fields/ScriptField.ts
+++ b/src/new_fields/ScriptField.ts
@@ -137,9 +137,11 @@ export namespace ComputedField {
}
}
- Plugins.addGetterPlugin((doc, _, value) => {
- if (useComputed && value instanceof ComputedField) {
- return { value: value.value(doc), shouldReturn: true };
- }
- });
+ export function initPlugin() {
+ Plugins.addGetterPlugin((doc, _, value) => {
+ if (useComputed && value instanceof ComputedField) {
+ return { value: value.value(doc), shouldReturn: true };
+ }
+ });
+ }
} \ No newline at end of file
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 2ebfb9e71..c6f693f7f 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -14,7 +14,7 @@ function _readOnlySetter(): never {
export interface GetterResult {
value: FieldResult;
- shouldReturn: boolean;
+ shouldReturn?: boolean;
}
export type GetterPlugin = (receiver: any, prop: string | number, currentValue: any) => GetterResult | undefined;
const getterPlugins: GetterPlugin[] = [];
@@ -103,9 +103,6 @@ export function getter(target: any, prop: string | symbol | number, receiver: an
function getFieldImpl(target: any, prop: string | number, receiver: any, ignoreProto: boolean = false): any {
receiver = receiver || target[SelfProxy];
let field = target.__fields[prop];
- if (field instanceof ProxyField) {
- return field.value();
- }
for (const plugin of getterPlugins) {
const res = plugin(receiver, prop, field);
if (res === undefined) continue;