aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts3
-rw-r--r--src/client/views/InkingCanvas.tsx29
-rw-r--r--src/client/views/InkingControl.tsx7
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx51
-rw-r--r--src/client/views/collections/CollectionView.tsx9
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx80
-rw-r--r--src/client/views/nodes/LinkBox.tsx77
-rw-r--r--src/client/views/nodes/LinkEditor.tsx16
-rw-r--r--src/debug/Viewer.tsx368
-rw-r--r--src/fields/ScriptField.ts174
-rw-r--r--src/mobile/ImageUpload.tsx34
-rw-r--r--src/new_fields/Doc.ts6
-rw-r--r--src/new_fields/InkField.ts7
-rw-r--r--src/new_fields/Types.ts4
-rw-r--r--src/server/authentication/controllers/WorkspacesMenu.tsx16
15 files changed, 435 insertions, 446 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 8f873ef41..c30fb21d5 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -29,11 +29,12 @@ import { Cast } from "../../new_fields/Types";
import { IconField } from "../../new_fields/IconField";
import { listSpec } from "../../new_fields/Schema";
import { DocServer } from "../DocServer";
+import { StrokeData, InkField } from "../../new_fields/InkField";
export interface DocumentOptions {
x?: number;
y?: number;
- // ink?: Map<string, StrokeData>;
+ ink?: InkField;
width?: number;
height?: number;
nativeWidth?: number;
diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index 47ee8eb85..1e26893c5 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -1,9 +1,5 @@
import { action, computed, trace, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Document } from "../../fields/Document";
-import { FieldWaiting } from "../../fields/Field";
-import { InkField, InkTool, StrokeData, StrokeMap } from "../../fields/InkField";
-import { KeyStore } from "../../fields/KeyStore";
import { Utils } from "../../Utils";
import { Transform } from "../util/Transform";
import "./InkingCanvas.scss";
@@ -11,10 +7,13 @@ import { InkingControl } from "./InkingControl";
import { InkingStroke } from "./InkingStroke";
import React = require("react");
import { undoBatch, UndoManager } from "../util/UndoManager";
+import { StrokeData, InkField, InkTool } from "../../new_fields/InkField";
+import { Doc } from "../../new_fields/Doc";
+import { Cast, PromiseValue, NumCast } from "../../new_fields/Types";
interface InkCanvasProps {
getScreenTransform: () => Transform;
- Document: Document;
+ Document: Doc;
children: () => JSX.Element[];
}
@@ -23,7 +22,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
maxCanvasDim = 8192 / 2; // 1/2 of the maximum canvas dimension for Chrome
@observable inkMidX: number = 0;
@observable inkMidY: number = 0;
- private previousState?: StrokeMap;
+ private previousState?: Map<string, StrokeData>;
private _currentStrokeId: string = "";
public static IntersectStrokeRect(stroke: StrokeData, selRect: { left: number, top: number, width: number, height: number }): boolean {
return stroke.pathData.reduce((inside: boolean, val) => inside ||
@@ -33,9 +32,9 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
}
componentDidMount() {
- this.props.Document.GetTAsync(KeyStore.Ink, InkField, ink => runInAction(() => {
+ PromiseValue(Cast(this.props.Document.ink, InkField)).then(ink => runInAction(() => {
if (ink) {
- let bounds = Array.from(ink.Data).reduce(([mix, max, miy, may], [id, strokeData]) =>
+ let bounds = Array.from(ink.inkData).reduce(([mix, max, miy, may], [id, strokeData]) =>
strokeData.pathData.reduce(([mix, max, miy, may], p) =>
[Math.min(mix, p.x), Math.max(max, p.x), Math.min(miy, p.y), Math.max(may, p.y)],
[mix, max, miy, may]),
@@ -47,13 +46,13 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
}
@computed
- get inkData(): StrokeMap {
- let map = this.props.Document.GetT(KeyStore.Ink, InkField);
- return !map || map === FieldWaiting ? new Map : new Map(map.Data);
+ get inkData(): Map<string, StrokeData> {
+ let map = Cast(this.props.Document.ink, InkField);
+ return !map ? new Map : new Map(map.inkData);
}
- set inkData(value: StrokeMap) {
- this.props.Document.SetDataOnPrototype(KeyStore.Ink, value, InkField);
+ set inkData(value: Map<string, StrokeData>) {
+ Doc.SetOnPrototype(this.props.Document, "ink", new InkField(value));
}
@action
@@ -78,7 +77,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
color: InkingControl.Instance.selectedColor,
width: InkingControl.Instance.selectedWidth,
tool: InkingControl.Instance.selectedTool,
- page: this.props.Document.GetNumber(KeyStore.CurPage, -1)
+ page: NumCast(this.props.Document.curPage, -1)
});
this.inkData = data;
}
@@ -137,7 +136,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
@computed
get drawnPaths() {
- let curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1);
+ let curPage = NumCast(this.props.Document.curPage, -1);
let paths = Array.from(this.inkData).reduce((paths, [id, strokeData]) => {
if (strokeData.page === -1 || strokeData.page === curPage) {
paths.push(<InkingStroke key={id} id={id} line={strokeData.pathData}
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index 9a68f0671..4b3dbd4e0 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -2,15 +2,14 @@ import { observable, action, computed } from "mobx";
import { CirclePicker, ColorResult } from 'react-color';
import React = require("react");
-import { InkTool } from "../../fields/InkField";
import { observer } from "mobx-react";
import "./InkingControl.scss";
import { library } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPen, faHighlighter, faEraser, faBan } from '@fortawesome/free-solid-svg-icons';
import { SelectionManager } from "../util/SelectionManager";
-import { KeyStore } from "../../fields/KeyStore";
-import { TextField } from "../../fields/TextField";
+import { InkTool } from "../../new_fields/InkField";
+import { Doc } from "../../new_fields/Doc";
library.add(faPen, faHighlighter, faEraser, faBan);
@@ -39,7 +38,7 @@ export class InkingControl extends React.Component {
if (SelectionManager.SelectedDocuments().length === 1) {
var sdoc = SelectionManager.SelectedDocuments()[0];
if (sdoc.props.ContainingCollectionView) {
- sdoc.props.Document.SetDataOnPrototype(KeyStore.BackgroundColor, color.hex, TextField);
+ Doc.SetOnPrototype(sdoc.props.Document, "backgroundColor", color.hex);
}
}
}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 905b48db7..c9d8d83c8 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -3,20 +3,19 @@ import { faCaretDown, faCaretRight, faTrashAlt } from '@fortawesome/free-solid-s
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, observable } from "mobx";
import { observer } from "mobx-react";
-import { Document } from "../../../fields/Document";
-import { FieldWaiting } from "../../../fields/Field";
-import { KeyStore } from "../../../fields/KeyStore";
-import { ListField } from "../../../fields/ListField";
import { DragManager, SetupDrag } from "../../util/DragManager";
import { EditableView } from "../EditableView";
import { CollectionSubView } from "./CollectionSubView";
import "./CollectionTreeView.scss";
import React = require("react");
+import { Document, listSpec } from '../../../new_fields/Schema';
+import { Cast, StrCast, BoolCast } from '../../../new_fields/Types';
+import { Doc, Id } from '../../../new_fields/Doc';
export interface TreeViewProps {
- document: Document;
- deleteDoc: (doc: Document) => void;
+ document: Doc;
+ deleteDoc: (doc: Doc) => void;
moveDocument: DragManager.MoveFunction;
copyOnDrag: boolean;
}
@@ -43,9 +42,9 @@ class TreeView extends React.Component<TreeViewProps> {
@action
remove = (document: Document) => {
- var children = this.props.document.GetT<ListField<Document>>(KeyStore.Data, ListField);
- if (children && children !== FieldWaiting) {
- children.Data.splice(children.Data.indexOf(document), 1);
+ var children = Cast(this.props.document.data, listSpec(Doc));
+ if (children) {
+ children.splice(children.indexOf(document), 1);
}
}
@@ -80,15 +79,15 @@ class TreeView extends React.Component<TreeViewProps> {
display={"inline"}
contents={titleString}
height={36}
- GetValue={() => this.props.document.Title}
+ GetValue={() => StrCast(this.props.document.title)}
SetValue={(value: string) => {
- this.props.document.SetText(KeyStore.Title, value);
+ this.props.document.title = value;
return true;
}}
/>);
return (
<div className="docContainer" ref={reference} onPointerDown={onItemDown}>
- {editableView(this.props.document.Title)}
+ {editableView(StrCast(this.props.document.title))}
<div className="delete-button" onClick={this.delete}><FontAwesomeIcon icon="trash-alt" size="xs" /></div>
</div >);
}
@@ -96,12 +95,12 @@ class TreeView extends React.Component<TreeViewProps> {
render() {
let bulletType = BulletType.List;
let childElements: JSX.Element | undefined = undefined;
- var children = this.props.document.GetT<ListField<Document>>(KeyStore.Data, ListField);
- if (children && children !== FieldWaiting) { // add children for a collection
+ var children = Cast(this.props.document.data, listSpec(Doc));
+ if (children) { // add children for a collection
if (!this._collapsed) {
bulletType = BulletType.Collapsible;
childElements = <ul>
- {children.Data.map(value => <TreeView key={value.Id} document={value} deleteDoc={this.remove} moveDocument={this.move} copyOnDrag={this.props.copyOnDrag} />)}
+ {children.map(value => <TreeView key={value[Id]} document={value} deleteDoc={this.remove} moveDocument={this.move} copyOnDrag={this.props.copyOnDrag} />)}
</ul >;
}
else bulletType = BulletType.Collapsed;
@@ -117,22 +116,22 @@ class TreeView extends React.Component<TreeViewProps> {
}
@observer
-export class CollectionTreeView extends CollectionSubView {
+export class CollectionTreeView extends CollectionSubView(Document) {
@action
remove = (document: Document) => {
- var children = this.props.Document.GetT<ListField<Document>>(KeyStore.Data, ListField);
- if (children && children !== FieldWaiting) {
- children.Data.splice(children.Data.indexOf(document), 1);
+ const children = this.children;
+ if (children) {
+ children.splice(children.indexOf(document), 1);
}
}
render() {
- let children = this.props.Document.GetT<ListField<Document>>(KeyStore.Data, ListField);
- let copyOnDrag = this.props.Document.GetBoolean(KeyStore.CopyDraggedItems, false);
- let childrenElement = !children || children === FieldWaiting ? (null) :
- (children.Data.map(value =>
- <TreeView document={value} key={value.Id} deleteDoc={this.remove} moveDocument={this.props.moveDocument} copyOnDrag={copyOnDrag} />)
+ const children = this.children;
+ let copyOnDrag = BoolCast(this.props.Document.copyDraggedItems, false);
+ let childrenElement = !children ? (null) :
+ (children.map(value =>
+ <TreeView document={value} key={value[Id]} deleteDoc={this.remove} moveDocument={this.props.moveDocument} copyOnDrag={copyOnDrag} />)
);
return (
@@ -145,9 +144,9 @@ export class CollectionTreeView extends CollectionSubView {
contents={this.props.Document.Title}
display={"inline"}
height={72}
- GetValue={() => this.props.Document.Title}
+ GetValue={() => StrCast(this.props.Document.title)}
SetValue={(value: string) => {
- this.props.Document.SetText(KeyStore.Title, value);
+ this.props.Document.title = value;
return true;
}} />
</div>
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 675e720e2..e7bf1e121 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -7,7 +7,6 @@ import { CollectionDockingView } from './CollectionDockingView';
import { CollectionTreeView } from './CollectionTreeView';
import { ContextMenu } from '../ContextMenu';
import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
-import { KeyStore } from '../../../fields/KeyStore';
import { observer } from 'mobx-react';
import { undoBatch } from '../../util/UndoManager';
import { trace } from 'mobx';
@@ -29,13 +28,13 @@ export class CollectionView extends React.Component<FieldViewProps> {
return (null);
}
- get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's?
+ get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey === "annotations"; } // bcz: ? Why do we need to compare Id's?
onContextMenu = (e: React.MouseEvent): void => {
if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document.Id !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
- ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform)) });
- ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema)) });
- ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree)) });
+ ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Freeform) });
+ ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Schema) });
+ ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Tree) });
}
}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index c6681e014..644a8784c 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,10 +1,6 @@
import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
-import { Document } from "../../../../fields/Document";
-import { FieldWaiting } from "../../../../fields/Field";
-import { InkField, StrokeData } from "../../../../fields/InkField";
-import { KeyStore } from "../../../../fields/KeyStore";
-import { Documents } from "../../../documents/Documents";
+import { Docs } from "../../../documents/Documents";
import { SelectionManager } from "../../../util/SelectionManager";
import { Transform } from "../../../util/Transform";
import { undoBatch } from "../../../util/UndoManager";
@@ -14,16 +10,19 @@ import { CollectionFreeFormView } from "./CollectionFreeFormView";
import "./MarqueeView.scss";
import React = require("react");
import { Utils } from "../../../../Utils";
+import { Doc } from "../../../../new_fields/Doc";
+import { NumCast, Cast } from "../../../../new_fields/Types";
+import { InkField, StrokeData } from "../../../../new_fields/InkField";
interface MarqueeViewProps {
getContainerTransform: () => Transform;
getTransform: () => Transform;
container: CollectionFreeFormView;
- addDocument: (doc: Document, allowDuplicates: false) => boolean;
- activeDocuments: () => Document[];
- selectDocuments: (docs: Document[]) => void;
- removeDocument: (doc: Document) => boolean;
- addLiveTextDocument: (doc: Document) => void;
+ addDocument: (doc: Doc, allowDuplicates: false) => boolean;
+ activeDocuments: () => Doc[];
+ selectDocuments: (docs: Doc[]) => void;
+ removeDocument: (doc: Doc) => boolean;
+ addLiveTextDocument: (doc: Doc) => void;
}
@observer
@@ -49,7 +48,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
onKeyPress = (e: KeyboardEvent) => {
//make textbox and add it to this collection
let [x, y] = this.props.getTransform().transformPoint(this._downX, this._downY);
- let newBox = Documents.TextDocument({ width: 200, height: 100, x: x, y: y, title: "-typed text-" });
+ let newBox = Docs.TextDocument({ width: 200, height: 100, x: x, y: y, title: "-typed text-" });
this.props.addLiveTextDocument(newBox);
e.stopPropagation();
}
@@ -64,8 +63,9 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
document.addEventListener("pointerup", this.onPointerUp, true);
document.addEventListener("keydown", this.marqueeCommand, true);
}
- if (e.altKey)
+ if (e.altKey) {
e.preventDefault();
+ }
}
@action
@@ -80,8 +80,9 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
e.preventDefault();
}
}
- if (e.altKey)
+ if (e.altKey) {
e.preventDefault();
+ }
}
@action
@@ -94,8 +95,9 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
this.props.selectDocuments(mselect.length ? mselect : [this.props.container.props.Document]);
}
this.cleanupInteractions(true);
- if (e.altKey)
+ if (e.altKey) {
e.preventDefault();
+ }
}
@action
@@ -127,11 +129,11 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
@undoBatch
@action
marqueeCommand = (e: KeyboardEvent) => {
- if (e.key === "Backspace" || e.key === "Delete" || e.key == "d") {
+ if (e.key === "Backspace" || e.key === "Delete" || e.key === "d") {
this.marqueeSelect().map(d => this.props.removeDocument(d));
- let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField);
- if (ink && ink !== FieldWaiting) {
- this.marqueeInkDelete(ink.Data);
+ let ink = Cast(this.props.container.props.Document.ink, InkField);
+ if (ink) {
+ this.marqueeInkDelete(ink.inkData);
}
this.cleanupInteractions(true);
e.stopPropagation();
@@ -141,33 +143,33 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
let bounds = this.Bounds;
let selected = this.marqueeSelect().map(d => {
this.props.removeDocument(d);
- d.SetNumber(KeyStore.X, d.GetNumber(KeyStore.X, 0) - bounds.left - bounds.width / 2);
- d.SetNumber(KeyStore.Y, d.GetNumber(KeyStore.Y, 0) - bounds.top - bounds.height / 2);
- d.SetNumber(KeyStore.Page, -1);
+ d.x = NumCast(d.X) - bounds.left - bounds.width / 2;
+ d.y = NumCast(d.Y) - bounds.top - bounds.height / 2;
+ d.page = -1;
return d;
});
- let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField);
- let inkData = ink && ink !== FieldWaiting ? ink.Data : undefined;
- let zoomBasis = this.props.container.props.Document.GetNumber(KeyStore.Scale, 1);
- let newCollection = Documents.FreeformDocument(selected, {
+ let ink = Cast(this.props.container.props.Document.ink, InkField);
+ let inkData = ink ? ink.inkData : undefined;
+ let zoomBasis = NumCast(this.props.container.props.Document.scale, 1);
+ let newCollection = Docs.FreeformDocument(selected, {
x: bounds.left,
y: bounds.top,
- panx: 0,
- pany: 0,
+ panX: 0,
+ panY: 0,
borderRounding: e.key === "e" ? -1 : undefined,
backgroundColor: selected.length ? "white" : "",
scale: zoomBasis,
width: bounds.width * zoomBasis,
height: bounds.height * zoomBasis,
- ink: inkData ? this.marqueeInkSelect(inkData) : undefined,
+ ink: inkData ? new InkField(this.marqueeInkSelect(inkData)) : undefined,
title: "a nested collection"
});
this.marqueeInkDelete(inkData);
SelectionManager.DeselectAll();
if (e.key === "r") {
- let summary = Documents.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" });
- summary.GetPrototype()!.CreateLink(newCollection.GetPrototype()!);
+ let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" });
+ Doc.MakeLink(summary.proto!, newCollection.proto!);
this.props.addLiveTextDocument(summary);
e.preventDefault();
}
@@ -182,9 +184,9 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
let bounds = this.Bounds;
let selected = this.marqueeSelect();
SelectionManager.DeselectAll();
- let summary = Documents.TextDocument({ x: bounds.left + bounds.width + 25, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" });
+ let summary = Docs.TextDocument({ x: bounds.left + bounds.width + 25, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" });
this.props.addLiveTextDocument(summary);
- selected.map(select => summary.GetPrototype()!.CreateLink(select.GetPrototype()!));
+ selected.forEach(select => Doc.MakeLink(summary.proto!, select.proto!));
this.cleanupInteractions(true);
}
@@ -219,19 +221,19 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
let idata = new Map();
ink.forEach((value: StrokeData, key: string, map: any) =>
!InkingCanvas.IntersectStrokeRect(value, this.Bounds) && idata.set(key, value));
- this.props.container.props.Document.SetDataOnPrototype(KeyStore.Ink, idata, InkField);
+ Doc.SetOnPrototype(this.props.container.props.Document, "ink", new InkField(idata));
}
}
marqueeSelect() {
let selRect = this.Bounds;
- let selection: Document[] = [];
+ let selection: Doc[] = [];
this.props.activeDocuments().map(doc => {
- var z = doc.GetNumber(KeyStore.ZoomBasis, 1);
- var x = doc.GetNumber(KeyStore.X, 0);
- var y = doc.GetNumber(KeyStore.Y, 0);
- var w = doc.Width() / z;
- var h = doc.Height() / z;
+ var z = NumCast(doc.zoomBasis, 1);
+ var x = NumCast(doc.x);
+ var y = NumCast(doc.y);
+ var w = NumCast(doc.width) / z;
+ var h = NumCast(doc.height) / z;
if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) {
selection.push(doc);
}
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 1c0e316e8..9bb90de0d 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -2,15 +2,14 @@ import { library } from '@fortawesome/fontawesome-svg-core';
import { faEdit, faEye, faTimes } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { observer } from "mobx-react";
-import { Document } from "../../../fields/Document";
-import { KeyStore } from '../../../fields/KeyStore';
-import { ListField } from "../../../fields/ListField";
-import { NumberField } from "../../../fields/NumberField";
import { DocumentManager } from "../../util/DocumentManager";
import { undoBatch } from "../../util/UndoManager";
import { CollectionDockingView } from "../collections/CollectionDockingView";
import './LinkBox.scss';
import React = require("react");
+import { Doc } from '../../../new_fields/Doc';
+import { Cast, NumCast } from '../../../new_fields/Types';
+import { listSpec } from '../../../new_fields/Schema';
library.add(faEye);
@@ -18,9 +17,9 @@ library.add(faEdit);
library.add(faTimes);
interface Props {
- linkDoc: Document;
+ linkDoc: Doc;
linkName: String;
- pairedDoc: Document;
+ pairedDoc: Doc;
type: String;
showEditor: () => void;
}
@@ -29,62 +28,52 @@ interface Props {
export class LinkBox extends React.Component<Props> {
@undoBatch
- onViewButtonPressed = (e: React.PointerEvent): void => {
+ onViewButtonPressed = async (e: React.PointerEvent): Promise<void> => {
e.stopPropagation();
let docView = DocumentManager.Instance.getDocumentView(this.props.pairedDoc);
if (docView) {
docView.props.focus(docView.props.Document);
} else {
- this.props.pairedDoc.GetAsync(KeyStore.AnnotationOn, (contextDoc: any) => {
- if (!contextDoc) {
- CollectionDockingView.Instance.AddRightSplit(this.props.pairedDoc.MakeDelegate());
- } else if (contextDoc instanceof Document) {
- this.props.pairedDoc.GetTAsync(KeyStore.Page, NumberField).then((pfield: any) => {
- contextDoc.GetTAsync(KeyStore.CurPage, NumberField).then((cfield: any) => {
- if (pfield !== cfield) {
- contextDoc.SetNumber(KeyStore.CurPage, pfield.Data);
- }
- let contextView = DocumentManager.Instance.getDocumentView(contextDoc);
- if (contextView) {
- contextView.props.focus(contextDoc);
- } else {
- CollectionDockingView.Instance.AddRightSplit(contextDoc);
- }
- });
- });
+ const contextDoc = await Cast(this.props.pairedDoc.annotationOn, Doc);
+ if (!contextDoc) {
+ CollectionDockingView.Instance.AddRightSplit(Doc.MakeDelegate(this.props.pairedDoc));
+ } else {
+ const page = NumCast(this.props.pairedDoc.page, undefined);
+ const curPage = NumCast(contextDoc.curPage, undefined);
+ if (page !== curPage) {
+ contextDoc.curPage = page;
}
- });
+ let contextView = DocumentManager.Instance.getDocumentView(contextDoc);
+ if (contextView) {
+ contextView.props.focus(contextDoc);
+ } else {
+ CollectionDockingView.Instance.AddRightSplit(contextDoc);
+ }
+ }
}
}
onEditButtonPressed = (e: React.PointerEvent): void => {
- console.log("edit down");
e.stopPropagation();
this.props.showEditor();
}
- onDeleteButtonPressed = (e: React.PointerEvent): void => {
- console.log("delete down");
+ onDeleteButtonPressed = async (e: React.PointerEvent): Promise<void> => {
e.stopPropagation();
- this.props.linkDoc.GetTAsync(KeyStore.LinkedFromDocs, Document, field => {
- if (field) {
- field.GetTAsync<ListField<Document>>(KeyStore.LinkedToDocs, ListField, field => {
- if (field) {
- field.Data.splice(field.Data.indexOf(this.props.linkDoc));
- }
- });
+ const [linkedFrom, linkedTo] = await Promise.all([Cast(this.props.linkDoc.linkedFrom, Doc), Cast(this.props.linkDoc.linkedTo, Doc)]);
+ if (linkedFrom) {
+ const linkedToDocs = Cast(linkedFrom.linkedToDocs, listSpec(Doc));
+ if (linkedToDocs) {
+ linkedToDocs.splice(linkedToDocs.indexOf(this.props.linkDoc));
}
- });
- this.props.linkDoc.GetTAsync(KeyStore.LinkedToDocs, Document, field => {
- if (field) {
- field.GetTAsync<ListField<Document>>(KeyStore.LinkedFromDocs, ListField, field => {
- if (field) {
- field.Data.splice(field.Data.indexOf(this.props.linkDoc));
- }
- });
+ }
+ if (linkedTo) {
+ const linkedFromDocs = Cast(linkedTo.linkedToDocs, listSpec(Doc));
+ if (linkedFromDocs) {
+ linkedFromDocs.splice(linkedFromDocs.indexOf(this.props.linkDoc));
}
- });
+ }
}
render() {
diff --git a/src/client/views/nodes/LinkEditor.tsx b/src/client/views/nodes/LinkEditor.tsx
index bde50fed8..f82c6e9cb 100644
--- a/src/client/views/nodes/LinkEditor.tsx
+++ b/src/client/views/nodes/LinkEditor.tsx
@@ -3,31 +3,29 @@ import React = require("react");
import { SelectionManager } from "../../util/SelectionManager";
import { observer } from "mobx-react";
import './LinkEditor.scss';
-import { KeyStore } from '../../../fields/KeyStore';
import { props } from "bluebird";
import { DocumentView } from "./DocumentView";
-import { Document } from "../../../fields/Document";
-import { TextField } from "../../../fields/TextField";
import { link } from "fs";
+import { StrCast } from "../../../new_fields/Types";
+import { Doc } from "../../../new_fields/Doc";
interface Props {
- linkDoc: Document;
+ linkDoc: Doc;
showLinks: () => void;
}
@observer
export class LinkEditor extends React.Component<Props> {
- @observable private _nameInput: string = this.props.linkDoc.GetText(KeyStore.Title, "");
- @observable private _descriptionInput: string = this.props.linkDoc.GetText(KeyStore.LinkDescription, "");
+ @observable private _nameInput: string = StrCast(this.props.linkDoc.title);
+ @observable private _descriptionInput: string = StrCast(this.props.linkDoc.linkDescription);
onSaveButtonPressed = (e: React.PointerEvent): void => {
- console.log("view down");
e.stopPropagation();
- this.props.linkDoc.SetData(KeyStore.Title, this._nameInput, TextField);
- this.props.linkDoc.SetData(KeyStore.LinkDescription, this._descriptionInput, TextField);
+ this.props.linkDoc.title = this._nameInput;
+ this.props.linkDoc.linkDescription = this._descriptionInput;
this.props.showLinks();
}
diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx
index 857da1ebb..4cac09dee 100644
--- a/src/debug/Viewer.tsx
+++ b/src/debug/Viewer.tsx
@@ -3,190 +3,184 @@ import "normalize.css";
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { observer } from 'mobx-react';
-import { Document } from '../fields/Document';
-import { BasicField } from '../fields/BasicField';
-import { ListField } from '../fields/ListField';
-import { Key } from '../fields/Key';
-import { Opt, Field } from '../fields/Field';
-import { Server } from '../client/Server';
-
-configure({
- enforceActions: "observed"
-});
-
-@observer
-class FieldViewer extends React.Component<{ field: BasicField<any> }> {
- render() {
- return <span>{JSON.stringify(this.props.field.Data)} ({this.props.field.Id})</span>;
- }
-}
-
-@observer
-class KeyViewer extends React.Component<{ field: Key }> {
- render() {
- return this.props.field.Name;
- }
-}
-
-@observer
-class ListViewer extends React.Component<{ field: ListField<Field> }>{
- @observable
- expanded = false;
-
- render() {
- let content;
- if (this.expanded) {
- content = (
- <div>
- {this.props.field.Data.map(field => <DebugViewer fieldId={field.Id} key={field.Id} />)}
- </div>
- );
- } else {
- content = <>[...] ({this.props.field.Id})</>;
- }
- return (
- <div>
- <button onClick={action(() => this.expanded = !this.expanded)}>Toggle</button>
- {content}
- </div >
- );
- }
-}
-
-@observer
-class DocumentViewer extends React.Component<{ field: Document }> {
- private keyMap: ObservableMap<string, Key> = new ObservableMap;
-
- private disposer?: Lambda;
-
- componentDidMount() {
- let f = () => {
- Array.from(this.props.field._proxies.keys()).forEach(id => {
- if (!this.keyMap.has(id)) {
- Server.GetField(id, (field) => {
- if (field && field instanceof Key) {
- this.keyMap.set(id, field);
- }
- });
- }
- });
- };
- this.disposer = this.props.field._proxies.observe(f);
- f();
- }
-
- componentWillUnmount() {
- if (this.disposer) {
- this.disposer();
- }
- }
-
- render() {
- let fields = Array.from(this.props.field._proxies.entries()).map(kv => {
- let key = this.keyMap.get(kv[0]);
- return (
- <div key={kv[0]}>
- <b>({key ? key.Name : kv[0]}): </b>
- <DebugViewer fieldId={kv[1]}></DebugViewer>
- </div>
- );
- });
- return (
- <div>
- Document ({this.props.field.Id})
- <div style={{ paddingLeft: "25px" }}>
- {fields}
- </div>
- </div>
- );
- }
-}
-
-@observer
-class DebugViewer extends React.Component<{ fieldId: string }> {
- @observable
- private field?: Field;
-
- @observable
- private error?: string;
-
- constructor(props: { fieldId: string }) {
- super(props);
- this.update();
- }
-
- update() {
- Server.GetField(this.props.fieldId, action((field: Opt<Field>) => {
- this.field = field;
- if (!field) {
- this.error = `Field with id ${this.props.fieldId} not found`;
- }
- }));
-
- }
-
- render() {
- let content;
- if (this.field) {
- // content = this.field.ToJson();
- if (this.field instanceof ListField) {
- content = (<ListViewer field={this.field} />);
- } else if (this.field instanceof Document) {
- content = (<DocumentViewer field={this.field} />);
- } else if (this.field instanceof BasicField) {
- content = (<FieldViewer field={this.field} />);
- } else if (this.field instanceof Key) {
- content = (<KeyViewer field={this.field} />);
- } else {
- content = (<span>Unrecognized field type</span>);
- }
- } else if (this.error) {
- content = <span>Field <b>{this.props.fieldId}</b> not found <button onClick={() => this.update()}>Refresh</button></span>;
- } else {
- content = <span>Field loading: {this.props.fieldId}</span>;
- }
- return content;
- }
-}
-
-@observer
-class Viewer extends React.Component {
- @observable
- private idToAdd: string = '';
-
- @observable
- private ids: string[] = [];
-
- @action
- inputOnChange = (e: React.ChangeEvent<HTMLInputElement>) => {
- this.idToAdd = e.target.value;
- }
-
- @action
- onKeyPress = (e: React.KeyboardEvent<HTMLDivElement>) => {
- if (e.key === "Enter") {
- this.ids.push(this.idToAdd);
- this.idToAdd = "";
- }
- }
-
- render() {
- return (
- <>
- <input value={this.idToAdd}
- onChange={this.inputOnChange}
- onKeyDown={this.onKeyPress} />
- <div>
- {this.ids.map(id => <DebugViewer fieldId={id} key={id}></DebugViewer>)}
- </div>
- </>
- );
- }
-}
-
-ReactDOM.render((
- <div style={{ position: "absolute", width: "100%", height: "100%" }}>
- <Viewer />
- </div>),
- document.getElementById('root')
-); \ No newline at end of file
+
+// configure({
+// enforceActions: "observed"
+// });
+
+// @observer
+// class FieldViewer extends React.Component<{ field: BasicField<any> }> {
+// render() {
+// return <span>{JSON.stringify(this.props.field.Data)} ({this.props.field.Id})</span>;
+// }
+// }
+
+// @observer
+// class KeyViewer extends React.Component<{ field: Key }> {
+// render() {
+// return this.props.field.Name;
+// }
+// }
+
+// @observer
+// class ListViewer extends React.Component<{ field: ListField<Field> }>{
+// @observable
+// expanded = false;
+
+// render() {
+// let content;
+// if (this.expanded) {
+// content = (
+// <div>
+// {this.props.field.Data.map(field => <DebugViewer fieldId={field.Id} key={field.Id} />)}
+// </div>
+// );
+// } else {
+// content = <>[...] ({this.props.field.Id})</>;
+// }
+// return (
+// <div>
+// <button onClick={action(() => this.expanded = !this.expanded)}>Toggle</button>
+// {content}
+// </div >
+// );
+// }
+// }
+
+// @observer
+// class DocumentViewer extends React.Component<{ field: Document }> {
+// private keyMap: ObservableMap<string, Key> = new ObservableMap;
+
+// private disposer?: Lambda;
+
+// componentDidMount() {
+// let f = () => {
+// Array.from(this.props.field._proxies.keys()).forEach(id => {
+// if (!this.keyMap.has(id)) {
+// Server.GetField(id, (field) => {
+// if (field && field instanceof Key) {
+// this.keyMap.set(id, field);
+// }
+// });
+// }
+// });
+// };
+// this.disposer = this.props.field._proxies.observe(f);
+// f();
+// }
+
+// componentWillUnmount() {
+// if (this.disposer) {
+// this.disposer();
+// }
+// }
+
+// render() {
+// let fields = Array.from(this.props.field._proxies.entries()).map(kv => {
+// let key = this.keyMap.get(kv[0]);
+// return (
+// <div key={kv[0]}>
+// <b>({key ? key.Name : kv[0]}): </b>
+// <DebugViewer fieldId={kv[1]}></DebugViewer>
+// </div>
+// );
+// });
+// return (
+// <div>
+// Document ({this.props.field.Id})
+// <div style={{ paddingLeft: "25px" }}>
+// {fields}
+// </div>
+// </div>
+// );
+// }
+// }
+
+// @observer
+// class DebugViewer extends React.Component<{ fieldId: string }> {
+// @observable
+// private field?: Field;
+
+// @observable
+// private error?: string;
+
+// constructor(props: { fieldId: string }) {
+// super(props);
+// this.update();
+// }
+
+// update() {
+// Server.GetField(this.props.fieldId, action((field: Opt<Field>) => {
+// this.field = field;
+// if (!field) {
+// this.error = `Field with id ${this.props.fieldId} not found`;
+// }
+// }));
+
+// }
+
+// render() {
+// let content;
+// if (this.field) {
+// // content = this.field.ToJson();
+// if (this.field instanceof ListField) {
+// content = (<ListViewer field={this.field} />);
+// } else if (this.field instanceof Document) {
+// content = (<DocumentViewer field={this.field} />);
+// } else if (this.field instanceof BasicField) {
+// content = (<FieldViewer field={this.field} />);
+// } else if (this.field instanceof Key) {
+// content = (<KeyViewer field={this.field} />);
+// } else {
+// content = (<span>Unrecognized field type</span>);
+// }
+// } else if (this.error) {
+// content = <span>Field <b>{this.props.fieldId}</b> not found <button onClick={() => this.update()}>Refresh</button></span>;
+// } else {
+// content = <span>Field loading: {this.props.fieldId}</span>;
+// }
+// return content;
+// }
+// }
+
+// @observer
+// class Viewer extends React.Component {
+// @observable
+// private idToAdd: string = '';
+
+// @observable
+// private ids: string[] = [];
+
+// @action
+// inputOnChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+// this.idToAdd = e.target.value;
+// }
+
+// @action
+// onKeyPress = (e: React.KeyboardEvent<HTMLDivElement>) => {
+// if (e.key === "Enter") {
+// this.ids.push(this.idToAdd);
+// this.idToAdd = "";
+// }
+// }
+
+// render() {
+// return (
+// <>
+// <input value={this.idToAdd}
+// onChange={this.inputOnChange}
+// onKeyDown={this.onKeyPress} />
+// <div>
+// {this.ids.map(id => <DebugViewer fieldId={id} key={id}></DebugViewer>)}
+// </div>
+// </>
+// );
+// }
+// }
+
+// ReactDOM.render((
+// <div style={{ position: "absolute", width: "100%", height: "100%" }}>
+// <Viewer />
+// </div>),
+// document.getElementById('root')
+// ); \ No newline at end of file
diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts
index 7f87be45d..ae532c9e2 100644
--- a/src/fields/ScriptField.ts
+++ b/src/fields/ScriptField.ts
@@ -1,101 +1,101 @@
-import { Field, FieldId } from "./Field";
-import { Types } from "../server/Message";
-import { CompileScript, ScriptOptions, CompiledScript } from "../client/util/Scripting";
-import { Server } from "../client/Server";
-import { Without } from "../Utils";
+// import { Field, FieldId } from "./Field";
+// import { Types } from "../server/Message";
+// import { CompileScript, ScriptOptions, CompiledScript } from "../client/util/Scripting";
+// import { Server } from "../client/Server";
+// import { Without } from "../Utils";
-export interface SerializableOptions extends Without<ScriptOptions, "capturedVariables"> {
- capturedIds: { [id: string]: string };
-}
+// export interface SerializableOptions extends Without<ScriptOptions, "capturedVariables"> {
+// capturedIds: { [id: string]: string };
+// }
-export interface ScriptData {
- script: string;
- options: SerializableOptions;
-}
+// export interface ScriptData {
+// script: string;
+// options: SerializableOptions;
+// }
-export class ScriptField extends Field {
- private _script?: CompiledScript;
- get script(): CompiledScript {
- return this._script!;
- }
- private options?: ScriptData;
+// export class ScriptField extends Field {
+// private _script?: CompiledScript;
+// get script(): CompiledScript {
+// return this._script!;
+// }
+// private options?: ScriptData;
- constructor(script?: CompiledScript, id?: FieldId, save: boolean = true) {
- super(id);
+// constructor(script?: CompiledScript, id?: FieldId, save: boolean = true) {
+// super(id);
- this._script = script;
+// this._script = script;
- if (save) {
- Server.UpdateField(this);
- }
- }
+// if (save) {
+// Server.UpdateField(this);
+// }
+// }
- ToScriptString() {
- return "new ScriptField(...)";
- }
+// ToScriptString() {
+// return "new ScriptField(...)";
+// }
- GetValue() {
- return this.script;
- }
+// GetValue() {
+// return this.script;
+// }
- TrySetValue(): boolean {
- throw new Error("Script fields currently can't be modified");
- }
+// TrySetValue(): boolean {
+// throw new Error("Script fields currently can't be modified");
+// }
- UpdateFromServer() {
- throw new Error("Script fields currently can't be updated");
- }
+// UpdateFromServer() {
+// throw new Error("Script fields currently can't be updated");
+// }
- static FromJson(id: string, data: ScriptData): ScriptField {
- let field = new ScriptField(undefined, id, false);
- field.options = data;
- return field;
- }
+// static FromJson(id: string, data: ScriptData): ScriptField {
+// let field = new ScriptField(undefined, id, false);
+// field.options = data;
+// return field;
+// }
- init(callback: (res: Field) => any) {
- const options = this.options!;
- const keys = Object.keys(options.options.capturedIds);
- Server.GetFields(keys).then(fields => {
- let captured: { [name: string]: Field } = {};
- keys.forEach(key => captured[options.options.capturedIds[key]] = fields[key]);
- const opts: ScriptOptions = {
- addReturn: options.options.addReturn,
- params: options.options.params,
- requiredType: options.options.requiredType,
- capturedVariables: captured
- };
- const script = CompileScript(options.script, opts);
- if (!script.compiled) {
- throw new Error("Can't compile script");
- }
- this._script = script;
- callback(this);
- });
- }
+// init(callback: (res: Field) => any) {
+// const options = this.options!;
+// const keys = Object.keys(options.options.capturedIds);
+// Server.GetFields(keys).then(fields => {
+// let captured: { [name: string]: Field } = {};
+// keys.forEach(key => captured[options.options.capturedIds[key]] = fields[key]);
+// const opts: ScriptOptions = {
+// addReturn: options.options.addReturn,
+// params: options.options.params,
+// requiredType: options.options.requiredType,
+// capturedVariables: captured
+// };
+// const script = CompileScript(options.script, opts);
+// if (!script.compiled) {
+// throw new Error("Can't compile script");
+// }
+// this._script = script;
+// callback(this);
+// });
+// }
- ToJson() {
- const { options, originalScript } = this.script;
- let capturedIds: { [id: string]: string } = {};
- for (const capt in options.capturedVariables) {
- capturedIds[options.capturedVariables[capt].Id] = capt;
- }
- const opts: SerializableOptions = {
- ...options,
- capturedIds
- };
- delete (opts as any).capturedVariables;
- return {
- id: this.Id,
- type: Types.Script,
- data: {
- script: originalScript,
- options: opts,
- },
- };
- }
+// ToJson() {
+// const { options, originalScript } = this.script;
+// let capturedIds: { [id: string]: string } = {};
+// for (const capt in options.capturedVariables) {
+// capturedIds[options.capturedVariables[capt].Id] = capt;
+// }
+// const opts: SerializableOptions = {
+// ...options,
+// capturedIds
+// };
+// delete (opts as any).capturedVariables;
+// return {
+// id: this.Id,
+// type: Types.Script,
+// data: {
+// script: originalScript,
+// options: opts,
+// },
+// };
+// }
- Copy(): Field {
- //Script fields are currently immutable, so we can fake copy them
- return this;
- }
-} \ No newline at end of file
+// Copy(): Field {
+// //Script fields are currently immutable, so we can fake copy them
+// return this;
+// }
+// } \ No newline at end of file
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
index ec89a1194..1f9e160ce 100644
--- a/src/mobile/ImageUpload.tsx
+++ b/src/mobile/ImageUpload.tsx
@@ -1,15 +1,14 @@
import * as ReactDOM from 'react-dom';
import * as rp from 'request-promise';
-import { Documents } from '../client/documents/Documents';
-import { Server } from '../client/Server';
-import { Document } from '../fields/Document';
-import { KeyStore } from '../fields/KeyStore';
-import { ListField } from '../fields/ListField';
+import { Docs } from '../client/documents/Documents';
import { RouteStore } from '../server/RouteStore';
-import { ServerUtils } from '../server/ServerUtil';
import "./ImageUpload.scss";
import React = require('react');
-import { Opt } from '../fields/Field';
+import { DocServer } from '../client/DocServer';
+import { Opt, Doc } from '../new_fields/Doc';
+import { Cast } from '../new_fields/Types';
+import { listSpec } from '../new_fields/Schema';
+import { List } from '../new_fields/List';
@@ -38,21 +37,24 @@ const onFileLoad = async (file: any) => {
const json = await res.json();
json.map(async (file: any) => {
let path = window.location.origin + file;
- var doc: Document = Documents.ImageDocument(path, { nativeWidth: 200, width: 200 });
+ var doc = Docs.ImageDocument(path, { nativeWidth: 200, width: 200 });
- const res = await rp.get(ServerUtils.prepend(RouteStore.getUserDocumentId));
+ const res = await rp.get(DocServer.prepend(RouteStore.getUserDocumentId));
if (!res) {
throw new Error("No user id returned");
}
- const field = await Server.GetField(res);
- let pending: Opt<Document>;
- if (field instanceof Document) {
- pending = await field.GetTAsync(KeyStore.OptionalRightCollection, Document);
+ const field = await DocServer.GetRefField(res);
+ let pending: Opt<Doc>;
+ if (field instanceof Doc) {
+ pending = await Cast(field.optionalRightCollection, Doc);
}
if (pending) {
- pending.GetOrCreateAsync(KeyStore.Data, ListField, list => {
- list.Data.push(doc);
- });
+ const data = await Cast(pending.data, listSpec(Doc));
+ if (data) {
+ data.push(doc);
+ } else {
+ pending.data = new List([doc]);
+ }
}
});
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 79e5a156d..6dfa37c1b 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -91,7 +91,7 @@ export namespace Doc {
return Cast(Get(doc, key, ignoreProto), ctor) as T | null | undefined;
}
export async function SetOnPrototype(doc: Doc, key: string, value: Field) {
- const proto = await Cast(doc.proto, Doc);
+ const proto = doc.proto;
if (proto) {
proto[key] = value;
}
@@ -166,6 +166,4 @@ export namespace Doc {
return delegate;
}
export const Prototype = Symbol("Prototype");
-}
-
-export const GetAsync = Doc.GetAsync; \ No newline at end of file
+} \ No newline at end of file
diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts
index cdb34cedf..49e6bf61e 100644
--- a/src/new_fields/InkField.ts
+++ b/src/new_fields/InkField.ts
@@ -27,5 +27,10 @@ const strokeDataSchema = createSimpleSchema({
export class InkField extends ObjectField {
@serializable(map(object(strokeDataSchema)))
- readonly inkData: Map<string, StrokeData> = new Map;
+ readonly inkData: Map<string, StrokeData>;
+
+ constructor(data?: Map<string, StrokeData>) {
+ super();
+ this.inkData = data || new Map;
+ }
}
diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts
index 079c7b76d..649dfdc3e 100644
--- a/src/new_fields/Types.ts
+++ b/src/new_fields/Types.ts
@@ -67,6 +67,10 @@ export function StrCast(field: FieldResult, defaultVal: Opt<string> = "") {
return Cast(field, "string", defaultVal);
}
+export function BoolCast(field: FieldResult, defaultVal: Opt<boolean> = undefined) {
+ return Cast(field, "boolean", defaultVal);
+}
+
type WithoutList<T extends Field> = T extends List<infer R> ? R[] : T;
export function FieldValue<T extends Field, U extends WithoutList<T>>(field: Opt<T> | Promise<Opt<T>>, defaultValue: U): WithoutList<T>;
diff --git a/src/server/authentication/controllers/WorkspacesMenu.tsx b/src/server/authentication/controllers/WorkspacesMenu.tsx
index b08c1aebe..29327e5ad 100644
--- a/src/server/authentication/controllers/WorkspacesMenu.tsx
+++ b/src/server/authentication/controllers/WorkspacesMenu.tsx
@@ -2,15 +2,15 @@ import * as React from 'react';
import { observable, action, configure, reaction, computed, ObservableMap, runInAction } from 'mobx';
import { observer } from "mobx-react";
import './WorkspacesMenu.css';
-import { Document } from '../../../fields/Document';
import { EditableView } from '../../../client/views/EditableView';
-import { KeyStore } from '../../../fields/KeyStore';
+import { Doc, Id } from '../../../new_fields/Doc';
+import { StrCast } from '../../../new_fields/Types';
export interface WorkspaceMenuProps {
- active: Document | undefined;
- open: (workspace: Document) => void;
+ active: Doc | undefined;
+ open: (workspace: Doc) => void;
new: () => void;
- allWorkspaces: Document[];
+ allWorkspaces: Doc[];
isShown: () => boolean;
toggle: () => void;
}
@@ -60,7 +60,7 @@ export class WorkspacesMenu extends React.Component<WorkspaceMenuProps> {
/>
{this.props.allWorkspaces.map((s, i) =>
<div
- key={s.Id}
+ key={s[Id]}
onContextMenu={(e) => {
e.preventDefault();
this.props.open(s);
@@ -73,9 +73,9 @@ export class WorkspacesMenu extends React.Component<WorkspaceMenuProps> {
<span>{i + 1} - </span>
<EditableView
display={"inline"}
- GetValue={() => s.Title}
+ GetValue={() => StrCast(s.title)}
SetValue={(title: string): boolean => {
- s.SetText(KeyStore.Title, title);
+ s.title = title;
return true;
}}
contents={s.Title}