From d808f36e6b874afd77bafd634e806b52203fa464 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Wed, 24 Apr 2019 21:11:40 -0400
Subject: PdfBox

---
 src/client/views/nodes/PDFBox.tsx | 56 ++++++++++++++++++++++-----------------
 1 file changed, 31 insertions(+), 25 deletions(-)

(limited to 'src/client/views/nodes/PDFBox.tsx')

diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 81ceb37f6..7fbfed1c0 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -6,10 +6,6 @@ import Measure from "react-measure";
 //@ts-ignore
 import { Document, Page } from "react-pdf";
 import 'react-pdf/dist/Page/AnnotationLayer.css';
-import { FieldWaiting, Opt } from '../../../fields/Field';
-import { ImageField } from '../../../fields/ImageField';
-import { KeyStore } from '../../../fields/KeyStore';
-import { PDFField } from '../../../fields/PDFField';
 import { RouteStore } from "../../../server/RouteStore";
 import { Utils } from '../../../Utils';
 import { Annotation } from './Annotation';
@@ -19,6 +15,13 @@ import "./PDFBox.scss";
 import { Sticky } from './Sticky'; //you should look at sticky and annotation, because they are used here
 import React = require("react");
 import { SelectionManager } from "../../util/SelectionManager";
+import { Cast, FieldValue } from "../../../new_fields/Types";
+import { Opt } from "../../../new_fields/Doc";
+import { DocComponent } from "../DocComponent";
+import { makeInterface } from "../../../new_fields/Schema";
+import { positionSchema } from "./DocumentView";
+import { pageSchema } from "./ImageBox";
+import { ImageField, PdfField } from "../../../new_fields/URLField";
 
 /** ALSO LOOK AT: Annotation.tsx, Sticky.tsx
  * This method renders PDF and puts all kinds of functionalities such as annotation, highlighting, 
@@ -51,8 +54,12 @@ import { SelectionManager } from "../../util/SelectionManager";
  * 
  * written by: Andrew Kim 
  */
+
+type PdfDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>;
+const PdfDocument = makeInterface(positionSchema, pageSchema);
+
 @observer
-export class PDFBox extends React.Component<FieldViewProps> {
+export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocument) {
     public static LayoutString() { return FieldView.LayoutString(PDFBox); }
 
     private _mainDiv = React.createRef<HTMLDivElement>();
@@ -89,8 +96,8 @@ export class PDFBox extends React.Component<FieldViewProps> {
     @observable private _interactive: boolean = false;
     @observable private _loaded: boolean = false;
 
-    @computed private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, 1); }
-    @computed private get thumbnailPage() { return this.props.Document.GetNumber(KeyStore.ThumbnailPage, -1); }
+    @computed private get curPage() { return FieldValue(this.Document.curPage, 1); }
+    @computed private get thumbnailPage() { return Cast(this.props.Document.thumbnailPage, "number", -1); }
 
     componentDidMount() {
         this._reactionDisposer = reaction(
@@ -380,14 +387,13 @@ export class PDFBox extends React.Component<FieldViewProps> {
     saveThumbnail = () => {
         this._renderAsSvg = false;
         setTimeout(() => {
-            var me = this;
-            let nwidth = me.props.Document.GetNumber(KeyStore.NativeWidth, 0);
-            let nheight = me.props.Document.GetNumber(KeyStore.NativeHeight, 0);
+            let nwidth = FieldValue(this.Document.nativeWidth, 0);
+            let nheight = FieldValue(this.Document.nativeHeight, 0);
             htmlToImage.toPng(this._mainDiv.current!, { width: nwidth, height: nheight, quality: 1 })
                 .then(action((dataUrl: string) => {
-                    me.props.Document.SetData(KeyStore.Thumbnail, new URL(dataUrl), ImageField);
-                    me.props.Document.SetNumber(KeyStore.ThumbnailPage, me.props.Document.GetNumber(KeyStore.CurPage, -1));
-                    me._renderAsSvg = true;
+                    this.props.Document.thumbnail = new ImageField(new URL(dataUrl));
+                    this.props.Document.thumbnailPage = FieldValue(this.Document.curPage, -1);
+                    this._renderAsSvg = true;
                 }))
                 .catch(function (error: any) {
                     console.error('oops, something went wrong!', error);
@@ -414,7 +420,7 @@ export class PDFBox extends React.Component<FieldViewProps> {
         }
 
         // bcz: the number of pages should really be set when the document is imported.
-        this.props.Document.SetNumber(KeyStore.NumPages, page._transport.numPages);
+        this.props.Document.numPages = page._transport.numPages;
         if (this._perPageInfo.length === 0) { //Makes sure it only runs once
             this._perPageInfo = [...Array(page._transport.numPages)];
         }
@@ -426,11 +432,11 @@ export class PDFBox extends React.Component<FieldViewProps> {
         // bcz: the nativeHeight should really be set when the document is imported.
         //      also, the native dimensions could be different for different pages of the PDF
         //      so this design is flawed.
-        var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0);
-        if (!this.props.Document.GetNumber(KeyStore.NativeHeight, 0)) {
+        var nativeWidth = FieldValue(this.Document.nativeWidth, 0);
+        if (!FieldValue(this.Document.nativeHeight, 0)) {
             var nativeHeight = nativeWidth * r.entry.height / r.entry.width;
-            this.props.Document.SetNumber(KeyStore.Height, nativeHeight / nativeWidth * this.props.Document.GetNumber(KeyStore.Width, 0));
-            this.props.Document.SetNumber(KeyStore.NativeHeight, nativeHeight);
+            this.props.Document.height = nativeHeight / nativeWidth * FieldValue(this.Document.width, 0);
+            this.props.Document.nativeHeight = nativeHeight;
         }
     }
 
@@ -438,8 +444,8 @@ export class PDFBox extends React.Component<FieldViewProps> {
     get pdfContent() {
         let page = this.curPage;
         const renderHeight = 2400;
-        let pdfUrl = this.props.Document.GetT(this.props.fieldKey, PDFField);
-        let xf = this.props.Document.GetNumber(KeyStore.NativeHeight, 0) / renderHeight;
+        let pdfUrl = Cast(this.props.Document[this.props.fieldKey], PdfField);
+        let xf = FieldValue(this.Document.nativeHeight, 0) / renderHeight;
         return <div className="pdfBox-contentContainer" key="container" style={{ transform: `scale(${xf}, ${xf})` }}>
             <Document file={window.origin + RouteStore.corsProxy + `/${pdfUrl}`} renderMode={this._renderAsSvg ? "svg" : ""}>
                 <Measure onResize={this.setScaling}>
@@ -456,8 +462,8 @@ export class PDFBox extends React.Component<FieldViewProps> {
     @computed
     get pdfRenderer() {
         let proxy = this._loaded ? (null) : this.imageProxyRenderer;
-        let pdfUrl = this.props.Document.GetT(this.props.fieldKey, PDFField);
-        if ((!this._interactive && proxy) || !pdfUrl || pdfUrl === FieldWaiting) {
+        let pdfUrl = Cast(this.props.Document[this.props.fieldKey], PdfField);
+        if ((!this._interactive && proxy) || !pdfUrl) {
             return proxy;
         }
         return [
@@ -470,10 +476,10 @@ export class PDFBox extends React.Component<FieldViewProps> {
 
     @computed
     get imageProxyRenderer() {
-        let thumbField = this.props.Document.Get(KeyStore.Thumbnail);
+        let thumbField = this.props.Document.thumbnail;
         if (thumbField) {
-            let path = thumbField === FieldWaiting || this.thumbnailPage !== this.curPage ? "https://image.flaticon.com/icons/svg/66/66163.svg" :
-                thumbField instanceof ImageField ? thumbField.Data.href : "http://cs.brown.edu/people/bcz/prairie.jpg";
+            let path = this.thumbnailPage !== this.curPage ? "https://image.flaticon.com/icons/svg/66/66163.svg" :
+                thumbField instanceof ImageField ? thumbField.url.href : "http://cs.brown.edu/people/bcz/prairie.jpg";
             return <img src={path} width="100%" />;
         }
         return (null);
-- 
cgit v1.2.3-70-g09d2


From a2751d16babb38cde2b86b1cb8fc5d74c15762d7 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Sun, 28 Apr 2019 00:23:18 -0400
Subject: Decent amount of stuff is working

---
 src/client/views/Main.tsx                                             | 2 +-
 src/client/views/collections/CollectionBaseView.tsx                   | 2 +-
 src/client/views/collections/CollectionPDFView.tsx                    | 3 ++-
 src/client/views/collections/CollectionVideoView.tsx                  | 3 ++-
 src/client/views/collections/CollectionView.tsx                       | 3 ++-
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx   | 2 +-
 src/client/views/nodes/CollectionFreeFormDocumentView.tsx             | 1 +
 src/client/views/nodes/DocumentView.tsx                               | 4 ++--
 src/client/views/nodes/FormattedTextBox.tsx                           | 3 ++-
 src/client/views/nodes/PDFBox.tsx                                     | 2 +-
 src/new_fields/RichTextField.ts                                       | 2 ++
 src/new_fields/Types.ts                                               | 2 +-
 12 files changed, 18 insertions(+), 11 deletions(-)

(limited to 'src/client/views/nodes/PDFBox.tsx')

diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 4a68d1c68..98c5a5306 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -165,7 +165,7 @@ export class Main extends React.Component {
     @action
     openWorkspace = async (doc: Doc, fromHistory = false) => {
         this.mainContainer = doc;
-        fromHistory || window.history.pushState(null, StrCast(doc.title), "/doc/" + doc.Id);
+        fromHistory || window.history.pushState(null, StrCast(doc.title), "/doc/" + doc[Id]);
         const col = await Cast(CurrentUserUtils.UserDocument.optionalRightCollection, Doc);
         // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized)
         setTimeout(async () => {
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index b2fba1415..ed761d3f3 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -95,7 +95,7 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
             //TODO This won't create the field if it doesn't already exist
             const value = Cast(props.Document[props.fieldKey], listSpec(Doc));
             if (value !== undefined) {
-                if (allowDuplicates || !value.some(v => v.Id === doc.Id)) {
+                if (allowDuplicates || !value.some(v => v[Id] === doc[Id])) {
                     value.push(doc);
                 }
             } else {
diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index 99438b4e8..5a1af354a 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -8,6 +8,7 @@ import { FieldView, FieldViewProps } from "../nodes/FieldView";
 import { CollectionRenderProps, CollectionBaseView, CollectionViewType } from "./CollectionBaseView";
 import { emptyFunction } from "../../../Utils";
 import { NumCast } from "../../../new_fields/Types";
+import { Id } from "../../../new_fields/RefField";
 
 
 @observer
@@ -33,7 +34,7 @@ export class CollectionPDFView extends React.Component<FieldViewProps> {
     }
 
     onContextMenu = (e: React.MouseEvent): void => {
-        if (!e.isPropagationStopped() && this.props.Document.Id !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
+        if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // 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: "PDFOptions", event: emptyFunction });
         }
     }
diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx
index d45be228a..7232ecea2 100644
--- a/src/client/views/collections/CollectionVideoView.tsx
+++ b/src/client/views/collections/CollectionVideoView.tsx
@@ -8,6 +8,7 @@ import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormV
 import { FieldView, FieldViewProps } from "../nodes/FieldView";
 import { emptyFunction } from "../../../Utils";
 import { NumCast } from "../../../new_fields/Types";
+import { Id } from "../../../new_fields/RefField";
 
 
 @observer
@@ -107,7 +108,7 @@ export class CollectionVideoView extends React.Component<FieldViewProps> {
     }
 
     onContextMenu = (e: React.MouseEvent): void => {
-        if (!e.isPropagationStopped() && this.props.Document.Id !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
+        if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // 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: "VideoOptions", event: emptyFunction });
         }
     }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index b72065bca..c2049a09a 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -10,6 +10,7 @@ import { CurrentUserUtils } from '../../../server/authentication/models/current_
 import { observer } from 'mobx-react';
 import { undoBatch } from '../../util/UndoManager';
 import { trace } from 'mobx';
+import { Id } from '../../../new_fields/RefField';
 
 @observer
 export class CollectionView extends React.Component<FieldViewProps> {
@@ -31,7 +32,7 @@ export class CollectionView extends React.Component<FieldViewProps> {
     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
+        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.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/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index dfacca204..dcded7648 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -257,7 +257,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             moveDocument: this.props.moveDocument,
             ScreenToLocalTransform: this.getTransform,
             isTopMost: false,
-            selectOnLoad: document.Id === this._selectOnLoaded,
+            selectOnLoad: document[Id] === this._selectOnLoaded,
             PanelWidth: () => Cast(document.width, "number", 0),//TODO Types These are inline functions
             PanelHeight: () => Cast(document.height, "number", 0),
             ContentScaling: returnOne,
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 376af0b36..8766eb7ea 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -20,6 +20,7 @@ const schema = createSchema({
     zIndex: "number"
 });
 
+//TODO Types: The import order is wrong, so positionSchema is undefined
 type FreeformDocument = makeInterface<[typeof schema, typeof positionSchema]>;
 const FreeformDocument = makeInterface(schema, positionSchema);
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c304b6a35..3814eeb9c 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -139,7 +139,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     onClick = (e: React.MouseEvent): void => {
-        if (CurrentUserUtils.MainDocId !== this.props.Document.Id &&
+        if (CurrentUserUtils.MainDocId !== this.props.Document[Id] &&
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
                 Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
             SelectionManager.SelectDoc(this, e.ctrlKey);
@@ -247,7 +247,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         ContextMenu.Instance.addItem({ description: "Fields", event: this.fieldsClicked });
         ContextMenu.Instance.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) });
         ContextMenu.Instance.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document) });
-        ContextMenu.Instance.addItem({ description: "Copy URL", event: () => Utils.CopyText(DocServer.prepend("/doc/" + this.props.Document.Id)) });
+        ContextMenu.Instance.addItem({ description: "Copy URL", event: () => Utils.CopyText(DocServer.prepend("/doc/" + this.props.Document[Id])) });
         ContextMenu.Instance.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]) });
         //ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking) })
         ContextMenu.Instance.addItem({ description: "Delete", event: this.deleteClicked });
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 96512718f..c4c720ca9 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -22,6 +22,7 @@ import { observer } from "mobx-react";
 import { InkingControl } from "../InkingControl";
 import { StrCast, Cast } from "../../../new_fields/Types";
 import { RichTextField } from "../../../new_fields/RichTextField";
+import { Id } from "../../../new_fields/RefField";
 const { buildMenuItems } = require("prosemirror-example-setup");
 const { menuBar } = require("prosemirror-menu");
 
@@ -108,7 +109,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         };
 
         if (this.props.isOverlay) {
-            this._inputReactionDisposer = reaction(() => MainOverlayTextBox.Instance.TextDoc && MainOverlayTextBox.Instance.TextDoc.Id,
+            this._inputReactionDisposer = reaction(() => MainOverlayTextBox.Instance.TextDoc && MainOverlayTextBox.Instance.TextDoc[Id],
                 () => {
                     if (this._editorView) {
                         this._editorView.destroy();
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 7fbfed1c0..9f0849492 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -447,7 +447,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         let pdfUrl = Cast(this.props.Document[this.props.fieldKey], PdfField);
         let xf = FieldValue(this.Document.nativeHeight, 0) / renderHeight;
         return <div className="pdfBox-contentContainer" key="container" style={{ transform: `scale(${xf}, ${xf})` }}>
-            <Document file={window.origin + RouteStore.corsProxy + `/${pdfUrl}`} renderMode={this._renderAsSvg ? "svg" : ""}>
+            <Document file={window.origin + RouteStore.corsProxy + `/${pdfUrl!.url.href}`} renderMode={this._renderAsSvg ? "svg" : ""}>
                 <Measure onResize={this.setScaling}>
                     {({ measureRef }) =>
                         <div className="pdfBox-page" ref={measureRef}>
diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts
index 0fa3cf73c..f2033d5a7 100644
--- a/src/new_fields/RichTextField.ts
+++ b/src/new_fields/RichTextField.ts
@@ -1,6 +1,8 @@
 import { ObjectField } from "./ObjectField";
 import { serializable } from "serializr";
+import { Deserializable } from "../client/util/SerializationHelper";
 
+@Deserializable("RichTextField")
 export class RichTextField extends ObjectField {
     @serializable(true)
     readonly Data: string;
diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts
index 3f8eabd45..e179c2602 100644
--- a/src/new_fields/Types.ts
+++ b/src/new_fields/Types.ts
@@ -76,7 +76,7 @@ type WithoutList<T extends Field> = T extends List<infer R> ? R[] : T;
 export function FieldValue<T extends Field, U extends WithoutList<T>>(field: FieldResult<T>, defaultValue: U): WithoutList<T>;
 export function FieldValue<T extends Field>(field: FieldResult<T>): Opt<T>;
 export function FieldValue<T extends Field>(field: FieldResult<T>, defaultValue?: T): Opt<T> {
-    return field instanceof Promise ? defaultValue : field;
+    return (field instanceof Promise || field === undefined) ? defaultValue : field;
 }
 
 export interface PromiseLike<T> {
-- 
cgit v1.2.3-70-g09d2

