From 171f285b5e61d7a0591578f1499f81b779a3c340 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 16 May 2019 15:54:34 -0400
Subject: fixed ? pdf rendering.   freezing text boxes.

---
 src/client/views/nodes/PDFBox.tsx | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 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 14fe2df80..f6328fa83 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -71,13 +71,14 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     @computed private get thumbnailPage() { return NumCast(this.props.Document.thumbnailPage, -1); }
 
     componentDidMount() {
+        let wasSelected = false;
         this._reactionDisposer = reaction(
-            () => [SelectionManager.SelectedDocuments().slice()],
+            () => this.props.isSelected(),
             () => {
-                if (this.curPage > 0 && this.thumbnailPage > 0 && this.curPage !== this.thumbnailPage && !this.props.isSelected()) {
+                if (this.curPage > 0 && this.curPage !== this.thumbnailPage && wasSelected && !this.props.isSelected()) {
                     this.saveThumbnail();
-                    this._interactive = true;
                 }
+                wasSelected = this._interactive = this.props.isSelected();
             },
             { fireImmediately: true });
 
@@ -256,7 +257,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
                 .catch(function (error: any) {
                     console.error('oops, something went wrong!', error);
                 });
-        }, 250);
+        }, 1250);
     }
 
     @action
@@ -283,24 +284,27 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     }
     @computed
     get pdfPage() {
-        return <Page height={this.renderHeight} pageNumber={this.curPage} onLoadSuccess={this.onLoaded} />;
+        console.log(this.curPage);
+        return <Page height={this.renderHeight} renderTextLayer={false} pageNumber={this.curPage} onLoadSuccess={this.onLoaded} />;
     }
     @computed
     get pdfContent() {
+        trace();
         let pdfUrl = Cast(this.props.Document[this.props.fieldKey], PdfField);
         if (!pdfUrl) {
             return <p>No pdf url to render</p>;
         }
-        let body = NumCast(this.props.Document.nativeHeight) ?
-            this.pdfPage :
+        let pdfpage = this.pdfPage;
+        let body = this.Document.nativeHeight ?
+            pdfpage :
             <Measure offset onResize={this.setScaling}>
                 {({ measureRef }) =>
                     <div className="pdfBox-page" ref={measureRef}>
-                        {this.pdfPage}
+                        {pdfpage}
                     </div>
                 }
             </Measure>;
-        let xf = NumCast(this.Document.nativeHeight) / this.renderHeight;
+        let xf = (this.Document.nativeHeight || 0) / this.renderHeight;
         return <div className="pdfBox-contentContainer" key="container" style={{ transform: `scale(${xf}, ${xf})` }}>
             <Document file={window.origin + RouteStore.corsProxy + `/${pdfUrl.url}`} renderMode={this._renderAsSvg ? "svg" : "canvas"}>
                 {body}
@@ -336,7 +340,8 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     @action onKeyDown = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = true);
     @action onKeyUp = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = false);
     render() {
-        let classname = "pdfBox-cont"; // + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : "");
+        trace();
+        let classname = "pdfBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : "");
         return (
             <div className={classname} tabIndex={0} ref={this._mainDiv} onPointerDown={this.onPointerDown} onKeyDown={this.onKeyDown} onKeyUp={this.onKeyUp} >
                 {this.pdfRenderer}
-- 
cgit v1.2.3-70-g09d2


From 530dc40f7519b8288d91db61103468ab713dfbdd Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 16 May 2019 21:02:15 -0400
Subject: fixed some small layout issues related to isButton and  templates

---
 src/client/views/Templates.tsx                  | 4 ++--
 src/client/views/nodes/DocumentContentsView.tsx | 8 ++++++--
 src/client/views/nodes/DocumentView.tsx         | 3 +++
 src/client/views/nodes/ImageBox.scss            | 6 +++++-
 src/client/views/nodes/ImageBox.tsx             | 3 +--
 src/client/views/nodes/PDFBox.tsx               | 1 -
 6 files changed, 17 insertions(+), 8 deletions(-)

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

diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx
index 5d29e68ae..5a99b3d90 100644
--- a/src/client/views/Templates.tsx
+++ b/src/client/views/Templates.tsx
@@ -74,8 +74,8 @@ export namespace Templates {
     export function ImageOverlay(width: number, height: number, field: string = "thumbnail") {
         return (`<div>
                 <div style="height:100%; width:100%; position:absolute;">{layout}</div>
-                <div style="height:${height}px; bottom:0; right:0; background:rgba(0,0,0,0.25); position:absolute;overflow:hidden;">
-                    <ImageBox id="isExpander" {...props} PanelWidth={${width}} fieldKey={"${field}"} />
+                <div style="height:auto; width:${width}px; bottom:0; right:0; background:rgba(0,0,0,0.25); position:absolute;overflow:hidden;">
+                    <ImageBox id="isExpander" {...props} style="width:100%; height=auto;" PanelWidth={${width}} fieldKey={"${field}"} />
                 </div>
             </div>`);
     }
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index f3d76c49b..ace8d4aa5 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -21,7 +21,7 @@ import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox";
 import React = require("react");
 import { FieldViewProps } from "./FieldView";
 import { Without, OmitKeys } from "../../../Utils";
-import { Cast, StrCast } from "../../../new_fields/Types";
+import { Cast, StrCast, NumCast } from "../../../new_fields/Types";
 import { List } from "../../../new_fields/List";
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
@@ -76,9 +76,13 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
             (this.props.layoutKey === "layout" && StrCast(this.props.Document.layout).indexOf("CollectionView") === -1)) {
             this.templates.forEach(template => {
                 let self = this;
+                // this scales constants in the markup by the scaling applied to the document, but caps the constants to be smaller
+                // than the width/height of the containing document
                 function convertConstantsToNative(match: string, offset: number, x: string) {
                     let px = Number(match.replace("px", ""));
-                    return `${px * self.props.ScreenToLocalTransform().Scale}px`;
+                    return `${Math.min(NumCast(self.props.Document.height, 0),
+                        Math.min(NumCast(self.props.Document.width, 0),
+                            px * self.props.ScreenToLocalTransform().Scale))}px`;
                 }
                 let nativizedTemplate = template.replace(/([0-9]+)px/g, convertConstantsToNative);
                 layout = nativizedTemplate.replace("{layout}", base);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 428dd9b36..40ad55d25 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -224,6 +224,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         if (doc.isButton && !doc.nativeWidth) {
             doc.nativeWidth = this.props.Document[WidthSym]();
             doc.nativeHeight = this.props.Document[HeightSym]();
+        } else {
+
+            doc.nativeWidth = doc.nativeHeight = undefined;
         }
     }
     fullScreenClicked = (e: React.MouseEvent): void => {
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index 2316a050e..f1b73a676 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -25,7 +25,11 @@
 }
 
 .imageBox-cont img {
-    height: 100%;
+    height: auto;
+    width:100%;
+}
+.imageBox-cont-interactive img {
+    height: auto;
     width:100%;
 }
 
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 3cc60a6c5..a06adfcf0 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -42,8 +42,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
     onLoad = (target: any) => {
         var h = this._imgRef.current!.naturalHeight;
         var w = this._imgRef.current!.naturalWidth;
-        console.log("title: " + this.Document.title);
-        if (this._photoIndex === 0) {
+        if (this._photoIndex === 0 && (this.props as any).id !== "isExpander") {
             Doc.SetOnPrototype(this.Document, "nativeHeight", FieldValue(this.Document.nativeWidth, 0) * h / w);
             this.Document.height = FieldValue(this.Document.width, 0) * h / w;
         }
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index f6328fa83..e71ac4924 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -284,7 +284,6 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     }
     @computed
     get pdfPage() {
-        console.log(this.curPage);
         return <Page height={this.renderHeight} renderTextLayer={false} pageNumber={this.curPage} onLoadSuccess={this.onLoaded} />;
     }
     @computed
-- 
cgit v1.2.3-70-g09d2


From e02e8bee7ee36490b83edb0a416978216b0f4a17 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 20 May 2019 15:46:21 -0400
Subject: hooking up image data url stuff.

---
 src/client/views/SearchBox.tsx    | 17 +++++++++++++++++
 src/client/views/nodes/PDFBox.tsx | 10 +++++++---
 src/server/index.ts               |  8 +++++---
 3 files changed, 29 insertions(+), 6 deletions(-)

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

diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx
index 8efd8d266..0ec1a6758 100644
--- a/src/client/views/SearchBox.tsx
+++ b/src/client/views/SearchBox.tsx
@@ -20,6 +20,7 @@ import { Id } from '../../new_fields/FieldSymbols';
 import { DocumentManager } from '../util/DocumentManager';
 import { SetupDrag } from '../util/DragManager';
 import { Docs } from '../documents/Documents';
+import { RouteStore } from '../../server/RouteStore';
 
 library.add(faSearch);
 library.add(faObjectGroup);
@@ -70,6 +71,22 @@ export class SearchBox extends React.Component {
         }
         return docs;
     }
+    public static async convertDataUri(imageUri: string, returnedFilename: string) {
+        try {
+            let posting = DocServer.prepend(RouteStore.dataUriToImage);
+            const returnedUri = await rp.post(posting, {
+                body: {
+                    uri: imageUri,
+                    name: returnedFilename
+                },
+                json: true,
+            });
+            return returnedUri;
+
+        } catch (e) {
+            console.log(e);
+        }
+    }
 
     @action
     handleClickFilter = (e: Event): void => {
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index e71ac4924..1017f5235 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -21,6 +21,8 @@ import { positionSchema } from "./DocumentView";
 import { pageSchema } from "./ImageBox";
 import { ImageField, PdfField } from "../../../new_fields/URLField";
 import { InkingControl } from "../InkingControl";
+import { SearchBox } from "../SearchBox";
+import { Id } from "../../../new_fields/FieldSymbols";
 
 /** ALSO LOOK AT: Annotation.tsx, Sticky.tsx
  * This method renders PDF and puts all kinds of functionalities such as annotation, highlighting, 
@@ -250,9 +252,11 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
             let nheight = FieldValue(this.Document.nativeHeight, 0);
             htmlToImage.toPng(this._mainDiv.current!, { width: nwidth, height: nheight, quality: 1 })
                 .then(action((dataUrl: string) => {
-                    this.props.Document.thumbnail = new ImageField(new URL(dataUrl));
-                    this.props.Document.thumbnailPage = FieldValue(this.Document.curPage, -1);
-                    this._renderAsSvg = true;
+                    SearchBox.convertDataUri(dataUrl, this.Document[Id] + "_" + this.curPage).then((returnedFilename) => {
+                        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);
diff --git a/src/server/index.ts b/src/server/index.ts
index a12751fe3..6843afbe4 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -114,6 +114,8 @@ function addSecureRoute(method: Method,
 app.use(express.static(__dirname + RouteStore.public));
 app.use(RouteStore.images, express.static(__dirname + RouteStore.public));
 
+app.use(express.json());
+
 app.get("/pull", (req, res) =>
     exec('"C:\\Program Files\\Git\\git-bash.exe" -c "git pull"', (err, stdout, stderr) => {
         if (err) {
@@ -220,10 +222,10 @@ addSecureRoute(
 addSecureRoute(
     Method.POST,
     (user, res, req) => {
-        const uri = req.query.uri;
-        const filename = req.query.name;
+        const uri = req.body.uri;
+        const filename = req.body.name;
         if (!uri || !filename) {
-            res.status(400).send("incorrect parameters specified");
+            res.status(401).send("incorrect parameters specified");
             return;
         }
         imageDataUri.outputFile(uri, uploadDir + filename).then((savedName: string) => {
-- 
cgit v1.2.3-70-g09d2


From 059faf25a0f8ba80e1d2853dcefa1a70df4cbb6a Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 20 May 2019 17:10:21 -0400
Subject: fixed icons for pdfs.  fixed activeItem issue for golden layout.

---
 src/client/goldenLayout.js                         |  2 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  1 +
 src/client/views/nodes/PDFBox.tsx                  | 58 +++++++++++-----------
 3 files changed, 31 insertions(+), 30 deletions(-)

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

diff --git a/src/client/goldenLayout.js b/src/client/goldenLayout.js
index ab2bcefed..54c9c6068 100644
--- a/src/client/goldenLayout.js
+++ b/src/client/goldenLayout.js
@@ -4466,7 +4466,7 @@
             }
 
             if (this.contentItems.length > 0) {
-                initialItem = this.contentItems[this.config.activeItemIndex || 0];
+                initialItem = this.contentItems[Math.min(this.contentItems.length - 1, this.config.activeItemIndex || 0)];
 
                 if (!initialItem) {
                     throw new Error('Configured activeItemIndex out of bounds');
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 5bff08280..fa2b09ba7 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -189,6 +189,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
         if (this._doubleTap) {
             this.props.addDocTab(this.props.Document, "inTab");
             SelectionManager.DeselectAll();
+            this.props.Document.libraryBrush = false;
         }
         let altKey = e.altKey;
         if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 1017f5235..d1b9098b0 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -1,28 +1,27 @@
 import * as htmlToImage from "html-to-image";
-import { action, computed, IReactionDisposer, observable, reaction, Reaction, trace, runInAction } from 'mobx';
+import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx';
 import { observer } from "mobx-react";
 import 'react-image-lightbox/style.css';
 import Measure from "react-measure";
 //@ts-ignore
 import { Document, Page } from "react-pdf";
 import 'react-pdf/dist/Page/AnnotationLayer.css';
+import { Id } from "../../../new_fields/FieldSymbols";
+import { makeInterface } from "../../../new_fields/Schema";
+import { Cast, FieldValue, NumCast } from "../../../new_fields/Types";
+import { ImageField, PdfField } from "../../../new_fields/URLField";
 import { RouteStore } from "../../../server/RouteStore";
 import { Utils } from '../../../Utils';
+import { DocServer } from "../../DocServer";
+import { DocComponent } from "../DocComponent";
+import { InkingControl } from "../InkingControl";
+import { SearchBox } from "../SearchBox";
 import { Annotation } from './Annotation';
+import { positionSchema } from "./DocumentView";
 import { FieldView, FieldViewProps } from './FieldView';
+import { pageSchema } from "./ImageBox";
 import "./PDFBox.scss";
 import React = require("react");
-import { SelectionManager } from "../../util/SelectionManager";
-import { Cast, FieldValue, NumCast } 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";
-import { InkingControl } from "../InkingControl";
-import { SearchBox } from "../SearchBox";
-import { Id } from "../../../new_fields/FieldSymbols";
 
 /** ALSO LOOK AT: Annotation.tsx, Sticky.tsx
  * This method renders PDF and puts all kinds of functionalities such as annotation, highlighting, 
@@ -73,11 +72,11 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     @computed private get thumbnailPage() { return NumCast(this.props.Document.thumbnailPage, -1); }
 
     componentDidMount() {
-        let wasSelected = false;
+        let wasSelected = this.props.isSelected();
         this._reactionDisposer = reaction(
-            () => this.props.isSelected(),
+            () => [this.props.isSelected(), this.curPage],
             () => {
-                if (this.curPage > 0 && this.curPage !== this.thumbnailPage && wasSelected && !this.props.isSelected()) {
+                if (this.curPage > 0 && !this.props.isTopMost && this.curPage !== this.thumbnailPage && wasSelected && !this.props.isSelected()) {
                     this.saveThumbnail();
                 }
                 wasSelected = this._interactive = this.props.isSelected();
@@ -246,16 +245,19 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
 
     @action
     saveThumbnail = () => {
+        this.props.Document.thumbnailPage = FieldValue(this.Document.curPage, -1);
         this._renderAsSvg = false;
         setTimeout(() => {
             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 })
+            htmlToImage.toPng(this._mainDiv.current!, { width: nwidth, height: nheight, quality: 0.8 })
                 .then(action((dataUrl: string) => {
-                    SearchBox.convertDataUri(dataUrl, this.Document[Id] + "_" + this.curPage).then((returnedFilename) => {
-                        this.props.Document.thumbnail = new ImageField(new URL(dataUrl));
-                        this.props.Document.thumbnailPage = FieldValue(this.Document.curPage, -1);
-                        this._renderAsSvg = true;
+                    SearchBox.convertDataUri(dataUrl, "icon" + this.Document[Id] + "_" + this.curPage).then((returnedFilename) => {
+                        if (returnedFilename) {
+                            let url = DocServer.prepend(returnedFilename);
+                            this.props.Document.thumbnail = new ImageField(new URL(url));
+                        }
+                        runInAction(() => this._renderAsSvg = true);
                     })
                 }))
                 .catch(function (error: any) {
@@ -292,7 +294,6 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     }
     @computed
     get pdfContent() {
-        trace();
         let pdfUrl = Cast(this.props.Document[this.props.fieldKey], PdfField);
         if (!pdfUrl) {
             return <p>No pdf url to render</p>;
@@ -309,7 +310,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
             </Measure>;
         let xf = (this.Document.nativeHeight || 0) / this.renderHeight;
         return <div className="pdfBox-contentContainer" key="container" style={{ transform: `scale(${xf}, ${xf})` }}>
-            <Document file={window.origin + RouteStore.corsProxy + `/${pdfUrl.url}`} renderMode={this._renderAsSvg ? "svg" : "canvas"}>
+            <Document file={window.origin + RouteStore.corsProxy + `/${pdfUrl.url}`} renderMode={this._renderAsSvg || this.props.isTopMost ? "svg" : "canvas"}>
                 {body}
             </Document>
         </div >;
@@ -317,26 +318,25 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
 
     @computed
     get pdfRenderer() {
-        let proxy = this._loaded ? (null) : this.imageProxyRenderer;
         let pdfUrl = Cast(this.props.Document[this.props.fieldKey], PdfField);
-        if ((!this._interactive && proxy) || !pdfUrl) {
+        let proxy = this.imageProxyRenderer;
+        if ((!this._interactive && proxy && (!this.props.ContainingCollectionView || !this.props.ContainingCollectionView.props.isTopMost)) || !pdfUrl) {
             return proxy;
         }
         return [
             this._pageInfo.area.filter(() => this._pageInfo.area).map((element: any) => element),
             this._currAnno.map((element: any) => element),
-            this.pdfContent,
-            proxy
+            this.pdfContent
         ];
     }
 
     @computed
     get imageProxyRenderer() {
         let thumbField = this.props.Document.thumbnail;
-        if (thumbField) {
-            let path = this.thumbnailPage !== this.curPage ? "https://image.flaticon.com/icons/svg/66/66163.svg" :
+        if (thumbField && this._renderAsSvg) {
+            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 <img key={Utils.GenerateGuid()} src={path} width="100%" />;
         }
         return (null);
     }
-- 
cgit v1.2.3-70-g09d2


From e5c9ba12e9a50a688e8c1554b525c87b1efbafb8 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 20 May 2019 17:23:09 -0400
Subject: added s/m/l icons for pdf rendering.

---
 src/client/views/nodes/ImageBox.tsx |  1 -
 src/client/views/nodes/PDFBox.tsx   | 43 +++++++++++++++++++++++++++++++++----
 2 files changed, 39 insertions(+), 5 deletions(-)

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

diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index a2291c7cf..8156ec872 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -19,7 +19,6 @@ import { InkingControl } from '../InkingControl';
 import { Doc } from '../../../new_fields/Doc';
 import { faImage } from '@fortawesome/free-solid-svg-icons';
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 var path = require('path');
 
 library.add(faImage);
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index d1b9098b0..2a59eb7e5 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -21,6 +21,7 @@ import { positionSchema } from "./DocumentView";
 import { FieldView, FieldViewProps } from './FieldView';
 import { pageSchema } from "./ImageBox";
 import "./PDFBox.scss";
+var path = require('path');
 import React = require("react");
 
 /** ALSO LOOK AT: Annotation.tsx, Sticky.tsx
@@ -330,20 +331,54 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         ];
     }
 
+    choosePath(url: URL) {
+        if (url.protocol === "data" || url.href.indexOf(window.location.origin) === -1)
+            return url.href;
+        let ext = path.extname(url.href);
+        return url.href.replace(ext, this._curSuffix + ext);
+    }
+    @observable _smallRetryCount = 1;
+    @observable _mediumRetryCount = 1;
+    @observable _largeRetryCount = 1;
+    @action retryPath = () => {
+        if (this._curSuffix === "_s") this._smallRetryCount++;
+        if (this._curSuffix === "_m") this._mediumRetryCount++;
+        if (this._curSuffix === "_l") this._largeRetryCount++;
+    }
+    @action onError = () => {
+        let timeout = this._curSuffix === "_s" ? this._smallRetryCount : this._curSuffix === "_m" ? this._mediumRetryCount : this._largeRetryCount;
+        if (timeout < 10)
+            setTimeout(this.retryPath, Math.min(10000, timeout * 5));
+    }
+    _curSuffix = "";
+
     @computed
     get imageProxyRenderer() {
         let thumbField = this.props.Document.thumbnail;
         if (thumbField && this._renderAsSvg) {
-            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 key={Utils.GenerateGuid()} src={path} width="100%" />;
+
+            let transform = this.props.ScreenToLocalTransform().inverse();
+            let pw = typeof this.props.PanelWidth === "function" ? this.props.PanelWidth() : typeof this.props.PanelWidth === "number" ? (this.props.PanelWidth as any) as number : 50;
+            var [sptX, sptY] = transform.transformPoint(0, 0);
+            let [bptX, bptY] = transform.transformPoint(pw, this.props.PanelHeight());
+            let w = bptX - sptX;
+
+            let path = thumbField instanceof ImageField ? thumbField.url.href : "http://cs.brown.edu/people/bcz/prairie.jpg";
+            this._curSuffix = "";
+            if (w > 20) {
+                let field = thumbField;
+                if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s";
+                else if (w < 400 && this._mediumRetryCount < 10) this._curSuffix = "_m";
+                else if (this._largeRetryCount < 10) this._curSuffix = "_l";
+                if (field instanceof ImageField) path = this.choosePath(field.url);
+            }
+            return <img key={path} src={path} width="100%" />;
         }
         return (null);
     }
     @action onKeyDown = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = true);
     @action onKeyUp = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = false);
     render() {
-        trace();
         let classname = "pdfBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : "");
         return (
             <div className={classname} tabIndex={0} ref={this._mainDiv} onPointerDown={this.onPointerDown} onKeyDown={this.onKeyDown} onKeyUp={this.onKeyUp} >
-- 
cgit v1.2.3-70-g09d2


From 70930405f8bdf43c05a77cb3dcbdadcbd3c9ab70 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Mon, 20 May 2019 19:10:10 -0400
Subject: PDF and Image test Context work

---
 .../views/collections/CollectionDockingView.tsx    |  3 ++-
 .../views/collections/ParentDocumentSelector.scss  | 10 ++++++++
 .../views/collections/ParentDocumentSelector.tsx   | 24 ++++++++++++++-----
 src/client/views/nodes/ImageBox.tsx                | 28 +++++++++++-----------
 src/client/views/nodes/PDFBox.tsx                  | 26 ++++++++++----------
 src/new_fields/Doc.ts                              | 13 ++++++----
 6 files changed, 65 insertions(+), 39 deletions(-)

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

diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 9721bf804..180a8be46 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -332,7 +332,8 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
                     let counter: any = this.htmlToElement(`<span class="messageCounter">0</div>`);
                     tab.element.append(counter);
                     let upDiv = document.createElement("span");
-                    ReactDOM.render(<ParentDocSelector Document={doc} />, upDiv);
+                    const stack = tab.contentItem.parent;
+                    ReactDOM.render(<ParentDocSelector Document={doc} addDocTab={(doc, location) => CollectionDockingView.Instance.AddTab(stack, doc)} />, upDiv);
                     tab.reactComponents = [upDiv];
                     tab.element.append(upDiv);
                     counter.DashDocId = tab.contentItem.config.props.documentId;
diff --git a/src/client/views/collections/ParentDocumentSelector.scss b/src/client/views/collections/ParentDocumentSelector.scss
index f3c605f3e..1ab12bb72 100644
--- a/src/client/views/collections/ParentDocumentSelector.scss
+++ b/src/client/views/collections/ParentDocumentSelector.scss
@@ -5,4 +5,14 @@
     box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
     min-width: 150px;
     color: black;
+
+    hr {
+        height: 1px;
+        margin: 0px;
+        background-color: gray;
+        border-top: 0px;
+        border-bottom: 0px;
+        border-right: 0px;
+        border-left: 0px;
+    }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index 4d07c31a7..65ae7f9ec 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -7,32 +7,44 @@ import { Id } from "../../../new_fields/FieldSymbols";
 import { SearchUtil } from "../../util/SearchUtil";
 import { CollectionDockingView } from "./CollectionDockingView";
 
+type SelectorProps = { Document: Doc, addDocTab(doc: Doc, location: string): void };
 @observer
-export class SelectorContextMenu extends React.Component<{ Document: Doc }> {
+export class SelectorContextMenu extends React.Component<SelectorProps> {
     @observable private _docs: Doc[] = [];
+    @observable private _otherDocs: Doc[] = [];
 
-    constructor(props: { Document: Doc }) {
+    constructor(props: SelectorProps) {
         super(props);
 
         this.fetchDocuments();
     }
 
     async fetchDocuments() {
+        let aliases = (await SearchUtil.GetAliasesOfDocument(this.props.Document)).filter(doc => doc !== this.props.Document);
         const docs = await SearchUtil.Search(`data_l:"${this.props.Document[Id]}"`, true);
-        runInAction(() => this._docs = docs);
+        const otherDocs: Set<Doc> = new Set;
+        const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search(`data_l:"${doc[Id]}"`, true)));
+        allDocs.forEach(docs => docs.forEach(doc => otherDocs.add(doc)));
+        docs.forEach(doc => otherDocs.delete(doc));
+        runInAction(() => {
+            this._docs = docs.filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance.props.Document));
+            this._otherDocs = Array.from(otherDocs).filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance.props.Document));
+        });
     }
 
     render() {
         return (
             <>
-                {this._docs.map(doc => <p><a onClick={() => CollectionDockingView.Instance.AddRightSplit(doc)}>{doc.title}</a></p>)}
+                {this._docs.map(doc => <p><a onClick={() => this.props.addDocTab(Doc.IsPrototype(doc) ? Doc.MakeDelegate(doc) : doc, "inTab")}>{doc.title}</a></p>)}
+                {this._otherDocs.length ? <hr></hr> : null}
+                {this._otherDocs.map(doc => <p><a onClick={() => this.props.addDocTab(Doc.IsPrototype(doc) ? Doc.MakeDelegate(doc) : doc, "inTab")}>{doc.title}</a></p>)}
             </>
         );
     }
 }
 
 @observer
-export class ParentDocSelector extends React.Component<{ Document: Doc }> {
+export class ParentDocSelector extends React.Component<SelectorProps> {
     @observable hover = false;
 
     @action
@@ -50,7 +62,7 @@ export class ParentDocSelector extends React.Component<{ Document: Doc }> {
         if (this.hover) {
             flyout = (
                 <div className="PDS-flyout">
-                    <SelectorContextMenu Document={this.props.Document} />
+                    <SelectorContextMenu {...this.props} />
                 </div>
             );
         }
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 8156ec872..e022793eb 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -181,26 +181,26 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
         if (timeout < 10)
             setTimeout(this.retryPath, Math.min(10000, timeout * 5));
     }
-    _curSuffix = "";
+    _curSuffix = "_m";
     render() {
-        let transform = this.props.ScreenToLocalTransform().inverse();
+        // let transform = this.props.ScreenToLocalTransform().inverse();
         let pw = typeof this.props.PanelWidth === "function" ? this.props.PanelWidth() : typeof this.props.PanelWidth === "number" ? (this.props.PanelWidth as any) as number : 50;
-        var [sptX, sptY] = transform.transformPoint(0, 0);
-        let [bptX, bptY] = transform.transformPoint(pw, this.props.PanelHeight());
-        let w = bptX - sptX;
+        // var [sptX, sptY] = transform.transformPoint(0, 0);
+        // let [bptX, bptY] = transform.transformPoint(pw, this.props.PanelHeight());
+        // let w = bptX - sptX;
 
         let id = (this.props as any).id; // bcz: used to set id = "isExpander" in templates.tsx
         let nativeWidth = FieldValue(this.Document.nativeWidth, pw);
         let paths: string[] = ["http://www.cs.brown.edu/~bcz/noImage.png"];
-        this._curSuffix = "";
-        if (w > 20) {
-            let field = this.Document[this.props.fieldKey];
-            if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s";
-            else if (w < 600 && this._mediumRetryCount < 10) this._curSuffix = "_m";
-            else if (this._largeRetryCount < 10) this._curSuffix = "_l";
-            if (field instanceof ImageField) paths = [this.choosePath(field.url)];
-            else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => this.choosePath((p as ImageField).url));
-        }
+        // this._curSuffix = "";
+        // if (w > 20) {
+        let field = this.Document[this.props.fieldKey];
+        // if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s";
+        // else if (w < 600 && this._mediumRetryCount < 10) this._curSuffix = "_m";
+        // else if (this._largeRetryCount < 10) this._curSuffix = "_l";
+        if (field instanceof ImageField) paths = [this.choosePath(field.url)];
+        else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => this.choosePath((p as ImageField).url));
+        // }
         let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive";
         return (
             <div id={id} className={`imageBox-cont${interactive}`}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 2a59eb7e5..3bffdd02d 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -350,28 +350,28 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         if (timeout < 10)
             setTimeout(this.retryPath, Math.min(10000, timeout * 5));
     }
-    _curSuffix = "";
+    _curSuffix = "_m";
 
     @computed
     get imageProxyRenderer() {
         let thumbField = this.props.Document.thumbnail;
         if (thumbField && this._renderAsSvg) {
 
-            let transform = this.props.ScreenToLocalTransform().inverse();
+            // let transform = this.props.ScreenToLocalTransform().inverse();
             let pw = typeof this.props.PanelWidth === "function" ? this.props.PanelWidth() : typeof this.props.PanelWidth === "number" ? (this.props.PanelWidth as any) as number : 50;
-            var [sptX, sptY] = transform.transformPoint(0, 0);
-            let [bptX, bptY] = transform.transformPoint(pw, this.props.PanelHeight());
-            let w = bptX - sptX;
+            // var [sptX, sptY] = transform.transformPoint(0, 0);
+            // let [bptX, bptY] = transform.transformPoint(pw, this.props.PanelHeight());
+            // let w = bptX - sptX;
 
             let path = thumbField instanceof ImageField ? thumbField.url.href : "http://cs.brown.edu/people/bcz/prairie.jpg";
-            this._curSuffix = "";
-            if (w > 20) {
-                let field = thumbField;
-                if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s";
-                else if (w < 400 && this._mediumRetryCount < 10) this._curSuffix = "_m";
-                else if (this._largeRetryCount < 10) this._curSuffix = "_l";
-                if (field instanceof ImageField) path = this.choosePath(field.url);
-            }
+            // this._curSuffix = "";
+            // if (w > 20) {
+            let field = thumbField;
+            // if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s";
+            // else if (w < 400 && this._mediumRetryCount < 10) this._curSuffix = "_m";
+            // else if (this._largeRetryCount < 10) this._curSuffix = "_l";
+            if (field instanceof ImageField) path = this.choosePath(field.url);
+            // }
             return <img key={path} src={path} width="100%" />;
         }
         return (null);
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index f4514c33e..92d3c140a 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -149,6 +149,9 @@ export namespace Doc {
     export function GetT<T extends Field>(doc: Doc, key: string, ctor: ToConstructor<T>, ignoreProto: boolean = false): FieldResult<T> {
         return Cast(Get(doc, key, ignoreProto), ctor) as FieldResult<T>;
     }
+    export function IsPrototype(doc: Doc) {
+        return GetT(doc, "isPrototype", "boolean", true);
+    }
     export async function SetOnPrototype(doc: Doc, key: string, value: Field) {
         const proto = Object.getOwnPropertyNames(doc).indexOf("isPrototype") === -1 ? doc.proto : doc;
 
@@ -180,11 +183,11 @@ export namespace Doc {
 
     // compare whether documents or their protos match
     export function AreProtosEqual(doc: Doc, other: Doc) {
-        let r = (doc[Id] === other[Id]);
-        let r2 = (doc.proto && doc.proto.Id === other[Id]);
-        let r3 = (other.proto && other.proto.Id === doc[Id]);
-        let r4 = (doc.proto && other.proto && doc.proto[Id] === other.proto[Id]);
-        return r || r2 || r3 || r4 ? true : false;
+        let r = (doc === other);
+        let r2 = (doc.proto === other);
+        let r3 = (other.proto === doc);
+        let r4 = (doc.proto === other.proto);
+        return r || r2 || r3 || r4;
     }
 
     // gets the document's prototype or returns the document if it is a prototype
-- 
cgit v1.2.3-70-g09d2


From e878910abf712f53113994b4d6f242b5c2231453 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Wed, 22 May 2019 11:57:37 -0400
Subject: Pdf proxy rendering

---
 src/client/views/nodes/PDFBox.tsx | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(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 3bffdd02d..5b8b15ed8 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -249,6 +249,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         this.props.Document.thumbnailPage = FieldValue(this.Document.curPage, -1);
         this._renderAsSvg = false;
         setTimeout(() => {
+            runInAction(() => this._smallRetryCount = this._mediumRetryCount = this._largeRetryCount = 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: 0.8 })
@@ -325,6 +326,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
             return proxy;
         }
         return [
+            proxy,
             this._pageInfo.area.filter(() => this._pageInfo.area).map((element: any) => element),
             this._currAnno.map((element: any) => element),
             this.pdfContent
@@ -372,7 +374,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
             // else if (this._largeRetryCount < 10) this._curSuffix = "_l";
             if (field instanceof ImageField) path = this.choosePath(field.url);
             // }
-            return <img key={path} src={path} width="100%" />;
+            return <img key={path + (this._mediumRetryCount).toString()} style={{ position: "absolute", width: "100%" }} src={path} onError={this.onError} />;
         }
         return (null);
     }
-- 
cgit v1.2.3-70-g09d2


From 30fdae9e869e0f132c76b4fa99b784e75d6c8dae Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Wed, 22 May 2019 19:51:49 -0400
Subject: A bunch of fixes/changes

---
 src/client/documents/Documents.ts                  |  2 +
 src/client/util/DocumentManager.ts                 |  6 ++-
 src/client/views/InkingCanvas.scss                 | 42 ++++++++++++--------
 src/client/views/SearchBox.tsx                     | 10 +++--
 .../views/collections/CollectionPDFView.scss       | 39 ++++++++++--------
 src/client/views/collections/CollectionSubView.tsx |  4 ++
 .../views/collections/CollectionVideoView.tsx      | 46 +++++++++++++++++++++-
 .../collections/collectionFreeForm/MarqueeView.tsx |  5 ++-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  9 ++++-
 src/client/views/nodes/DocumentView.tsx            | 12 +++---
 src/client/views/nodes/ImageBox.tsx                |  6 ++-
 src/client/views/nodes/KeyValueBox.tsx             |  2 +-
 src/client/views/nodes/PDFBox.tsx                  | 16 +++++++-
 src/client/views/nodes/VideoBox.tsx                |  8 +++-
 14 files changed, 153 insertions(+), 54 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 323534b2b..ae190a989 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -77,7 +77,9 @@ export namespace DocUtils {
             linkDoc.proto!.linkTags = "Default";
 
             linkDoc.proto!.linkedTo = target;
+            linkDoc.proto!.linkedToPage = target.curPage;
             linkDoc.proto!.linkedFrom = source;
+            linkDoc.proto!.linkedFromPage = source.curPage;
 
             let linkedFrom = Cast(protoTarg.linkedFromDocs, listSpec(Doc));
             if (!linkedFrom) {
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index f113ff1d7..65c4b9e4b 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -115,11 +115,11 @@ export class DocumentManager {
     }
 
     @undoBatch
-    public jumpToDocument = async (docDelegate: Doc, forceDockFunc: boolean = false, dockFunc?: (doc: Doc) => void): Promise<void> => {
+    public jumpToDocument = async (docDelegate: Doc, forceDockFunc: boolean = false, dockFunc?: (doc: Doc) => void, linkPage?: number): Promise<void> => {
         let doc = Doc.GetProto(docDelegate);
-        const page = NumCast(doc.page, undefined);
         const contextDoc = await Cast(doc.annotationOn, Doc);
         if (contextDoc) {
+            const page = NumCast(doc.page, linkPage || 0);
             const curPage = NumCast(contextDoc.curPage, page);
             if (page !== curPage) contextDoc.curPage = page;
         }
@@ -127,11 +127,13 @@ export class DocumentManager {
         // using forceDockFunc as a flag for splitting linked to doc to the right...can change later if needed
         if (!forceDockFunc && (docView = DocumentManager.Instance.getDocumentView(doc))) {
             docView.props.Document.libraryBrush = true;
+            if (linkPage !== undefined) docView.props.Document.curPage = linkPage;
             docView.props.focus(docView.props.Document);
         } else {
             if (!contextDoc) {
                 const actualDoc = Doc.MakeAlias(docDelegate);
                 actualDoc.libraryBrush = true;
+                if (linkPage !== undefined) actualDoc.curPage = linkPage;
                 (dockFunc || CollectionDockingView.Instance.AddRightSplit)(actualDoc);
             } else {
                 let contextView: DocumentView | null;
diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss
index 8bcaf41dd..d95398f17 100644
--- a/src/client/views/InkingCanvas.scss
+++ b/src/client/views/InkingCanvas.scss
@@ -1,40 +1,50 @@
 @import "globalCssVariables";
 
 .inkingCanvas {
-    opacity:0.99;
+    opacity: 0.99;
+
     .jsx-parser {
-        position:absolute;
-        width:100%;
-        height:100%;
+        position: absolute;
+        width: 100%;
+        height: 100%;
+        z-index: -1; // allows annotations to appear on videos when screen is full-size & ... 
     }
 }
-.inkingCanvas-paths-ink, .inkingCanvas-paths-markers, .inkingCanvas-noSelect, .inkingCanvas-canSelect {
+
+.inkingCanvas-paths-ink,
+.inkingCanvas-paths-markers,
+.inkingCanvas-noSelect,
+.inkingCanvas-canSelect {
     position: absolute;
     top: 0;
-    left:0;
+    left: 0;
     width: 8192px;
     height: 8192px;
-    cursor:"crosshair";
+    cursor: "crosshair";
     pointer-events: auto;
-    
+
 }
-.inkingCanvas-canSelect, 
-.inkingCanvas-noSelect    {
-    top:-50000px;
-    left:-50000px;
+
+.inkingCanvas-canSelect,
+.inkingCanvas-noSelect {
+    top: -50000px;
+    left: -50000px;
     width: 100000px;
     height: 100000px;
 }
-.inkingCanvas-noSelect  {
+
+.inkingCanvas-noSelect {
     pointer-events: none;
     cursor: "arrow";
 }
-.inkingCanvas-paths-ink, .inkingCanvas-paths-markers {
+
+.inkingCanvas-paths-ink,
+.inkingCanvas-paths-markers {
     pointer-events: none;
     z-index: 10000; // overlays ink on top of everything 
     cursor: "arrow";
 }
+
 .inkingCanvas-paths-markers {
     mix-blend-mode: multiply;
-}
-
+}
\ No newline at end of file
diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx
index 911fc8d9c..fa9462acf 100644
--- a/src/client/views/SearchBox.tsx
+++ b/src/client/views/SearchBox.tsx
@@ -21,6 +21,7 @@ import { DocumentManager } from '../util/DocumentManager';
 import { SetupDrag } from '../util/DragManager';
 import { Docs } from '../documents/Documents';
 import { RouteStore } from '../../server/RouteStore';
+import { NumCast } from '../../new_fields/Types';
 
 library.add(faSearch);
 library.add(faObjectGroup);
@@ -143,18 +144,21 @@ export class SearchBox extends React.Component {
         });
         let x = 0;
         let y = 0;
+        let maxy = 300;
         for (const doc of docs) {
             doc.x = x;
             doc.y = y;
             doc.width = 200;
-            doc.height = 200;
+            doc.height = 200 * NumCast(doc.nativeHeight) / NumCast(doc.nativeWidth, 1);
+            maxy = Math.max(doc.height, maxy);
             x += 250;
             if (x > 1000) {
+                maxy = 300;
                 x = 0;
-                y += 250;
+                y += maxy + 25;
             }
         }
-        return Docs.FreeformDocument(docs, { width: 400, height: 400, panX: 175, panY: 175, title: `Search Docs: "${this.searchString}"` });
+        return Docs.FreeformDocument(docs, { width: 400, height: 400, panX: 175, panY: 175, backgroundColor: "grey", title: `Search Docs: "${this.searchString}"` });
     }
 
     // Useful queries:
diff --git a/src/client/views/collections/CollectionPDFView.scss b/src/client/views/collections/CollectionPDFView.scss
index f6fb79582..50201bae8 100644
--- a/src/client/views/collections/CollectionPDFView.scss
+++ b/src/client/views/collections/CollectionPDFView.scss
@@ -1,49 +1,56 @@
 .collectionPdfView-buttonTray {
-    top : 15px;
-    left : 20px;
-    position: relative; 
+    top: 15px;
+    left: 20px;
+    position: relative;
     transform-origin: left top;
     position: absolute;
 }
+
 .collectionPdfView-thumb {
-    width:25px;
-    height:25px;
+    width: 25px;
+    height: 25px;
     transform-origin: left top;
     position: absolute;
     background: darkgray;
 }
+
 .collectionPdfView-slider {
-    width:25px;
-    height:25px;
+    width: 25px;
+    height: 25px;
     transform-origin: left top;
     position: absolute;
     background: lightgray;
 }
-.collectionPdfView-cont{
+
+.collectionPdfView-cont {
     width: 100%;
     height: 100%;
-    position: absolute; 
+    position: absolute;
     top: 0;
-    left:0;
+    left: 0;
+    z-index: -1;
 }
+
 .collectionPdfView-cont-dragging {
     span {
         user-select: none;
     }
 }
+
 .collectionPdfView-backward {
-    color : white;
+    color: white;
     font-size: 24px;
-    top :0px;
-    left : 0px;
+    top: 0px;
+    left: 0px;
     position: absolute;
     background-color: rgba(50, 50, 50, 0.2);
 }
+
 .collectionPdfView-forward {
-    color : white;
+    color: white;
     font-size: 24px;
-    top :0px;
-    left : 45px;
+    top: 0px;
+    left: 45px;
     position: absolute;
     background-color: rgba(50, 50, 50, 0.2);
 }
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 7800b35df..4a21e4465 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -153,6 +153,10 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
         @undoBatch
         @action
         protected onDrop(e: React.DragEvent, options: DocumentOptions): void {
+            if (e.ctrlKey) {
+                e.stopPropagation(); // bcz: this is a hack to stop propagation when dropping an image on a text document with shift+ctrl
+                return;
+            }
             let html = e.dataTransfer.getData("text/html");
             let text = e.dataTransfer.getData("text/plain");
 
diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx
index 27f23a1a8..7853544d5 100644
--- a/src/client/views/collections/CollectionVideoView.tsx
+++ b/src/client/views/collections/CollectionVideoView.tsx
@@ -1,4 +1,5 @@
 import { action, observable, trace } from "mobx";
+import * as htmlToImage from "html-to-image";
 import { observer } from "mobx-react";
 import { ContextMenu } from "../ContextMenu";
 import { CollectionViewType, CollectionBaseView, CollectionRenderProps } from "./CollectionBaseView";
@@ -6,10 +7,14 @@ import React = require("react");
 import "./CollectionVideoView.scss";
 import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
 import { FieldView, FieldViewProps } from "../nodes/FieldView";
-import { emptyFunction } from "../../../Utils";
+import { emptyFunction, Utils } from "../../../Utils";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { VideoBox } from "../nodes/VideoBox";
-import { NumCast } from "../../../new_fields/Types";
+import { NumCast, Cast, StrCast } from "../../../new_fields/Types";
+import { VideoField } from "../../../new_fields/URLField";
+import { SearchBox } from "../SearchBox";
+import { DocServer } from "../../DocServer";
+import { Docs, DocUtils } from "../../documents/Documents";
 
 
 @observer
@@ -67,6 +72,43 @@ 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
         }
+
+        let field = Cast(this.props.Document[this.props.fieldKey], VideoField);
+        if (field) {
+            let url = field.url.href;
+            ContextMenu.Instance.addItem({
+                description: "Copy path", event: () => { Utils.CopyText(url); }, icon: "expand-arrows-alt"
+            });
+        }
+        let width = NumCast(this.props.Document.width);
+        let height = NumCast(this.props.Document.height);
+        ContextMenu.Instance.addItem({
+            description: "Take Snapshot", event: async () => {
+                var canvas = document.createElement('canvas');
+                canvas.width = 640;
+                canvas.height = 640 * NumCast(this.props.Document.nativeHeight) / NumCast(this.props.Document.nativeWidth);
+                var ctx = canvas.getContext('2d');//draw image to canvas. scale to target dimensions
+                ctx && ctx.drawImage(this._videoBox!.player!, 0, 0, canvas.width, canvas.height);
+
+                //convert to desired file format
+                var dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png'
+                // if you want to preview the captured image,
+
+                let filename = encodeURIComponent("snapshot" + this.props.Document.title + "_" + this.props.Document.curPage).replace(/\./g, "");
+                SearchBox.convertDataUri(dataUrl, filename).then((returnedFilename) => {
+                    if (returnedFilename) {
+                        let url = DocServer.prepend(returnedFilename);
+                        let imageSummary = Docs.ImageDocument(url, {
+                            x: NumCast(this.props.Document.x) + width, y: NumCast(this.props.Document.y),
+                            width: 150, height: height / width * 150, title: "--snapshot" + NumCast(this.props.Document.curPage) + " image-"
+                        });
+                        this.props.addDocument && this.props.addDocument(imageSummary, false);
+                        DocUtils.MakeLink(imageSummary, this.props.Document);
+                    }
+                });
+            },
+            icon: "expand-arrows-alt"
+        });
     }
 
     setVideoBox = (videoBox: VideoBox) => { this._videoBox = videoBox; };
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index d72046800..973ebfbdd 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -296,7 +296,10 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
                     SearchBox.convertDataUri(dataUrl, "icon" + summary[Id] + "_image").then((returnedFilename) => {
                         if (returnedFilename) {
                             let url = DocServer.prepend(returnedFilename);
-                            let imageSummary = Docs.ImageDocument(url, { x: bounds.left, y: bounds.top + 100 / zoomBasis, width: 150, title: "-summary image-" });
+                            let imageSummary = Docs.ImageDocument(url, {
+                                x: bounds.left, y: bounds.top + 100 / zoomBasis,
+                                width: 150, height: bounds.height / bounds.width * 150, title: "-summary image-"
+                            });
                             summary.imageSummary = imageSummary;
                             this.props.addDocument(imageSummary, false);
                         }
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index aaaa6a9c5..66d91f9c2 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -195,6 +195,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
             this.props.Document.libraryBrush = false;
         }
         let altKey = e.altKey;
+        let ctrlKey = e.ctrlKey;
         if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
             Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
             let isExpander = (e.target as any).id === "isExpander";
@@ -242,9 +243,13 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                     let linkedFwdDocs = [
                         linkedToDocs.length ? linkedToDocs[0].linkedTo as Doc : linkedFromDocs.length ? linkedFromDocs[0].linkedFrom as Doc : expandedDocs[0],
                         linkedFromDocs.length ? linkedFromDocs[0].linkedFrom as Doc : linkedToDocs.length ? linkedToDocs[0].linkedTo as Doc : expandedDocs[0]];
-                    if (linkedFwdDocs) {
+
+                    let linkedFwdPage = [
+                        linkedToDocs.length ? NumCast(linkedToDocs[0].linkedToPage, undefined) : linkedFromDocs.length ? NumCast(linkedFromDocs[0].linkedFromPage, undefined) : undefined,
+                        linkedFromDocs.length ? NumCast(linkedFromDocs[0].linkedFromPage, undefined) : linkedToDocs.length ? NumCast(linkedToDocs[0].linkedToPage, undefined) : undefined];
+                    if (!linkedFwdDocs.some(l => l instanceof Promise)) {
                         let maxLocation = StrCast(linkedFwdDocs[altKey ? 1 : 0].maximizeLocation, "inTab");
-                        DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], altKey, document => this.props.addDocTab(document, maxLocation));
+                        DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, document => this.props.addDocTab(document, maxLocation), linkedFwdPage[altKey ? 1 : 0]);
                     }
                 }
             }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 87c88f57c..01c4d82fb 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -234,12 +234,14 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     makeButton = (e: React.MouseEvent): void => {
         let doc = this.props.Document.proto ? this.props.Document.proto : this.props.Document;
         doc.isButton = !BoolCast(doc.isButton, false);
-        if (doc.isButton && !doc.nativeWidth) {
-            doc.nativeWidth = this.props.Document[WidthSym]();
-            doc.nativeHeight = this.props.Document[HeightSym]();
-        } else {
+        if (StrCast(doc.layout).indexOf("Formatted") !== -1) { // only need to freeze the dimensions of text boxes since they don't have a native width and height naturally
+            if (doc.isButton && !doc.nativeWidth) {
+                doc.nativeWidth = this.props.Document[WidthSym]();
+                doc.nativeHeight = this.props.Document[HeightSym]();
+            } else {
 
-            doc.nativeWidth = doc.nativeHeight = undefined;
+                doc.nativeWidth = doc.nativeHeight = undefined;
+            }
         }
     }
     fullScreenClicked = (e: React.MouseEvent): void => {
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 71bda6fea..cc0dc8220 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -47,7 +47,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
     onLoad = (target: any) => {
         var h = this._imgRef.current!.naturalHeight;
         var w = this._imgRef.current!.naturalWidth;
-        if (this._photoIndex === 0 && (this.props as any).id !== "isExpander" && (!this.Document.nativeHeight || !this.Document.nativeWidth)) {
+        if (this._photoIndex === 0 && (this.props as any).id !== "isExpander" && (!this.Document.nativeWidth || !this.Document.nativeHeight || Math.abs(this.Document.nativeWidth / this.Document.nativeHeight - w / h) > 0.05)) {
             Doc.SetOnPrototype(this.Document, "nativeHeight", FieldValue(this.Document.nativeWidth, 0) * h / w);
             this.Document.height = FieldValue(this.Document.width, 0) * h / w;
         }
@@ -165,8 +165,10 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
     }
 
     choosePath(url: URL) {
-        if (url.protocol === "data" || url.href.indexOf(window.location.origin) === -1)
+        const lower = url.href.toLowerCase();
+        if (url.protocol === "data" || url.href.indexOf(window.location.origin) === -1 || !(lower.endsWith(".png") || lower.endsWith(".jpg") || lower.endsWith(".jpeg"))) {
             return url.href;
+        }
         let ext = path.extname(url.href);
         return url.href.replace(ext, this._curSuffix + ext);
     }
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 8cb576786..849f17aa4 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -78,7 +78,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
 
         let rows: JSX.Element[] = [];
         let i = 0;
-        for (let key in ids) {
+        for (let key of Object.keys(ids).sort()) {
             rows.push(<KeyValuePair doc={realDoc} keyWidth={100 - this.splitPercentage} rowStyle={"keyValueBox-" + (i++ % 2 ? "oddRow" : "evenRow")} key={key} keyName={key} />);
         }
         return rows;
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 5b8b15ed8..733bc920f 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -23,6 +23,7 @@ import { pageSchema } from "./ImageBox";
 import "./PDFBox.scss";
 var path = require('path');
 import React = require("react");
+import { ContextMenu } from "../ContextMenu";
 
 /** ALSO LOOK AT: Annotation.tsx, Sticky.tsx
  * This method renders PDF and puts all kinds of functionalities such as annotation, highlighting, 
@@ -357,7 +358,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     @computed
     get imageProxyRenderer() {
         let thumbField = this.props.Document.thumbnail;
-        if (thumbField && this._renderAsSvg) {
+        if (thumbField && this._renderAsSvg && NumCast(this.props.Document.thumbnailPage, 0) === this.Document.curPage) {
 
             // let transform = this.props.ScreenToLocalTransform().inverse();
             let pw = typeof this.props.PanelWidth === "function" ? this.props.PanelWidth() : typeof this.props.PanelWidth === "number" ? (this.props.PanelWidth as any) as number : 50;
@@ -380,10 +381,21 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     }
     @action onKeyDown = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = true);
     @action onKeyUp = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = false);
+    onContextMenu = (e: React.MouseEvent): void => {
+        let field = Cast(this.Document[this.props.fieldKey], PdfField);
+        if (field) {
+            let url = field.url.href;
+            ContextMenu.Instance.addItem({
+                description: "Copy path", event: () => {
+                    Utils.CopyText(url);
+                }, icon: "expand-arrows-alt"
+            });
+        }
+    }
     render() {
         let classname = "pdfBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : "");
         return (
-            <div className={classname} tabIndex={0} ref={this._mainDiv} onPointerDown={this.onPointerDown} onKeyDown={this.onKeyDown} onKeyUp={this.onKeyUp} >
+            <div className={classname} tabIndex={0} ref={this._mainDiv} onPointerDown={this.onPointerDown} onKeyDown={this.onKeyDown} onKeyUp={this.onKeyUp} onContextMenu={this.onContextMenu} >
                 {this.pdfRenderer}
             </div >
         );
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 6ae55d151..ab57b4b04 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -88,10 +88,14 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
         if (vref) {
             vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen);
             if (this._reactionDisposer) this._reactionDisposer();
-            this._reactionDisposer = reaction(() => this.props.Document.curPage, () =>
-                vref.currentTime = NumCast(this.props.Document.curPage, 0), { fireImmediately: true });
+            this._reactionDisposer = reaction(() => this.props.Document.curPage, () => {
+                if (!this.Playing) {
+                    vref.currentTime = NumCast(this.props.Document.curPage, 0);
+                }
+            }, { fireImmediately: true });
         }
     }
+
     videoContent(path: string) {
         let style = "videoBox-cont" + (this._fullScreen ? "-fullScreen" : "");
         return <video className={`${style}`} ref={this.setVideoRef} onPointerDown={this.onPointerDown}>
-- 
cgit v1.2.3-70-g09d2


From 01d172a91d9a140129d2dd938c3289d7a0d25f16 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 24 May 2019 14:10:32 -0400
Subject: cleaned up nativewidth/height for Image and Video and some PDF stuff.

---
 package.json                                       |  1 +
 src/client/documents/Documents.ts                  | 12 +++-
 .../CollectionFreeFormLinkView.tsx                 |  4 +-
 .../CollectionFreeFormLinksView.tsx                |  7 ++-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  5 +-
 src/client/views/nodes/ImageBox.tsx                | 15 +----
 src/client/views/nodes/PDFBox.scss                 |  4 ++
 src/client/views/nodes/PDFBox.tsx                  |  2 +-
 src/client/views/nodes/VideoBox.tsx                | 68 +++++++---------------
 9 files changed, 53 insertions(+), 65 deletions(-)

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

diff --git a/package.json b/package.json
index aa4abb0a5..d5abc808e 100644
--- a/package.json
+++ b/package.json
@@ -167,6 +167,7 @@
         "react-split-pane": "^0.1.85",
         "react-table": "^6.9.2",
         "request": "^2.88.0",
+        "request-image-size": "^2.1.0",
         "request-promise": "^4.2.4",
         "serializr": "^1.5.1",
         "sharp": "^0.22.1",
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index ae190a989..1f4b76384 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -34,6 +34,7 @@ import { StrokeData, InkField } from "../../new_fields/InkField";
 import { dropActionType } from "../util/DragManager";
 import { DateField } from "../../new_fields/DateField";
 import { UndoManager } from "../util/UndoManager";
+var requestImageSize = require('request-image-size');
 
 export interface DocumentOptions {
     x?: number;
@@ -216,7 +217,16 @@ export namespace Docs {
     }
 
     export function ImageDocument(url: string, options: DocumentOptions = {}) {
-        return CreateInstance(imageProto, new ImageField(new URL(url)), options);
+        let inst = CreateInstance(imageProto, new ImageField(new URL(url)), options);
+        requestImageSize(url)
+            .then((size: any) => {
+                if (!inst.proto!.nativeWidth) {
+                    inst.proto!.nativeWidth = size.width;
+                }
+                inst.proto!.nativeHeight = Number(inst.proto!.nativeWidth!) * size.height / size.width;
+            })
+            .catch((err: any) => console.log(err));
+        return inst;
         // let doc = SetInstanceOptions(GetImagePrototype(), { ...options, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] },
         //     [new URL(url), ImageField]);
         // doc.SetText(KeyStore.Caption, "my caption...");
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index d6097b9a3..61de83f57 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -46,11 +46,11 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         let y2 = NumCast(b.y) + (BoolCast(b.isMinimized, false) ? 5 : NumCast(b.height) / NumCast(b.zoomBasis, 1) / 2);
         return (
             <>
-                <line key={Utils.GenerateGuid()} className="collectionfreeformlinkview-linkLine"
+                <line key={"linkLine"} className="collectionfreeformlinkview-linkLine"
                     style={{ strokeWidth: `${35 * l.length / 2}` }}
                     x1={`${x1}`} y1={`${y1}`}
                     x2={`${x2}`} y2={`${y2}`} />
-                <circle key={Utils.GenerateGuid()} className="collectionfreeformlinkview-linkCircle"
+                <circle key={"linkCircle"} className="collectionfreeformlinkview-linkCircle"
                     cx={(x1 + x2) / 2} cy={(y1 + y2) / 2} r={8} onPointerDown={this.onPointerDown} />
             </>
         );
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index c5f7ad0d1..85556fb90 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -113,8 +113,11 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP
             );
             return drawnPairs;
         }, [] as { a: Doc, b: Doc, l: Doc[] }[]);
-        return connections.map(c => <CollectionFreeFormLinkView key={Utils.GenerateGuid()} A={c.a} B={c.b} LinkDocs={c.l}
-            removeDocument={this.props.removeDocument} addDocument={this.props.addDocument} />);
+        return connections.map(c => {
+            let x = c.l.reduce((p, l) => p + l[Id], "");
+            return <CollectionFreeFormLinkView key={x} A={c.a} B={c.b} LinkDocs={c.l}
+                removeDocument={this.props.removeDocument} addDocument={this.props.addDocument} />;
+        });
     }
 
     render() {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 8be0766eb..d1c4fb72d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -323,7 +323,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY));
     }
 
-    private childViews = () => [...this.views, <CollectionFreeFormBackgroundView key="backgroundView" {...this.props} {...this.getDocumentViewProps(this.props.Document)} />];
+    private childViews = () => [
+        <CollectionFreeFormBackgroundView key="backgroundView" {...this.props} {...this.getDocumentViewProps(this.props.Document)} />,
+        ...this.views
+    ];
     render() {
         const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`;
         const easing = () => this.props.Document.panTransformType === "Ease";
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index cc0dc8220..128f3c6f8 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -12,7 +12,7 @@ import React = require("react");
 import { createSchema, makeInterface, listSpec } from '../../../new_fields/Schema';
 import { DocComponent } from '../DocComponent';
 import { positionSchema } from './DocumentView';
-import { FieldValue, Cast, StrCast } from '../../../new_fields/Types';
+import { FieldValue, Cast, StrCast, PromiseValue } from '../../../new_fields/Types';
 import { ImageField } from '../../../new_fields/URLField';
 import { List } from '../../../new_fields/List';
 import { InkingControl } from '../InkingControl';
@@ -21,6 +21,7 @@ import { faImage } from '@fortawesome/free-solid-svg-icons';
 import { library } from '@fortawesome/fontawesome-svg-core';
 var path = require('path');
 
+
 library.add(faImage);
 
 
@@ -43,15 +44,6 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
     @observable private _isOpen: boolean = false;
     private dropDisposer?: DragManager.DragDropDisposer;
 
-    @action
-    onLoad = (target: any) => {
-        var h = this._imgRef.current!.naturalHeight;
-        var w = this._imgRef.current!.naturalWidth;
-        if (this._photoIndex === 0 && (this.props as any).id !== "isExpander" && (!this.Document.nativeWidth || !this.Document.nativeHeight || Math.abs(this.Document.nativeWidth / this.Document.nativeHeight - w / h) > 0.05)) {
-            Doc.SetOnPrototype(this.Document, "nativeHeight", FieldValue(this.Document.nativeWidth, 0) * h / w);
-            this.Document.height = FieldValue(this.Document.width, 0) * h / w;
-        }
-    }
 
 
     protected createDropTarget = (ele: HTMLDivElement) => {
@@ -217,8 +209,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
                     // style={{ objectFit: (this._photoIndex === 0 ? undefined : "contain") }}
                     width={nativeWidth}
                     ref={this._imgRef}
-                    onError={this.onError}
-                    onLoad={this.onLoad} />
+                    onError={this.onError} />
                 {paths.length > 1 ? this.dots(paths) : (null)}
                 {/* {this.lightbox(paths)} */}
             </div>);
diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index 3760e378a..449408a61 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -17,6 +17,10 @@
     z-index: 25;
     pointer-events: all;
 }
+.pdfBox-thumbnail {
+    position: absolute;
+    width: 100%;
+}
 .pdfButton {
     pointer-events: all;
     width: 100px;
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 733bc920f..aa29a7170 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -375,7 +375,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
             // else if (this._largeRetryCount < 10) this._curSuffix = "_l";
             if (field instanceof ImageField) path = this.choosePath(field.url);
             // }
-            return <img key={path + (this._mediumRetryCount).toString()} style={{ position: "absolute", width: "100%" }} src={path} onError={this.onError} />;
+            return <img className="pdfBox-thumbnail" key={path + (this._mediumRetryCount).toString()} src={path} onError={this.onError} />;
         }
         return (null);
     }
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index ab57b4b04..35ecf12f6 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -10,10 +10,10 @@ import { makeInterface } from "../../../new_fields/Schema";
 import { pageSchema } from "./ImageBox";
 import { Cast, FieldValue, NumCast } from "../../../new_fields/Types";
 import { VideoField } from "../../../new_fields/URLField";
-import Measure from "react-measure";
 import "./VideoBox.scss";
 import { RouteStore } from "../../../server/RouteStore";
 import { DocServer } from "../../DocServer";
+import { actionFieldDecorator } from "mobx/lib/internal";
 
 type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>;
 const VideoDocument = makeInterface(positionSchema, pageSchema);
@@ -22,30 +22,23 @@ const VideoDocument = makeInterface(positionSchema, pageSchema);
 export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoDocument) {
     private _reactionDisposer?: IReactionDisposer;
     private _videoRef: HTMLVideoElement | null = null;
-    private _loaded: boolean = false;
     @observable _playTimer?: NodeJS.Timeout = undefined;
     @observable _fullScreen = false;
     @observable public Playing: boolean = false;
     public static LayoutString() { return FieldView.LayoutString(VideoBox); }
 
-    public get player(): HTMLVideoElement | undefined {
-        if (this._videoRef) {
-            return this._videoRef;
-        }
+    public get player(): HTMLVideoElement | null {
+        return this._videoRef;
     }
-    @action
-    setScaling = (r: any) => {
-        if (this._loaded) {
-            // bcz: the nativeHeight should really be set when the document is imported.
-            var nativeWidth = FieldValue(this.Document.nativeWidth, 0);
-            var nativeHeight = FieldValue(this.Document.nativeHeight, 0);
-            var newNativeHeight = nativeWidth * r.offset.height / r.offset.width;
-            if (!nativeHeight && newNativeHeight !== nativeHeight && !isNaN(newNativeHeight)) {
-                this.Document.height = newNativeHeight / nativeWidth * FieldValue(this.Document.width, 0);
-                this.Document.nativeHeight = newNativeHeight;
-            }
-        } else {
-            this._loaded = true;
+
+    videoLoad = () => {
+        let aspect = this.player!.videoWidth / this.player!.videoHeight;
+        var nativeWidth = FieldValue(this.Document.nativeWidth, 0);
+        var nativeHeight = FieldValue(this.Document.nativeHeight, 0);
+        if (!nativeWidth || !nativeHeight) {
+            if (!this.Document.nativeWidth) this.Document.nativeWidth = this.player!.videoWidth;
+            this.Document.nativeHeight = this.Document.nativeWidth / aspect;
+            this.Document.height = FieldValue(this.Document.width, 0) / aspect;
         }
     }
 
@@ -88,22 +81,12 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
         if (vref) {
             vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen);
             if (this._reactionDisposer) this._reactionDisposer();
-            this._reactionDisposer = reaction(() => this.props.Document.curPage, () => {
-                if (!this.Playing) {
-                    vref.currentTime = NumCast(this.props.Document.curPage, 0);
-                }
-            }, { fireImmediately: true });
+            this._reactionDisposer = reaction(() => this.props.Document.curPage, () =>
+                !this.Playing && (vref.currentTime = this.Document.curPage || 0)
+                , { fireImmediately: true });
         }
     }
 
-    videoContent(path: string) {
-        let style = "videoBox-cont" + (this._fullScreen ? "-fullScreen" : "");
-        return <video className={`${style}`} ref={this.setVideoRef} onPointerDown={this.onPointerDown}>
-            <source src={path} type="video/mp4" />
-            Not supported.
-        </video>;
-    }
-
     getMp4ForVideo(videoId: string = "JN5beCVArMs") {
         return new Promise(async (resolve, reject) => {
             const videoInfoRequestConfig = {
@@ -111,7 +94,6 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
                     connection: 'keep-alive',
                     "user-agent": 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/46.0',
                 },
-
             };
             try {
                 let responseSchema: any = {};
@@ -145,9 +127,6 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
 
     render() {
         let field = Cast(this.Document[this.props.fieldKey], VideoField);
-        if (!field) {
-            return <div>Loading</div>;
-        }
 
         // this.getMp4ForVideo().then((mp4) => {
         //     console.log(mp4);
@@ -155,15 +134,12 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
         //     console.log("")
         // });
         // //
-        let content = this.videoContent(field.url.href);
-        return NumCast(this.props.Document.nativeHeight) ?
-            content :
-            <Measure offset onResize={this.setScaling}>
-                {({ measureRef }) =>
-                    <div style={{ width: "100%", height: "auto" }} ref={measureRef}>
-                        {content}
-                    </div>
-                }
-            </Measure>;
+
+        let style = "videoBox-cont" + (this._fullScreen ? "-fullScreen" : "");
+        return !field ? <div>Loading</div> :
+            <video className={`${style}`} ref={this.setVideoRef} onCanPlay={this.videoLoad} onPointerDown={this.onPointerDown}>
+                <source src={field.url.href} type="video/mp4" />
+                Not supported.
+            </video>;
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 1087133d71ef2ac7df6976c61685167ed0fe71d9 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 5 Jun 2019 14:09:40 -0400
Subject: cleaned up selections somewhat so that PDFs don't flicker when
 manipulating annotations.

---
 src/client/util/SelectionManager.ts                | 24 +++++++++-------------
 src/client/views/DocumentDecorations.tsx           |  1 -
 .../views/collections/CollectionBaseView.tsx       |  2 +-
 src/client/views/collections/CollectionPDFView.tsx |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  1 -
 .../collections/collectionFreeForm/MarqueeView.tsx |  1 -
 src/client/views/nodes/PDFBox.tsx                  | 16 +++++++--------
 7 files changed, 20 insertions(+), 27 deletions(-)

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

diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 8c92c2023..5311841e1 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -21,6 +21,13 @@ export namespace SelectionManager {
                 doc.props.whenActiveChanged(true);
             }
         }
+        @action
+        DeSelectDoc(doc: DocumentView): void {
+            if (manager.SelectedDocuments.indexOf(doc) !== -1) {
+                manager.SelectedDocuments.splice(manager.SelectedDocuments.indexOf(doc), 1);
+                doc.props.whenActiveChanged(false);
+            }
+        }
 
         @action
         DeselectAll(): void {
@@ -28,16 +35,6 @@ export namespace SelectionManager {
             manager.SelectedDocuments = [];
             FormattedTextBox.InputBoxOverlay = undefined;
         }
-        @action
-        ReselectAll() {
-            let sdocs = manager.SelectedDocuments.map(d => d);
-            manager.SelectedDocuments = [];
-            return sdocs;
-        }
-        @action
-        ReselectAll2(sdocs: DocumentView[]) {
-            sdocs.map(s => SelectionManager.SelectDoc(s, true));
-        }
     }
 
     const manager = new Manager();
@@ -49,6 +46,9 @@ export namespace SelectionManager {
     export function IsSelected(doc: DocumentView): boolean {
         return manager.SelectedDocuments.indexOf(doc) !== -1;
     }
+    export function DeSelectDoc(doc: DocumentView): void {
+        manager.DeSelectDoc(doc);
+    }
 
     export function DeselectAll(except?: Doc): void {
         let found: DocumentView | undefined = undefined;
@@ -62,10 +62,6 @@ export namespace SelectionManager {
         if (found) manager.SelectDoc(found, false);
     }
 
-    export function ReselectAll() {
-        let sdocs = manager.ReselectAll();
-        setTimeout(() => manager.ReselectAll2(sdocs), 0);
-    }
     export function SelectedDocuments(): Array<DocumentView> {
         return manager.SelectedDocuments;
     }
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 37895516a..cdd537760 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -463,7 +463,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         e.stopPropagation();
         this._resizing = "";
         this.Interacting = false;
-        SelectionManager.ReselectAll();
         if (e.button === 0) {
             e.preventDefault();
             this._isPointerDown = false;
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index 9350dc974..cb92464e5 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -158,7 +158,7 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
 
     @action.bound
     moveDocument(doc: Doc, targetCollection: Doc, addDocument: (doc: Doc) => boolean): boolean {
-        if (this.props.Document === targetCollection) {
+        if (Doc.AreProtosEqual(this.props.Document, targetCollection)) {
             return true;
         }
         if (this.removeDocument(doc)) {
diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index 5e51437a4..25c1535b3 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -70,7 +70,7 @@ export class CollectionPDFView extends React.Component<FieldViewProps> {
         return (
             <>
                 <CollectionFreeFormView {...props} CollectionView={this} />
-                {this.props.isSelected() ? this.uIButtons : (null)}
+                {this.props.active() ? this.uIButtons : (null)}
             </>
         );
     }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 634b4dfa0..582f93c2e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -104,7 +104,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                     }
                     this.bringToFront(d);
                 });
-                SelectionManager.ReselectAll();
             }
             return true;
         }
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 9ec941eff..81ca4c29a 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -325,7 +325,6 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
             }
             else {
                 this.props.addDocument(newCollection, false);
-                SelectionManager.DeselectAll();
                 this.props.selectDocuments([newCollection]);
             }
             this.cleanupInteractions(false);
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index aa29a7170..855c744e6 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -68,20 +68,21 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
 
     @observable private _currAnno: any = [];
     @observable private _interactive: boolean = false;
-    @observable private _loaded: boolean = false;
 
     @computed private get curPage() { return NumCast(this.Document.curPage, 1); }
     @computed private get thumbnailPage() { return NumCast(this.props.Document.thumbnailPage, -1); }
 
     componentDidMount() {
-        let wasSelected = this.props.isSelected();
+        let wasSelected = this.props.active();
         this._reactionDisposer = reaction(
-            () => [this.props.isSelected(), this.curPage],
+            () => [this.props.active(), this.curPage],
             () => {
-                if (this.curPage > 0 && !this.props.isTopMost && this.curPage !== this.thumbnailPage && wasSelected && !this.props.isSelected()) {
-                    this.saveThumbnail();
-                }
-                wasSelected = this._interactive = this.props.isSelected();
+                setTimeout(action(() => {  // this forces the active() check to happen after all changes in a transaction have occurred.
+                    if (this.curPage > 0 && !this.props.isTopMost && this.curPage !== this.thumbnailPage && wasSelected && !this.props.active()) {
+                        this.saveThumbnail();
+                    }
+                    wasSelected = this._interactive = this.props.active();
+                }), 0);
             },
             { fireImmediately: true });
 
@@ -276,7 +277,6 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         if (this._perPageInfo.length === 0) { //Makes sure it only runs once
             this._perPageInfo = [...Array(page._transport.numPages)];
         }
-        this._loaded = true;
     }
 
     @action
-- 
cgit v1.2.3-70-g09d2

