aboutsummaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/client')
-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
9 files changed, 88 insertions, 75 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