From 70a6f10779729cff4a1b46d56dd5ff84f41ed14e Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 4 Nov 2019 13:08:47 -0500
Subject: cleaned up some exceptions, runtime warnings, fixed borderRounding,
 and adding to Library->Documents

---
 src/client/views/nodes/DocumentView.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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

diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 11066145b..f593a5363 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -668,7 +668,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 onPointerEnter={() => Doc.BrushDoc(this.props.Document)} onPointerLeave={() => Doc.UnBrushDoc(this.props.Document)}
             >
                 {this.Document.links && DocListCast(this.Document.links).filter((d) => !DocListCast(this.layoutDoc.hiddenLinks).some(hidden => Doc.AreProtosEqual(hidden, d))).filter(this.isNonTemporalLink).map((d, i) =>
-                    <div style={{ pointerEvents: "none", position: "absolute", transformOrigin: "top left", width: "100%", height: "100%", transform: `scale(${this.layoutDoc.fitWidth ? 1 : 1 / this.props.ContentScaling()})` }}>
+                    <div key={`${d[Id]}`} style={{ pointerEvents: "none", position: "absolute", transformOrigin: "top left", width: "100%", height: "100%", transform: `scale(${this.layoutDoc.fitWidth ? 1 : 1 / this.props.ContentScaling()})` }}>
                         <DocumentView {...this.props} backgroundColor={returnTransparent} Document={d} removeDocument={undoBatch((doc: Doc) => Doc.AddDocToList(this.layoutDoc, "hiddenLinks", doc))} layoutKey={this.linkEndpoint(d)} />
                     </div>)}
                 {!showTitle && !showCaption ?
-- 
cgit v1.2.3-70-g09d2


From 8160b5e1e79aedc7acc6f1dc418b428073ce2118 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 5 Nov 2019 12:25:07 -0500
Subject: minor cleanup

---
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  51 ++++----
 src/client/views/nodes/DocumentView.scss           | 139 ++++++++++-----------
 src/client/views/nodes/DocumentView.tsx            | 112 +++++++----------
 src/client/views/nodes/PDFBox.scss                 |   1 +
 src/client/views/nodes/PDFBox.tsx                  |  57 ++++-----
 src/client/views/pdf/PDFViewer.tsx                 |  23 ++--
 6 files changed, 171 insertions(+), 212 deletions(-)

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

diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 581e5b736..a035bdc3d 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -1,5 +1,5 @@
 import { random } from "animejs";
-import { computed, IReactionDisposer, observable, reaction } from "mobx";
+import { computed, IReactionDisposer, observable, reaction, trace } from "mobx";
 import { observer } from "mobx-react";
 import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc";
 import { listSpec } from "../../../new_fields/Schema";
@@ -84,30 +84,29 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     finalPanelHeight = () => this.dataProvider ? this.dataProvider.height : this.panelHeight();
 
     render() {
-        return (
-            <div className="collectionFreeFormDocumentView-container"
-                style={{
-                    boxShadow:
-                        this.layoutDoc.opacity === 0 ? undefined :  // if it's not visible, then no shadow
-                            this.layoutDoc.z ? `#9c9396  ${StrCast(this.layoutDoc.boxShadow, "10px 10px 0.9vw")}` :  // if it's a floating doc, give it a big shadow
-                                this.clusterColor ? (`${this.clusterColor} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(this.layoutDoc.isBackground ? 100 : 50) / this.props.ContentScaling()}px`)}`) :  // if it's just in a cluster, make the shadown roughly match the cluster border extent
-                                    this.layoutDoc.isBackground ? `1px 1px 1px ${this.clusterColor}` :  // if it's a background & has a cluster color, make the shadow spread really big
-                                        StrCast(this.layoutDoc.boxShadow, ""),
-                    borderRadius: this.borderRounding(),
-                    transform: this.transform,
-                    transition: this.Document.isAnimating !== undefined ? ".5s ease-in" : this.props.transition ? this.props.transition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.transition),
-                    width: this.width,
-                    height: this.height,
-                    zIndex: this.Document.zIndex || 0,
-                }} >
-                <DocumentView {...this.props}
-                    ContentScaling={this.contentScaling}
-                    ScreenToLocalTransform={this.getTransform}
-                    backgroundColor={this.clusterColorFunc}
-                    PanelWidth={this.finalPanelWidth}
-                    PanelHeight={this.finalPanelHeight}
-                />
-            </div>
-        );
+        trace();
+        return <div className="collectionFreeFormDocumentView-container"
+            style={{
+                boxShadow:
+                    this.layoutDoc.opacity === 0 ? undefined :  // if it's not visible, then no shadow
+                        this.layoutDoc.z ? `#9c9396  ${StrCast(this.layoutDoc.boxShadow, "10px 10px 0.9vw")}` :  // if it's a floating doc, give it a big shadow
+                            this.clusterColor ? (`${this.clusterColor} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(this.layoutDoc.isBackground ? 100 : 50) / this.props.ContentScaling()}px`)}`) :  // if it's just in a cluster, make the shadown roughly match the cluster border extent
+                                this.layoutDoc.isBackground ? `1px 1px 1px ${this.clusterColor}` :  // if it's a background & has a cluster color, make the shadow spread really big
+                                    StrCast(this.layoutDoc.boxShadow, ""),
+                borderRadius: this.borderRounding(),
+                transform: this.transform,
+                transition: this.Document.isAnimating !== undefined ? ".5s ease-in" : this.props.transition ? this.props.transition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.transition),
+                width: this.width,
+                height: this.height,
+                zIndex: this.Document.zIndex || 0,
+            }} >
+            <DocumentView {...this.props}
+                ContentScaling={this.contentScaling}
+                ScreenToLocalTransform={this.getTransform}
+                backgroundColor={this.clusterColorFunc}
+                PanelWidth={this.finalPanelWidth}
+                PanelHeight={this.finalPanelHeight}
+            />
+        </div>;
     }
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index a0bf74990..65df86d27 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -1,89 +1,82 @@
 @import "../globalCssVariables";
 
 .documentView-node, .documentView-node-topmost {
-  position: inherit;
-  top: 0;
-  left:0;
-  border-radius: inherit;
-  transition : outline .3s linear;
-  cursor: grab;
-                    
- // background: $light-color; //overflow: hidden;
-  transform-origin: left top;
+    position: inherit;
+    top: 0;
+    left:0;
+    border-radius: inherit;
+    transition : outline .3s linear;
+    cursor: grab;
+                        
+    // background: $light-color; //overflow: hidden;
+    transform-origin: left top;
 
-  &.minimized {
-    width: 30px;
-    height: 30px;
-  }
+    &.minimized {
+        width: 30px;
+        height: 30px;
+    }
 
-  .top {
-    height: 20px;
-    cursor: pointer;
-  }
+    .top {
+        height: 20px;
+        cursor: pointer;
+    }
 
-  .content {
-    padding: 20px 20px;
-    height: auto;
-    box-sizing: border-box;
-  }
+    .content {
+        padding: 20px 20px;
+        height: auto;
+        box-sizing: border-box;
+    }
 
-  .scroll-box {
-    overflow-y: scroll;
-    height: calc(100% - 20px);
-  }
+    .scroll-box {
+        overflow-y: scroll;
+        height: calc(100% - 20px);
+    }
 
-  .documentView-overlays {
-    border-radius: inherit;
-    position: absolute; 
-    display: inline-block; 
-    width: 100%; 
-    height: 100%; 
-    pointer-events: none;
-    .documentView-textOverlay {
-        border-radius: inherit;
-        width: 100%;
-        display: inline-block; 
+    .documentView-docuLinkWrapper {
+        pointer-events: none;
         position: absolute;
+        transform-origin: top left;
+        width: 100%;
+        height: 100%; 
     }
-  }
-}
+    .documentView-styleWrapper {
+        position: absolute; 
+        display: inline-block;
+        width:100%;
+        height:100%;
+        pointer-events: none;
 
-.documentView-styleWrapper {
-    position: absolute; 
-    display: inline-block;
-    width:100%;
-    height:100%;
-    pointer-events: none;
+        .documentView-styleContentWrapper {
+            width:100%;
+            display: inline-block;
+            position: absolute;
+        }
+        .documentView-titleWrapper {
+            overflow:hidden; 
+            color: white; 
+            transform-origin: top left; 
+            top: 0; 
+            height: 25;
+            background: rgba(0, 0, 0, .4);
+            padding: 4px; 
+            text-align: center; 
+            text-overflow: ellipsis; 
+            white-space: pre;
+        }
 
-    .documentView-styleContentWrapper {
-        width:100%;
-        display: inline-block;
-        position: absolute;
-    }
-    .documentView-titleWrapper {
-        overflow:hidden; 
-        color: white; 
-        transform-origin: top left; 
-        top: 0; 
-        height: 25;
-        background: rgba(0, 0, 0, .4);
-        padding: 4px; 
-        text-align: center; 
-        text-overflow: ellipsis; 
-        white-space: pre;
-    }
+        .documentView-searchHighlight {
+            position: absolute; 
+            background: yellow; 
+            bottom: -20px;
+            border-radius: 5px;
+            transform-origin: bottom left; 
+        }
 
-    .documentView-searchHighlight {
-        position: absolute; 
-        background: yellow; 
-        bottom: -20px;
-        border-radius: 5px;
-        transform-origin: bottom left; 
+        .documentView-captionWrapper {
+            position: absolute; 
+            bottom: 0; 
+            transform-origin: bottom left;
+        }
     }
 
-    .documentView-captionWrapper {
-        position: absolute; 
-        bottom: 0; 
-        transform-origin: bottom left;
-    }
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f593a5363..c091f1260 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,6 +1,6 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 import * as fa from '@fortawesome/free-solid-svg-icons';
-import { action, computed, runInAction } from "mobx";
+import { action, computed, runInAction, trace } from "mobx";
 import { observer } from "mobx-react";
 import * as rp from "request-promise";
 import { Doc, DocListCast, DocListCastAsync, Opt } from "../../../new_fields/Doc";
@@ -41,30 +41,10 @@ import { DocumentContentsView } from "./DocumentContentsView";
 import "./DocumentView.scss";
 import { FormattedTextBox } from './FormattedTextBox';
 import React = require("react");
-import { link } from 'fs';
-
-library.add(fa.faEdit);
-library.add(fa.faTrash);
-library.add(fa.faShare);
-library.add(fa.faDownload);
-library.add(fa.faExpandArrowsAlt);
-library.add(fa.faCompressArrowsAlt);
-library.add(fa.faLayerGroup);
-library.add(fa.faExternalLinkAlt);
-library.add(fa.faAlignCenter);
-library.add(fa.faCaretSquareRight);
-library.add(fa.faSquare);
-library.add(fa.faConciergeBell);
-library.add(fa.faWindowRestore);
-library.add(fa.faFolder);
-library.add(fa.faMapPin);
-library.add(fa.faLink);
-library.add(fa.faFingerprint);
-library.add(fa.faCrosshairs);
-library.add(fa.faDesktop);
-library.add(fa.faUnlock);
-library.add(fa.faLock);
-library.add(fa.faLaptopCode, fa.faMale, fa.faCopy, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone);
+
+library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight,
+    fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale,
+    fa.faCopy, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone);
 
 export interface DocumentViewProps {
     ContainingCollectionView: Opt<CollectionView>;
@@ -599,6 +579,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     render() {
         if (!this.props.Document) return (null);
+        trace();
         const animDims = this.Document.animateToDimensions ? Array.from(this.Document.animateToDimensions) : undefined;
         const ruleColor = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleColor_" + this.Document.heading]) : undefined;
         const ruleRounding = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleRounding_" + this.Document.heading]) : undefined;
@@ -631,10 +612,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             </div>);
         const titleView = (!showTitle ? (null) :
             <div className="documentView-titleWrapper" style={{
+                width: `${100 * this.props.ContentScaling()}%`, transform: `scale(${1 / this.props.ContentScaling()})`,
                 position: showTextTitle ? "relative" : "absolute",
                 pointerEvents: SelectionManager.GetIsDragging() ? "none" : "all",
-                width: `${100 * this.props.ContentScaling()}%`,
-                transform: `scale(${1 / this.props.ContentScaling()})`
             }}>
                 <EditableView
                     contents={this.Document[showTitle]}
@@ -649,48 +629,46 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const highlightColors = ["transparent", "maroon", "maroon", "yellow", "magenta", "cyan", "orange"];
         const highlightStyles = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid", "solid"];
         let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc.viewType !== CollectionViewType.Linear;
-        return (
-            <div className={`documentView-node${this.topMost ? "-topmost" : ""}`}
-                ref={this._mainCont}
-                style={{
-                    transition: this.Document.isAnimating !== undefined ? ".5s linear" : StrCast(this.Document.transition),
-                    pointerEvents: this.Document.isBackground && !this.isSelected() ? "none" : "all",
-                    color: StrCast(this.Document.color),
-                    outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px",
-                    border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined,
-                    background: this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc.viewType === CollectionViewType.Linear ? undefined : backgroundColor,
-                    width: animwidth,
-                    height: animheight,
-                    transform: `scale(${this.layoutDoc.fitWidth ? 1 : this.props.ContentScaling()})`,
-                    opacity: this.Document.opacity
-                }}
-                onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick}
-                onPointerEnter={() => Doc.BrushDoc(this.props.Document)} onPointerLeave={() => Doc.UnBrushDoc(this.props.Document)}
-            >
-                {this.Document.links && DocListCast(this.Document.links).filter((d) => !DocListCast(this.layoutDoc.hiddenLinks).some(hidden => Doc.AreProtosEqual(hidden, d))).filter(this.isNonTemporalLink).map((d, i) =>
-                    <div key={`${d[Id]}`} style={{ pointerEvents: "none", position: "absolute", transformOrigin: "top left", width: "100%", height: "100%", transform: `scale(${this.layoutDoc.fitWidth ? 1 : 1 / this.props.ContentScaling()})` }}>
-                        <DocumentView {...this.props} backgroundColor={returnTransparent} Document={d} removeDocument={undoBatch((doc: Doc) => Doc.AddDocToList(this.layoutDoc, "hiddenLinks", doc))} layoutKey={this.linkEndpoint(d)} />
-                    </div>)}
-                {!showTitle && !showCaption ?
-                    this.Document.searchFields ?
-                        (<div className="documentView-searchWrapper">
-                            {this.contents}
-                            {searchHighlight}
-                        </div>)
-                        :
-                        this.contents
-                    :
-                    <div className="documentView-styleWrapper" >
-                        <div className="documentView-styleContentWrapper" style={{ height: showTextTitle ? "calc(100% - 29px)" : "100%", top: showTextTitle ? "29px" : undefined }}>
-                            {this.contents}
-                        </div>
-                        {titleView}
-                        {captionView}
+        return <div className={`documentView-node${this.topMost ? "-topmost" : ""}`}
+            ref={this._mainCont}
+            style={{
+                transition: this.Document.isAnimating !== undefined ? ".5s linear" : StrCast(this.Document.transition),
+                pointerEvents: this.Document.isBackground && !this.isSelected() ? "none" : "all",
+                color: StrCast(this.Document.color),
+                outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px",
+                border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined,
+                background: this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc.viewType === CollectionViewType.Linear ? undefined : backgroundColor,
+                width: animwidth,
+                height: animheight,
+                transform: `scale(${this.layoutDoc.fitWidth ? 1 : this.props.ContentScaling()})`,
+                opacity: this.Document.opacity
+            }}
+            onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick}
+            onPointerEnter={() => Doc.BrushDoc(this.props.Document)} onPointerLeave={() => Doc.UnBrushDoc(this.props.Document)}
+        >
+            {this.Document.links && DocListCast(this.Document.links).filter((d) => !DocListCast(this.layoutDoc.hiddenLinks).some(hidden => Doc.AreProtosEqual(hidden, d))).filter(this.isNonTemporalLink).map((d, i) =>
+                <div className="documentView-docuLinkWrapper" key={`${d[Id]}`} style={{ transform: `scale(${this.layoutDoc.fitWidth ? 1 : 1 / this.props.ContentScaling()})` }}>
+                    <DocumentView {...this.props} Document={d} layoutKey={this.linkEndpoint(d)} backgroundColor={returnTransparent} removeDocument={undoBatch(doc => Doc.AddDocToList(this.layoutDoc, "hiddenLinks", doc))} />
+                </div>)}
+            {!showTitle && !showCaption ?
+                this.Document.searchFields ?
+                    (<div className="documentView-searchWrapper">
+                        {this.contents}
                         {searchHighlight}
+                    </div>)
+                    :
+                    this.contents
+                :
+                <div className="documentView-styleWrapper" >
+                    <div className="documentView-styleContentWrapper" style={{ height: showTextTitle ? "calc(100% - 29px)" : "100%", top: showTextTitle ? "29px" : undefined }}>
+                        {this.contents}
                     </div>
-                }
-            </div>
-        );
+                    {titleView}
+                    {captionView}
+                    {searchHighlight}
+                </div>
+            }
+        </div>
     }
 }
 
diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index 8bec4fbe3..963205206 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -7,6 +7,7 @@
     overflow: hidden;
     position:absolute;
     cursor:auto;
+    transform-origin: top left;
 }
 
 .pdfBox-title-outer {
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 396a5356a..3baa6eb09 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -1,5 +1,5 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, observable, runInAction, reaction, IReactionDisposer } from 'mobx';
+import { action, observable, runInAction, reaction, IReactionDisposer, trace } from 'mobx';
 import { observer } from "mobx-react";
 import * as Pdfjs from "pdfjs-dist";
 import "pdfjs-dist/web/pdf_viewer.css";
@@ -32,13 +32,14 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
     private _valueValue: string = "";
     private _scriptValue: string = "";
     private _searchString: string = "";
+    private _initialScale: number | undefined;  // the initial scale of the PDF when first rendered which determines whether the document will be live on startup or not.  Getting bigger after startup won't make it automatically be live.
     private _everActive = false; // has this box ever had its contents activated -- if so, stop drawing the overlay title
     private _pdfViewer: PDFViewer | undefined;
-    private _searchRef: React.RefObject<HTMLInputElement> = React.createRef();
-    private _keyRef: React.RefObject<HTMLInputElement> = React.createRef();
-    private _valueRef: React.RefObject<HTMLInputElement> = React.createRef();
-    private _scriptRef: React.RefObject<HTMLInputElement> = React.createRef();
-    private _selectReaction: IReactionDisposer | undefined;
+    private _searchRef = React.createRef<HTMLInputElement>();
+    private _keyRef = React.createRef<HTMLInputElement>();
+    private _valueRef = React.createRef<HTMLInputElement>();
+    private _scriptRef = React.createRef<HTMLInputElement>();
+    private _selectReactionDisposer: IReactionDisposer | undefined;
 
     @observable private _searching: boolean = false;
     @observable private _flyout: boolean = false;
@@ -46,21 +47,17 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
     @observable private _pageControls = false;
 
     componentWillUnmount() {
-        this._selectReaction && this._selectReaction();
+        this._selectReactionDisposer && this._selectReactionDisposer();
     }
     componentDidMount() {
         const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField);
         if (pdfUrl instanceof PdfField) {
             Pdfjs.getDocument(pdfUrl.url.pathname).promise.then(pdf => runInAction(() => this._pdf = pdf));
         }
-        this._selectReaction = reaction(() => this.props.isSelected(),
+        this._selectReactionDisposer = reaction(() => this.props.isSelected(),
             () => {
-                if (this.props.isSelected()) {
-                    document.removeEventListener("keydown", this.onKeyDown);
-                    document.addEventListener("keydown", this.onKeyDown);
-                } else {
-                    document.removeEventListener("keydown", this.onKeyDown);
-                }
+                document.removeEventListener("keydown", this.onKeyDown);
+                this.props.isSelected() && document.addEventListener("keydown", this.onKeyDown);
             }, { fireImmediately: true });
     }
 
@@ -75,8 +72,8 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
     public prevAnnotation() { this._pdfViewer && this._pdfViewer.prevAnnotation(); }
     public nextAnnotation() { this._pdfViewer && this._pdfViewer.nextAnnotation(); }
     public backPage() { this._pdfViewer!.gotoPage((this.Document.curPage || 1) - 1); }
-    public gotoPage = (p: number) => { this._pdfViewer!.gotoPage(p); };
     public forwardPage() { this._pdfViewer!.gotoPage((this.Document.curPage || 1) + 1); }
+    public gotoPage = (p: number) => { this._pdfViewer!.gotoPage(p); };
 
     @undoBatch
     onKeyDown = action((e: KeyboardEvent) => {
@@ -86,12 +83,8 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
             e.stopImmediatePropagation();
             e.preventDefault();
         }
-        if (e.key === "PageDown" || e.key === "ArrowDown" || e.key === "ArrowRight") {
-            this.forwardPage();
-        }
-        if (e.key === "PageUp" || e.key === "ArrowUp" || e.key === "ArrowLeft") {
-            this.backPage();
-        }
+        if (e.key === "PageDown" || e.key === "ArrowDown" || e.key === "ArrowRight") this.forwardPage();
+        if (e.key === "PageUp" || e.key === "ArrowUp" || e.key === "ArrowLeft") this.backPage();
     });
 
     @undoBatch
@@ -120,14 +113,12 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
     settingsPanel() {
         let pageBtns = <>
             <button className="pdfBox-overlayButton-iconCont" key="back" title="Page Back"
-                onPointerDown={(e) => e.stopPropagation()}
-                onClick={() => this.backPage()}
+                onPointerDown={e => e.stopPropagation()} onClick={this.backPage}
                 style={{ left: 50, top: 5, height: "30px", position: "absolute", pointerEvents: "all" }}>
                 <FontAwesomeIcon style={{ color: "white" }} icon={"arrow-left"} size="sm" />
             </button>
             <button className="pdfBox-overlayButton-iconCont" key="fwd" title="Page Forward"
-                onPointerDown={(e) => e.stopPropagation()}
-                onClick={() => this.forwardPage()}
+                onPointerDown={e => e.stopPropagation()} onClick={this.forwardPage}
                 style={{ left: 80, top: 5, height: "30px", position: "absolute", pointerEvents: "all" }}>
                 <FontAwesomeIcon style={{ color: "white" }} icon={"arrow-right"} size="sm" />
             </button>
@@ -137,15 +128,13 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
                 onPointerDown={e => e.stopPropagation()} style={{ display: this.active() ? "flex" : "none", position: "absolute", width: "100%", height: "100%", zIndex: 1, pointerEvents: "none" }}>
                 <div className="pdfBox-overlayCont" key="cont" onPointerDown={(e) => e.stopPropagation()} style={{ left: `${this._searching ? 0 : 100}%` }}>
                     <button className="pdfBox-overlayButton" title="Open Search Bar" />
-                    <input className="pdfBox-searchBar" placeholder="Search" ref={this._searchRef} onChange={this.searchStringChanged} onKeyDown={e => {
-                        e.keyCode === KeyCodes.ENTER && this.search(this._searchString, !e.shiftKey);
-                    }} />
+                    <input className="pdfBox-searchBar" placeholder="Search" ref={this._searchRef} onChange={this.searchStringChanged} onKeyDown={e => e.keyCode === KeyCodes.ENTER && this.search(this._searchString, !e.shiftKey)} />
                     <button title="Search" onClick={e => this.search(this._searchString, !e.shiftKey)}>
                         <FontAwesomeIcon icon="search" size="sm" color="white" /></button>
-                    <button className="pdfBox-prevIcon " title="Previous Annotation" onClick={e => this.prevAnnotation()} >
+                    <button className="pdfBox-prevIcon " title="Previous Annotation" onClick={this.prevAnnotation} >
                         <FontAwesomeIcon style={{ color: "white" }} icon={"arrow-up"} size="sm" />
                     </button>
-                    <button className="pdfBox-nextIcon" title="Next Annotation" onClick={e => this.nextAnnotation()} >
+                    <button className="pdfBox-nextIcon" title="Next Annotation" onClick={this.nextAnnotation} >
                         <FontAwesomeIcon style={{ color: "white" }} icon={"arrow-down"} size="sm" />
                     </button>
                 </div>
@@ -200,8 +189,9 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
 
         ContextMenu.Instance.addItem({ description: "Pdf Funcs...", subitems: funcs, icon: "asterisk" });
     }
-    _initialScale: number | undefined;  // the initial scale of the PDF when first rendered which determines whether the document will be live on startup or not.  Getting bigger after startup won't make it automatically be live....
+
     render() {
+        trace();
         const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField);
         let classname = "pdfBox-cont" + (this.active() ? "-interactive" : "");
         let noPdf = !(pdfUrl instanceof PdfField) || !this._pdf;
@@ -214,11 +204,10 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
                 </div>
             </div> :
             <div className={classname} style={{
-                transformOrigin: "top left",
                 width: this.props.Document.fitWidth ? `${100 / this.props.ContentScaling()}%` : undefined,
                 height: this.props.Document.fitWidth ? `${100 / this.props.ContentScaling()}%` : undefined,
                 transform: `scale(${this.props.Document.fitWidth ? this.props.ContentScaling() : 1})`
-            }} onContextMenu={this.specificContextMenu} onPointerDown={(e: React.PointerEvent) => {
+            }} onContextMenu={this.specificContextMenu} onPointerDown={e => {
                 let hit = document.elementFromPoint(e.clientX, e.clientY);
                 if (hit && hit.localName === "span" && this.props.isSelected()) {  // drag selecting text stops propagation
                     e.button === 0 && e.stopPropagation();
@@ -228,7 +217,7 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
                     setPdfViewer={this.setPdfViewer} ContainingCollectionView={this.props.ContainingCollectionView}
                     renderDepth={this.props.renderDepth} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth}
                     Document={this.props.Document} DataDoc={this.dataDoc} ContentScaling={this.props.ContentScaling}
-                    addDocTab={this.props.addDocTab} GoToPage={this.gotoPage} focus={this.props.focus}
+                    addDocTab={this.props.addDocTab} focus={this.props.focus}
                     pinToPres={this.props.pinToPres} addDocument={this.addDocument}
                     ScreenToLocalTransform={this.props.ScreenToLocalTransform} select={this.props.select}
                     isSelected={this.props.isSelected} whenActiveChanged={this.whenActiveChanged}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 51dc6e8d6..060ba8613 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -59,7 +59,6 @@ interface IViewerProps {
     isSelected: () => boolean;
     loaded: (nw: number, nh: number, np: number) => void;
     active: () => boolean;
-    GoToPage?: (n: number) => void;
     addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     addDocument?: (doc: Doc) => boolean;
@@ -220,7 +219,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
     }
 
     createPdfViewer() {
-        if (!this._mainCont.current) {
+        if (!this._mainCont.current) { // bcz: I don't think this is ever triggered or needed
             if (this._retries < 5) {
                 this._retries++;
                 setTimeout(() => this.createPdfViewer(), 1000);
@@ -235,9 +234,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
         }));
         document.addEventListener("pagerendered", action(() => this._showCover = this._showWaiting = false));
         var pdfLinkService = new PDFJSViewer.PDFLinkService();
-        let pdfFindController = new PDFJSViewer.PDFFindController({
-            linkService: pdfLinkService,
-        });
+        let pdfFindController = new PDFJSViewer.PDFFindController({ linkService: pdfLinkService });
         this._pdfViewer = new PDFJSViewer.PDFViewer({
             container: this._mainCont.current,
             viewer: this._viewer.current,
@@ -626,6 +623,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
     }
 
     @computed get annotationLayer() {
+        trace();
         return <div className="pdfViewer-annotationLayer" style={{ height: (this.Document.nativeHeight || 0) }} ref={this._annotationLayer}>
             {this.nonDocAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map((anno, index) =>
                 <Annotation {...this.props} focus={this.props.focus} extensionDoc={this.extensionDoc!} anno={anno} key={`${anno[Id]}-annotation`} />)}
@@ -672,13 +670,14 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
     marqueeing = () => this._marqueeing;
     visibleHeight = () => this.props.PanelHeight() / this.props.ContentScaling() * 72 / 96;
     render() {
-        return !this.extensionDoc ? (null) : (<div className={"pdfViewer-viewer" + (this._zoomed !== 1 ? "-zoomed" : "")}
-            onScroll={this.onScroll} onWheel={this.onZoomWheel} onPointerDown={this.onPointerDown} onClick={this.onClick} ref={this._mainCont}>
-            {this.pdfViewerDiv}
-            {this.annotationLayer}
-            {this.standinViews}
-            <PdfViewerMarquee isMarqueeing={this.marqueeing} width={this.marqueeWidth} height={this.marqueeHeight} x={this.marqueeX} y={this.marqueeY} />
-        </div >);
+        trace();
+        return !this.extensionDoc ? (null) :
+            <div className={"pdfViewer-viewer" + (this._zoomed !== 1 ? "-zoomed" : "")} onScroll={this.onScroll} onWheel={this.onZoomWheel} onPointerDown={this.onPointerDown} onClick={this.onClick} ref={this._mainCont}>
+                {this.pdfViewerDiv}
+                {this.annotationLayer}
+                {this.standinViews}
+                <PdfViewerMarquee isMarqueeing={this.marqueeing} width={this.marqueeWidth} height={this.marqueeHeight} x={this.marqueeX} y={this.marqueeY} />
+            </div >;
     }
 }
 
-- 
cgit v1.2.3-70-g09d2


From f83205e4ea3486ebeeaa52918650bf6521c36cb9 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 6 Nov 2019 12:35:51 -0500
Subject: schema view cleanups

---
 package.json                                       |   2 +-
 src/client/views/MainView.tsx                      |   2 +-
 .../CollectionSchemaMovableTableHOC.tsx            |   2 +-
 .../views/collections/CollectionSchemaView.scss    |   6 +-
 .../views/collections/CollectionSchemaView.tsx     | 243 +++++++--------------
 src/client/views/nodes/DocumentView.tsx            |   2 +-
 src/server/index.ts                                |  64 +++---
 7 files changed, 116 insertions(+), 205 deletions(-)

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

diff --git a/package.json b/package.json
index 8ee080933..fb978be14 100644
--- a/package.json
+++ b/package.json
@@ -115,7 +115,7 @@
         "@types/youtube": "0.0.38",
         "adm-zip": "^0.4.13",
         "archiver": "^3.0.3",
-        "array-batcher": "^1.1.3",
+        "array-batcher": "^1.2.3",
         "async": "^2.6.2",
         "babel-runtime": "^6.26.0",
         "bcrypt-nodejs": "0.0.3",
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 383300b22..773da05df 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -137,7 +137,7 @@ export class MainView extends React.Component {
 
     globalPointerDown = action((e: PointerEvent) => {
         this.isPointerDown = true;
-        AudioBox.AudioEnabled = true;
+        AudioBox.Enabled = true;
         const targets = document.elementsFromPoint(e.x, e.y);
         if (targets && targets.length && targets[0].className.toString().indexOf("contextMenu") === -1) {
             ContextMenu.Instance.closeMenu();
diff --git a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
index 39abc41ec..274c8b6d1 100644
--- a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
+++ b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
@@ -229,7 +229,7 @@ export class MovableRow extends React.Component<MovableRowProps> {
                 <div className="collectionSchema-row-wrapper" ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
                     <ReactTableDefaults.TrComponent>
                         <div className="row-dragger">
-                            <div className="row-option" onClick={() => this.props.removeDoc(this.props.rowInfo.original)}><FontAwesomeIcon icon="trash" size="sm" /></div>
+                            <div className="row-option" onClick={undoBatch(() => this.props.removeDoc(this.props.rowInfo.original))}><FontAwesomeIcon icon="trash" size="sm" /></div>
                             <div className="row-option" style={{ cursor: "grab" }} ref={reference} onPointerDown={onItemDown}><FontAwesomeIcon icon="grip-vertical" size="sm" /></div>
                         </div>
                         {children}
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
index 6a9392253..36c6c7b0e 100644
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ b/src/client/views/collections/CollectionSchemaView.scss
@@ -10,6 +10,7 @@
     top: 0;
     width: 100%;
     height: 100%;
+    margin-top: 0;
     transition: top 0.5s;
     display: flex;
     justify-content: space-between;
@@ -43,9 +44,8 @@
     height: auto !important;
 
     .collectionSchemaView-previewDoc {
-        height: 100%;
-        width: 100%;
         position: absolute;
+        display: inline;
     }
 
     .collectionSchemaView-input {
@@ -469,7 +469,7 @@ button.add-column {
     overflow: visible;
 }
 
-.sub {
+.reactTable-sub {
     padding: 10px 30px;
     background-color: rgb(252, 252, 252);
     width: calc(100% - 50px);
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 34f642f80..b840dc5f8 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -4,7 +4,7 @@ import { faCog, faPlus, faTable, faSortUp, faSortDown } from '@fortawesome/free-
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, observable, trace, untracked } from "mobx";
 import { observer } from "mobx-react";
-import ReactTable, { CellInfo, ComponentPropsGetterR, Column, RowInfo, ResizedChangeFunction, Resize } from "react-table";
+import ReactTable, { CellInfo, ComponentPropsGetterR, Column, RowInfo, ResizedChangeFunction, Resize, SortingRule } from "react-table";
 import "react-table/react-table.css";
 import { emptyFunction, returnOne, returnEmptyString } from "../../../Utils";
 import { Doc, DocListCast, Field, Opt } from "../../../new_fields/Doc";
@@ -32,7 +32,6 @@ import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
 import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
 import { DocumentType } from "../../documents/DocumentTypes";
 
-
 library.add(faCog, faPlus, faSortUp, faSortDown);
 library.add(faTable);
 // bcz: need to add drag and drop of rows and columns.  This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657
@@ -73,20 +72,14 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
         super.CreateDropTarget(ele);
     }
 
-    isFocused = (doc: Doc): boolean => {
-        if (!this.props.isSelected()) return false;
-        return doc === this._focusedTable;
-    }
+    isFocused = (doc: Doc): boolean => !this.props.isSelected() ? false : doc === this._focusedTable;
 
-    @action
-    setFocused = (doc: Doc): void => {
-        this._focusedTable = doc;
-    }
+    @action setFocused = (doc: Doc) => this._focusedTable = doc;
 
-    @action
-    setPreviewDoc = (doc: Doc): void => {
-        this.previewDoc = doc;
-    }
+    @action setPreviewDoc = (doc: Doc) => this.previewDoc = doc;
+
+    @undoBatch
+    @action setPreviewScript = (script: string) => this.previewScript = script;
 
     //toggles preview side-panel of schema
     @action
@@ -128,12 +121,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
         }
     }
 
-    onWheel = (e: React.WheelEvent): void => {
-        if (this.props.active()) {
-            e.stopPropagation();
-        }
-    }
-
     @computed
     get previewDocument(): Doc | undefined {
         let selected = this.previewDoc;
@@ -180,62 +167,51 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
         </div>;
     }
 
-    @undoBatch
-    @action
-    setPreviewScript = (script: string) => {
-        this.previewScript = script;
-    }
-
     @computed
     get schemaTable() {
-        return (
-            <SchemaTable
-                Document={this.props.Document}
-                PanelHeight={this.props.PanelHeight}
-                PanelWidth={this.props.PanelWidth}
-                childDocs={this.childDocs}
-                CollectionView={this.props.CollectionView}
-                ContainingCollectionView={this.props.ContainingCollectionView}
-                ContainingCollectionDoc={this.props.ContainingCollectionDoc}
-                fieldKey={this.props.fieldKey}
-                renderDepth={this.props.renderDepth}
-                moveDocument={this.props.moveDocument}
-                ScreenToLocalTransform={this.props.ScreenToLocalTransform}
-                active={this.props.active}
-                onDrop={this.onDrop}
-                addDocTab={this.props.addDocTab}
-                pinToPres={this.props.pinToPres}
-                isSelected={this.props.isSelected}
-                isFocused={this.isFocused}
-                setFocused={this.setFocused}
-                setPreviewDoc={this.setPreviewDoc}
-                deleteDocument={this.props.removeDocument}
-                dataDoc={this.props.DataDoc}
-            />
-        );
+        return <SchemaTable
+            Document={this.props.Document}
+            PanelHeight={this.props.PanelHeight}
+            PanelWidth={this.props.PanelWidth}
+            childDocs={this.childDocs}
+            CollectionView={this.props.CollectionView}
+            ContainingCollectionView={this.props.ContainingCollectionView}
+            ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+            fieldKey={this.props.fieldKey}
+            renderDepth={this.props.renderDepth}
+            moveDocument={this.props.moveDocument}
+            ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+            active={this.props.active}
+            onDrop={this.onDrop}
+            addDocTab={this.props.addDocTab}
+            pinToPres={this.props.pinToPres}
+            isSelected={this.props.isSelected}
+            isFocused={this.isFocused}
+            setFocused={this.setFocused}
+            setPreviewDoc={this.setPreviewDoc}
+            deleteDocument={this.props.removeDocument}
+            addDocument={this.props.addDocument}
+            dataDoc={this.props.DataDoc}
+        />;
     }
 
     @computed
     public get schemaToolbar() {
-        return (
-            <div className="collectionSchemaView-toolbar">
-                <div className="collectionSchemaView-toolbar-item">
-                    <div id="preview-schema-checkbox-div"><input type="checkbox" key={"Show Preview"} checked={this.previewWidth() !== 0} onChange={this.toggleExpander} />Show Preview</div>
-                </div>
+        return <div className="collectionSchemaView-toolbar">
+            <div className="collectionSchemaView-toolbar-item">
+                <div id="preview-schema-checkbox-div"><input type="checkbox" key={"Show Preview"} checked={this.previewWidth() !== 0} onChange={this.toggleExpander} />Show Preview</div>
             </div>
-        );
+        </div>;
     }
 
     render() {
-        return (
-            <div className="collectionSchemaView-container" style={{ height: "100%", marginTop: "0", }}>
-                <div className="collectionSchemaView-tableContainer" onPointerDown={this.onPointerDown} onWheel={this.onWheel} onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createTarget}>
-                    {this.schemaTable}
-                </div>
-                {this.dividerDragger}
-                {!this.previewWidth() ? (null) : this.previewPanel}
+        return <div className="collectionSchemaView-container">
+            <div className="collectionSchemaView-tableContainer" onPointerDown={this.onPointerDown} onWheel={e => this.props.active() && e.stopPropagation()} onDrop={e => this.onDrop(e, {})} ref={this.createTarget}>
+                {this.schemaTable}
             </div>
-        );
+            {this.dividerDragger}
+            {!this.previewWidth() ? (null) : this.previewPanel}
+        </div>;
     }
 }
 
@@ -251,6 +227,7 @@ export interface SchemaTableProps {
     fieldKey: string;
     renderDepth: number;
     deleteDocument: (document: Doc) => boolean;
+    addDocument: (document: Doc) => boolean;
     moveDocument: (document: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean;
     ScreenToLocalTransform: () => Transform;
     active: () => boolean;
@@ -307,11 +284,11 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
             return resized;
         }, [] as { id: string, value: number }[]);
     }
-    @computed get sorted(): { id: string, desc: boolean }[] {
+    @computed get sorted(): SortingRule[] {
         return this.columns.reduce((sorted, shf) => {
             shf.desc && sorted.push({ id: shf.heading, desc: shf.desc });
             return sorted;
-        }, [] as { id: string, desc: boolean }[]);
+        }, [] as SortingRule[]);
     }
 
     @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); }
@@ -433,26 +410,11 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
         return Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before);
     }
 
-    tableRemoveDoc = (document: Doc): boolean => {
-
-        let children = this.childDocs;
-        if (children.indexOf(document) !== -1) {
-            children.splice(children.indexOf(document), 1);
-            this.childDocs = children;
-            return true;
-        }
-        return false;
-    }
-
     private getTrProps: ComponentPropsGetterR = (state, rowInfo) => {
-        const that = this;
-        if (!rowInfo) {
-            return {};
-        }
-        return {
+        return !rowInfo ? {} : {
             ScreenToLocalTransform: this.props.ScreenToLocalTransform,
             addDoc: this.tableAddDoc,
-            removeDoc: this.tableRemoveDoc,
+            removeDoc: this.props.deleteDocument,
             rowInfo,
             rowFocused: !this._headerIsEditing && rowInfo.index === this._focusedCell.row && this.props.isFocused(this.props.Document),
             textWrapRow: this.toggleTextWrapRow,
@@ -477,10 +439,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
         };
     }
 
-    @action
-    onExpandCollection = (collection: Doc): void => {
-        this._openCollections.push(collection[Id]);
-    }
+    @action onExpandCollection = (collection: Doc) => this._openCollections.push(collection[Id]);
 
     @action
     onCloseCollection = (collection: Doc): void => {
@@ -488,15 +447,8 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
         if (index > -1) this._openCollections.splice(index, 1);
     }
 
-    @action
-    setCellIsEditing = (isEditing: boolean): void => {
-        this._cellIsEditing = isEditing;
-    }
-
-    @action
-    setHeaderIsEditing = (isEditing: boolean): void => {
-        this._headerIsEditing = isEditing;
-    }
+    @action setCellIsEditing = (isEditing: boolean) => this._cellIsEditing = isEditing;
+    @action setHeaderIsEditing = (isEditing: boolean) => this._headerIsEditing = isEditing;
 
     onPointerDown = (e: React.PointerEvent): void => {
         this.props.setFocused(this.props.Document);
@@ -505,67 +457,40 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
         }
     }
 
-    onWheel = (e: React.WheelEvent): void => {
-        if (this.props.active()) {
-            e.stopPropagation();
-        }
-    }
-
+    @action
     onKeyDown = (e: KeyboardEvent): void => {
         if (!this._cellIsEditing && !this._headerIsEditing && this.props.isFocused(this.props.Document)) {// && this.props.isSelected()) {
             let direction = e.key === "Tab" ? "tab" : e.which === 39 ? "right" : e.which === 37 ? "left" : e.which === 38 ? "up" : e.which === 40 ? "down" : "";
-            this.changeFocusedCellByDirection(direction);
+            this._focusedCell = this.changeFocusedCellByDirection(direction, this._focusedCell.row, this._focusedCell.col);
 
-            let children = this.childDocs;
-            const pdoc = FieldValue(children[this._focusedCell.row]);
+            const pdoc = FieldValue(this.childDocs[this._focusedCell.row]);
             pdoc && this.props.setPreviewDoc(pdoc);
         }
     }
 
-    @action
-    changeFocusedCellByDirection = (direction: string): void => {
-        let children = this.childDocs;
+    changeFocusedCellByDirection = (direction: string, curRow: number, curCol: number) => {
         switch (direction) {
-            case "tab":
-                if (this._focusedCell.col + 1 === this.columns.length && this._focusedCell.row + 1 === children.length) {
-                    this._focusedCell = { row: 0, col: 0 };
-                } else if (this._focusedCell.col + 1 === this.columns.length) {
-                    this._focusedCell = { row: this._focusedCell.row + 1, col: 0 };
-                } else {
-                    this._focusedCell = { row: this._focusedCell.row, col: this._focusedCell.col + 1 };
-                }
-                break;
-            case "right":
-                this._focusedCell = { row: this._focusedCell.row, col: this._focusedCell.col + 1 === this.columns.length ? this._focusedCell.col : this._focusedCell.col + 1 };
-                break;
-            case "left":
-                this._focusedCell = { row: this._focusedCell.row, col: this._focusedCell.col === 0 ? this._focusedCell.col : this._focusedCell.col - 1 };
-                break;
-            case "up":
-                this._focusedCell = { row: this._focusedCell.row === 0 ? this._focusedCell.row : this._focusedCell.row - 1, col: this._focusedCell.col };
-                break;
-            case "down":
-                this._focusedCell = { row: this._focusedCell.row + 1 === children.length ? this._focusedCell.row : this._focusedCell.row + 1, col: this._focusedCell.col };
-                break;
+            case "tab": return { row: (curRow + 1 === this.childDocs.length ? 0 : curRow + 1), col: curCol + 1 === this.columns.length ? 0 : curCol + 1 };
+            case "right": return { row: curRow, col: curCol + 1 === this.columns.length ? curCol : curCol + 1 };
+            case "left": return { row: curRow, col: curCol === 0 ? curCol : curCol - 1 };
+            case "up": return { row: curRow === 0 ? curRow : curRow - 1, col: curCol };
+            case "down": return { row: curRow + 1 === this.childDocs.length ? curRow : curRow + 1, col: curCol };
         }
+        return this._focusedCell;
     }
 
     @action
     changeFocusedCellByIndex = (row: number, col: number): void => {
-        this._focusedCell = { row: row, col: col };
+        if (this._focusedCell.row !== row || this._focusedCell.col !== col) {
+            this._focusedCell = { row: row, col: col };
+        }
         this.props.setFocused(this.props.Document);
     }
 
     @undoBatch
     createRow = () => {
-        let children = this.childDocs;
-
-        let newDoc = Docs.Create.TextDocument({ width: 100, height: 30 });
-        let proto = Doc.GetProto(newDoc);
-        proto.title = "";
-        children.push(newDoc);
-
-        this.childDocs = children;
+        let newDoc = Docs.Create.TextDocument({ title: "", width: 100, height: 30 });
+        this.props.addDocument(newDoc);
     }
 
     @undoBatch
@@ -677,9 +602,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     }
 
     @action
-    setColumns = (columns: SchemaHeaderField[]) => {
-        this.columns = columns;
-    }
+    setColumns = (columns: SchemaHeaderField[]) => this.columns = columns;
 
     @undoBatch
     reorderColumns = (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columnsValues: SchemaHeaderField[]) => {
@@ -762,7 +685,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
             SubComponent={hasCollectionChild ?
                 row => {
                     if (row.original.type === "collection") {
-                        return <div className="sub"><SchemaTable {...this.props} Document={row.original} childDocs={undefined} /></div>;
+                        return <div className="reactTable-sub"><SchemaTable {...this.props} Document={row.original} childDocs={undefined} /></div>;
                     }
                 }
                 : undefined}
@@ -881,13 +804,11 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     }
 
     render() {
-        return (
-            <div className="collectionSchemaView-table" onPointerDown={this.onPointerDown} onWheel={this.onWheel}
-                onDrop={(e: React.DragEvent) => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} >
-                {this.reactTable}
-                <div className="collectionSchemaView-addRow" onClick={() => this.createRow()}>+ new</div>
-            </div>
-        );
+        return <div className="collectionSchemaView-table" onPointerDown={this.onPointerDown} onWheel={e => this.props.active() && e.stopPropagation()}
+            onDrop={e => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} >
+            {this.reactTable}
+            <div className="collectionSchemaView-addRow" onClick={() => this.createRow()}>+ new</div>
+        </div>;
     }
 }
 
@@ -922,7 +843,6 @@ interface CollectionSchemaPreviewProps {
 @observer
 export class CollectionSchemaPreview extends React.Component<CollectionSchemaPreviewProps>{
     private dropDisposer?: DragManager.DragDropDisposer;
-    _mainCont?: HTMLDivElement;
     private get layoutDoc() { return this.props.Document && Doc.Layout(this.props.Document); }
     private get nativeWidth() { return NumCast(this.layoutDoc!.nativeWidth, this.props.PanelWidth()); }
     private get nativeHeight() { return NumCast(this.layoutDoc!.nativeHeight, this.props.PanelHeight()); }
@@ -933,10 +853,7 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
         }
         return wscale;
     }
-    protected createDropTarget = (ele: HTMLDivElement) => {
-    }
     private createTarget = (ele: HTMLDivElement) => {
-        this._mainCont = ele;
         this.dropDisposer && this.dropDisposer();
         if (ele) {
             this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } });
@@ -960,25 +877,12 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
     private PanelHeight = () => this.nativeHeight && (!this.props.Document || !this.props.Document.fitWidth) ? this.nativeHeight * this.contentScaling() : this.props.PanelHeight();
     private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, 0).scale(1 / this.contentScaling());
     get centeringOffset() { return this.nativeWidth && (!this.props.Document || !this.props.Document.fitWidth) ? (this.props.PanelWidth() - this.nativeWidth * this.contentScaling()) / 2 : 0; }
-    @action
-    onPreviewScriptChange = (e: React.ChangeEvent<HTMLInputElement>) => {
-        this.props.setPreviewScript(e.currentTarget.value);
-    }
-    @computed get borderRounding() {
-        let br = StrCast(this.props.Document!.borderRounding);
-        if (br.endsWith("%")) {
-            let percent = Number(br.substr(0, br.length - 1)) / 100;
-            let nativeDim = Math.min(NumCast(this.layoutDoc!.nativeWidth), NumCast(this.layoutDoc!.nativeHeight));
-            let minDim = percent * (nativeDim ? nativeDim : Math.min(this.PanelWidth(), this.PanelHeight()));
-            return minDim;
-        }
-        return undefined;
-    }
 
+    @computed get borderRounding() { return StrCast(this.props.Document!.borderRounding); }
 
     render() {
         let input = this.props.previewScript === undefined ? (null) :
-            <div ref={this.createTarget}><input className="collectionSchemaView-input" value={this.props.previewScript} onChange={this.onPreviewScriptChange}
+            <div ref={this.createTarget}><input className="collectionSchemaView-input" value={this.props.previewScript} onChange={e => this.props.setPreviewScript(e.currentTarget.value)}
                 style={{ left: `calc(50% - ${Math.min(75, (this.props.Document ? this.PanelWidth() / 2 : 75))}px)` }} /></div>;
         return (<div className="collectionSchemaView-previewRegion"
             style={{ width: this.props.PanelWidth(), height: this.props.PanelHeight() }}>
@@ -987,7 +891,6 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
                     style={{
                         transform: `translate(${this.centeringOffset}px, 0px)`,
                         borderRadius: this.borderRounding,
-                        display: "inline",
                         height: this.props.PanelHeight(),
                         width: this.props.PanelWidth()
                     }}>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c091f1260..54a687c34 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -668,7 +668,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                     {searchHighlight}
                 </div>
             }
-        </div>
+        </div>;
     }
 }
 
diff --git a/src/server/index.ts b/src/server/index.ts
index 1595781dc..c6753a253 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -1049,34 +1049,42 @@ addSecureRoute({
 
         let failed: number[] = [];
 
-        const batched = BatchedArray.from<GooglePhotosUploadUtils.MediaInput>(media, { batchSize: 25 });
-        const newMediaItems = await batched.batchedMapPatientInterval<NewMediaItem>(
-            { magnitude: 100, unit: TimeUnit.Milliseconds },
-            async (batch, collector) => {
-                for (let index = 0; index < batch.length; index++) {
-                    const { url, description } = batch[index];
-                    const uploadToken = await GooglePhotosUploadUtils.DispatchGooglePhotosUpload(url);
-                    if (!uploadToken) {
-                        failed.push(index);
-                    } else {
-                        collector.push({
-                            description,
-                            simpleMediaItem: { uploadToken }
-                        });
-                    }
-                }
-            }
-        );
-
-        const failedCount = failed.length;
-        if (failedCount) {
-            console.error(`Unable to upload ${failedCount} image${failedCount === 1 ? "" : "s"} to Google's servers`);
-        }
-
-        GooglePhotosUploadUtils.CreateMediaItems(newMediaItems, req.body.album).then(
-            results => _success(res, { results, failed }),
-            error => _error(res, mediaError, error)
-        );
+        // bcz: this doesn't compile:
+        // Using ts-node version 7.0.1, typescript version 3.5.3
+        // [ERROR] 09:54:48 ⨯ Unable to compile TypeScript:
+        //  src/server/index.ts(1055,13): error TS2345: Argument of type '(batch: MediaInput[], collector: BatchContext) => Promise<void>' is not assignable to parameter of type 'BatchFunction<MediaInput, NewMediaItem[] | Promise<NewMediaItem[]>>'.
+        //   Type 'Promise<void>' is not assignable to type 'NewMediaItem[] | Promise<NewMediaItem[]>'.
+        //     Type 'Promise<void>' is not assignable to type 'Promise<NewMediaItem[]>'.
+        //       Type 'void' is not assignable to type 'NewMediaItem[]'.
+        // src/server/index.ts(1062,35): error TS2339: Property 'push' does not exist on type 'BatchContext'.
+        // const batched = BatchedArray.from<GooglePhotosUploadUtils.MediaInput>(media, { batchSize: 25 });
+        // const newMediaItems = await batched.batchedMapPatientInterval<NewMediaItem>(
+        //     { magnitude: 100, unit: TimeUnit.Milliseconds },
+        //     async (batch, collector) => {
+        //         for (let index = 0; index < batch.length; index++) {
+        //             const { url, description } = batch[index];
+        //             const uploadToken = await GooglePhotosUploadUtils.DispatchGooglePhotosUpload(url);
+        //             if (!uploadToken) {
+        //                 failed.push(index);
+        //             } else {
+        //                 collector.push({
+        //                     description,
+        //                     simpleMediaItem: { uploadToken }
+        //                 });
+        //             }
+        //         }
+        //     }
+        // );
+
+        // const failedCount = failed.length;
+        // if (failedCount) {
+        //     console.error(`Unable to upload ${failedCount} image${failedCount === 1 ? "" : "s"} to Google's servers`);
+        // }
+
+        // GooglePhotosUploadUtils.CreateMediaItems(newMediaItems, req.body.album).then(
+        //     results => _success(res, { results, failed }),
+        //     error => _error(res, mediaError, error)
+        // );
     }
 });
 
-- 
cgit v1.2.3-70-g09d2


From 5c6dc8fb25c2ac65a9efa534ee86211ac6d68301 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Fri, 8 Nov 2019 15:14:56 -0500
Subject: moved schemaPreview into ContentFittingDOcumentView.  fixed dragging
 link anchors

---
 src/client/views/DocumentDecorations.tsx           |   2 +-
 .../views/collections/CollectionSchemaView.scss    |  22 ---
 .../views/collections/CollectionSchemaView.tsx     | 203 ++++-----------------
 .../views/collections/CollectionStackingView.tsx   |   6 +-
 .../views/collections/CollectionTreeView.tsx       |   4 +-
 .../views/nodes/ContentFittingDocumentView.scss    |  23 +++
 .../views/nodes/ContentFittingDocumentView.tsx     | 117 ++++++++++++
 src/client/views/nodes/DocumentView.tsx            |  84 +++++----
 .../views/presentationview/PresElementBox.tsx      |   4 +-
 9 files changed, 223 insertions(+), 242 deletions(-)
 create mode 100644 src/client/views/nodes/ContentFittingDocumentView.scss
 create mode 100644 src/client/views/nodes/ContentFittingDocumentView.tsx

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index b46caf3ea..0336440d5 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -556,7 +556,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     render() {
         var bounds = this.Bounds;
         let seldoc = SelectionManager.SelectedDocuments().length ? SelectionManager.SelectedDocuments()[0] : undefined;
-        if (bounds.x === Number.MAX_VALUE || !seldoc || this._hidden || isNaN(bounds.r) || isNaN(bounds.b) || isNaN(bounds.x) || isNaN(bounds.y)) {
+        if (SelectionManager.GetIsDragging() || bounds.x === Number.MAX_VALUE || !seldoc || this._hidden || isNaN(bounds.r) || isNaN(bounds.b) || isNaN(bounds.x) || isNaN(bounds.y)) {
             return (null);
         }
         let minimizeIcon = (
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
index 36c6c7b0e..cb95dcbbc 100644
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ b/src/client/views/collections/CollectionSchemaView.scss
@@ -39,28 +39,6 @@
     }
 }
 
-.collectionSchemaView-previewRegion {
-    position: relative;
-    height: auto !important;
-
-    .collectionSchemaView-previewDoc {
-        position: absolute;
-        display: inline;
-    }
-
-    .collectionSchemaView-input {
-        position: absolute;
-        max-width: 150px;
-        width: 100%;
-        bottom: 0px;
-    }
-
-    .documentView-node:first-child {
-        position: relative;
-        background: $light-color;
-    }
-}
-
 .ReactTable {
     width: 100%;
     background: white;
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index b840dc5f8..203c68463 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -1,36 +1,34 @@
 import React = require("react");
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { faCog, faPlus, faTable, faSortUp, faSortDown } from '@fortawesome/free-solid-svg-icons';
+import { faCog, faPlus, faSortDown, faSortUp, faTable } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, trace, untracked } from "mobx";
+import { action, computed, observable, untracked } from "mobx";
 import { observer } from "mobx-react";
-import ReactTable, { CellInfo, ComponentPropsGetterR, Column, RowInfo, ResizedChangeFunction, Resize, SortingRule } from "react-table";
+import ReactTable, { CellInfo, Column, ComponentPropsGetterR, Resize, SortingRule } from "react-table";
 import "react-table/react-table.css";
-import { emptyFunction, returnOne, returnEmptyString } from "../../../Utils";
 import { Doc, DocListCast, Field, Opt } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
-import { Docs, DocumentOptions } from "../../documents/Documents";
+import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
+import { ComputedField } from "../../../new_fields/ScriptField";
 import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
+import { Docs, DocumentOptions } from "../../documents/Documents";
+import { DocumentType } from "../../documents/DocumentTypes";
 import { Gateway } from "../../northstar/manager/Gateway";
-import { DragManager } from "../../util/DragManager";
-import { CompileScript, ts, Transformer } from "../../util/Scripting";
+import { CompileScript, Transformer, ts } from "../../util/Scripting";
 import { Transform } from "../../util/Transform";
+import { undoBatch } from "../../util/UndoManager";
 import { COLLECTION_BORDER_WIDTH } from '../../views/globalCssVariables.scss';
 import { ContextMenu } from "../ContextMenu";
 import '../DocumentDecorations.scss';
-import { DocumentView } from "../nodes/DocumentView";
+import { CellProps, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDocCell, CollectionSchemaNumberCell, CollectionSchemaStringCell } from "./CollectionSchemaCells";
+import { CollectionSchemaAddColumnHeader, CollectionSchemaHeader } from "./CollectionSchemaHeaders";
+import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC";
 import "./CollectionSchemaView.scss";
 import { CollectionSubView } from "./CollectionSubView";
 import { CollectionView } from "./CollectionView";
-import { undoBatch } from "../../util/UndoManager";
-import { CollectionSchemaHeader, CollectionSchemaAddColumnHeader } from "./CollectionSchemaHeaders";
-import { CellProps, CollectionSchemaCell, CollectionSchemaNumberCell, CollectionSchemaStringCell, CollectionSchemaBooleanCell, CollectionSchemaCheckboxCell, CollectionSchemaDocCell } from "./CollectionSchemaCells";
-import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC";
-import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
-import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
-import { DocumentType } from "../../documents/DocumentTypes";
+import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
 
 library.add(faCog, faPlus, faSortUp, faSortDown);
 library.add(faTable);
@@ -72,14 +70,14 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
         super.CreateDropTarget(ele);
     }
 
-    isFocused = (doc: Doc): boolean => !this.props.isSelected() ? false : doc === this._focusedTable;
+    isFocused = (doc: Doc): boolean => this.props.isSelected() && doc === this._focusedTable;
 
     @action setFocused = (doc: Doc) => this._focusedTable = doc;
 
     @action setPreviewDoc = (doc: Doc) => this.previewDoc = doc;
 
     @undoBatch
-    @action setPreviewScript = (script: string) => this.previewScript = script;
+    @action setPreviewScript = (script: string) => this.previewScript = script
 
     //toggles preview side-panel of schema
     @action
@@ -123,9 +121,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
 
     @computed
     get previewDocument(): Doc | undefined {
-        let selected = this.previewDoc;
-        let pdc = selected ? (this.previewScript && this.previewScript !== "this" ? FieldValue(Cast(selected[this.previewScript], Doc)) : selected) : undefined;
-        return pdc;
+        return this.previewDoc ? (this.previewScript && this.previewScript !== "this" ? FieldValue(Cast(this.previewDoc[this.previewScript], Doc)) : this.previewDoc) : undefined;
     }
 
     getPreviewTransform = (): Transform => {
@@ -142,7 +138,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
     get previewPanel() {
         let layoutDoc = this.previewDocument ? Doc.expandTemplateLayout(this.previewDocument, this.props.DataDoc) : undefined;
         return <div ref={this.createTarget}>
-            <CollectionSchemaPreview
+            <ContentFittingDocumentView
                 Document={layoutDoc}
                 DataDocument={this.previewDocument !== this.props.DataDoc ? this.props.DataDoc : undefined}
                 fieldKey={this.props.fieldKey}
@@ -298,11 +294,9 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
         let tableIsFocused = this.props.isFocused(this.props.Document);
         let focusedRow = this._focusedCell.row;
         let focusedCol = this._focusedCell.col;
-        let isEditable = !this._headerIsEditing;// && this.props.isSelected();
-
-        let children = this.childDocs;
+        let isEditable = !this._headerIsEditing;
 
-        if (children.reduce((found, doc) => found || doc.type === "collection", false)) {
+        if (this.childDocs.reduce((found, doc) => found || doc.type === "collection", false)) {
             columns.push(
                 {
                     expander: true,
@@ -423,14 +417,12 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     }
 
     private getTdProps: ComponentPropsGetterR = (state, rowInfo, column, instance) => {
-        if (!rowInfo) return {};
-        if (!column) return {};
+        if (!rowInfo || column) return {};
 
         let row = rowInfo.index;
         //@ts-ignore
         let col = this.columns.map(c => c.heading).indexOf(column!.id);
         let isFocused = this._focusedCell.row === row && this._focusedCell.col === col && this.props.isFocused(this.props.Document);
-        let isEditing = this.props.isFocused(this.props.Document) && this._cellIsEditing;
         // TODO: editing border doesn't work :(
         return {
             style: {
@@ -439,21 +431,20 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
         };
     }
 
-    @action onExpandCollection = (collection: Doc) => this._openCollections.push(collection[Id]);
-
     @action
     onCloseCollection = (collection: Doc): void => {
         let index = this._openCollections.findIndex(col => col === collection[Id]);
         if (index > -1) this._openCollections.splice(index, 1);
     }
 
+    @action onExpandCollection = (collection: Doc) => this._openCollections.push(collection[Id]);
     @action setCellIsEditing = (isEditing: boolean) => this._cellIsEditing = isEditing;
     @action setHeaderIsEditing = (isEditing: boolean) => this._headerIsEditing = isEditing;
 
     onPointerDown = (e: React.PointerEvent): void => {
         this.props.setFocused(this.props.Document);
-        if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey) {
-            if (this.props.isSelected()) e.stopPropagation();
+        if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey && this.props.isSelected()) {
+            e.stopPropagation();
         }
     }
 
@@ -497,19 +488,12 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     @action
     createColumn = () => {
         let index = 0;
-        let columns = this.columns;
-        let found = columns.findIndex(col => col.heading.toUpperCase() === "New field".toUpperCase()) > -1;
-        if (!found) {
-            columns.push(new SchemaHeaderField("New field", "#f1efeb"));
-            this.columns = columns;
-            return;
-        }
+        let found = this.columns.findIndex(col => col.heading.toUpperCase() === "New field".toUpperCase()) > -1;
         while (found) {
             index++;
-            found = columns.findIndex(col => col.heading.toUpperCase() === ("New field (" + index + ")").toUpperCase()) > -1;
+            found = this.columns.findIndex(col => col.heading.toUpperCase() === ("New field (" + index + ")").toUpperCase()) > -1;
         }
-        columns.push(new SchemaHeaderField("New field (" + index + ")", "#f1efeb"));
-        this.columns = columns;
+        this.columns.push(new SchemaHeaderField(`New field ${index ? "(" + index + ")" : ""}`, "#f1efeb"));
     }
 
     @undoBatch
@@ -602,7 +586,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     }
 
     @action
-    setColumns = (columns: SchemaHeaderField[]) => this.columns = columns;
+    setColumns = (columns: SchemaHeaderField[]) => this.columns = columns
 
     @undoBatch
     reorderColumns = (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columnsValues: SchemaHeaderField[]) => {
@@ -648,11 +632,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
         let textWrapped = this.textWrappedRows;
         let index = textWrapped.findIndex(id => doc[Id] === id);
 
-        if (index > -1) {
-            textWrapped.splice(index, 1);
-        } else {
-            textWrapped.push(doc[Id]);
-        }
+        index > -1 ? textWrapped.splice(index, 1) : textWrapped.push(doc[Id]);
 
         this.textWrappedRows = textWrapped;
     }
@@ -682,13 +662,8 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
             expanded={expanded}
             resized={this.resized}
             onResizedChange={this.onResizedChange}
-            SubComponent={hasCollectionChild ?
-                row => {
-                    if (row.original.type === "collection") {
-                        return <div className="reactTable-sub"><SchemaTable {...this.props} Document={row.original} childDocs={undefined} /></div>;
-                    }
-                }
-                : undefined}
+            SubComponent={!hasCollectionChild ? undefined : row => (row.original.type !== "collection") ? (null) :
+                <div className="reactTable-sub"><SchemaTable {...this.props} Document={row.original} childDocs={undefined} /></div>}
 
         />;
     }
@@ -804,125 +779,9 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
     }
 
     render() {
-        return <div className="collectionSchemaView-table" onPointerDown={this.onPointerDown} onWheel={e => this.props.active() && e.stopPropagation()}
-            onDrop={e => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} >
+        return <div className="collectionSchemaView-table" onPointerDown={this.onPointerDown} onWheel={e => this.props.active() && e.stopPropagation()} onDrop={e => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} >
             {this.reactTable}
             <div className="collectionSchemaView-addRow" onClick={() => this.createRow()}>+ new</div>
         </div>;
     }
-}
-
-
-interface CollectionSchemaPreviewProps {
-    Document?: Doc;
-    DataDocument?: Doc;
-    childDocs?: Doc[];
-    renderDepth: number;
-    fitToBox?: boolean;
-    fieldKey: string;
-    PanelWidth: () => number;
-    PanelHeight: () => number;
-    ruleProvider: Doc | undefined;
-    focus?: (doc: Doc) => void;
-    showOverlays?: (doc: Doc) => { title?: string, caption?: string };
-    CollectionView?: CollectionView;
-    CollectionDoc?: Doc;
-    onClick?: ScriptField;
-    getTransform: () => Transform;
-    addDocument: (document: Doc) => boolean;
-    moveDocument: (document: Doc, target: Doc, addDoc: ((doc: Doc) => boolean)) => boolean;
-    removeDocument: (document: Doc) => boolean;
-    active: () => boolean;
-    whenActiveChanged: (isActive: boolean) => void;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
-    pinToPres: (document: Doc) => void;
-    setPreviewScript: (script: string) => void;
-    previewScript?: string;
-}
-
-@observer
-export class CollectionSchemaPreview extends React.Component<CollectionSchemaPreviewProps>{
-    private dropDisposer?: DragManager.DragDropDisposer;
-    private get layoutDoc() { return this.props.Document && Doc.Layout(this.props.Document); }
-    private get nativeWidth() { return NumCast(this.layoutDoc!.nativeWidth, this.props.PanelWidth()); }
-    private get nativeHeight() { return NumCast(this.layoutDoc!.nativeHeight, this.props.PanelHeight()); }
-    private contentScaling = () => {
-        let wscale = this.props.PanelWidth() / (this.nativeWidth ? this.nativeWidth : this.props.PanelWidth());
-        if (wscale * this.nativeHeight > this.props.PanelHeight()) {
-            return this.props.PanelHeight() / (this.nativeHeight ? this.nativeHeight : this.props.PanelHeight());
-        }
-        return wscale;
-    }
-    private createTarget = (ele: HTMLDivElement) => {
-        this.dropDisposer && this.dropDisposer();
-        if (ele) {
-            this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } });
-        }
-    }
-
-    @undoBatch
-    @action
-    drop = (e: Event, de: DragManager.DropEvent) => {
-        if (de.data instanceof DragManager.DocumentDragData) {
-            this.props.childDocs && this.props.childDocs.map(otherdoc => {
-                let target = Doc.GetProto(otherdoc);
-                target.layout = ComputedField.MakeFunction("this.image_data[0]");
-                target.layoutCustom = Doc.MakeDelegate(de.data.draggedDocuments[0]);
-            });
-            e.stopPropagation();
-        }
-        return true;
-    }
-    private PanelWidth = () => this.nativeWidth && (!this.props.Document || !this.props.Document.fitWidth) ? this.nativeWidth * this.contentScaling() : this.props.PanelWidth();
-    private PanelHeight = () => this.nativeHeight && (!this.props.Document || !this.props.Document.fitWidth) ? this.nativeHeight * this.contentScaling() : this.props.PanelHeight();
-    private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, 0).scale(1 / this.contentScaling());
-    get centeringOffset() { return this.nativeWidth && (!this.props.Document || !this.props.Document.fitWidth) ? (this.props.PanelWidth() - this.nativeWidth * this.contentScaling()) / 2 : 0; }
-
-    @computed get borderRounding() { return StrCast(this.props.Document!.borderRounding); }
-
-    render() {
-        let input = this.props.previewScript === undefined ? (null) :
-            <div ref={this.createTarget}><input className="collectionSchemaView-input" value={this.props.previewScript} onChange={e => this.props.setPreviewScript(e.currentTarget.value)}
-                style={{ left: `calc(50% - ${Math.min(75, (this.props.Document ? this.PanelWidth() / 2 : 75))}px)` }} /></div>;
-        return (<div className="collectionSchemaView-previewRegion"
-            style={{ width: this.props.PanelWidth(), height: this.props.PanelHeight() }}>
-            {!this.props.Document || !this.props.PanelWidth ? (null) : (
-                <div className="collectionSchemaView-previewDoc"
-                    style={{
-                        transform: `translate(${this.centeringOffset}px, 0px)`,
-                        borderRadius: this.borderRounding,
-                        height: this.props.PanelHeight(),
-                        width: this.props.PanelWidth()
-                    }}>
-                    <DocumentView {...this.props}
-                        DataDoc={this.props.DataDocument}
-                        Document={this.props.Document}
-                        fitToBox={this.props.fitToBox}
-                        onClick={this.props.onClick}
-                        ruleProvider={this.props.ruleProvider}
-                        showOverlays={this.props.showOverlays}
-                        addDocument={this.props.addDocument}
-                        removeDocument={this.props.removeDocument}
-                        moveDocument={this.props.moveDocument}
-                        whenActiveChanged={this.props.whenActiveChanged}
-                        ContainingCollectionView={this.props.CollectionView}
-                        ContainingCollectionDoc={this.props.CollectionDoc}
-                        addDocTab={this.props.addDocTab}
-                        pinToPres={this.props.pinToPres}
-                        parentActive={this.props.active}
-                        ScreenToLocalTransform={this.getTransform}
-                        renderDepth={this.props.renderDepth + 1}
-                        ContentScaling={this.contentScaling}
-                        PanelWidth={this.PanelWidth}
-                        PanelHeight={this.PanelHeight}
-                        focus={this.props.focus || emptyFunction}
-                        backgroundColor={returnEmptyString}
-                        bringToFront={emptyFunction}
-                        zoomToScale={emptyFunction}
-                        getScale={returnOne}
-                    />
-                </div>)}
-            {input}
-        </div>);
-    }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 37d897088..15033e51a 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -16,7 +16,7 @@ import { DragManager } from "../../util/DragManager";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
 import { EditableView } from "../EditableView";
-import { CollectionSchemaPreview } from "./CollectionSchemaView";
+import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
 import "./CollectionStackingView.scss";
 import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn";
 import { CollectionSubView } from "./CollectionSubView";
@@ -165,7 +165,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         let layoutDoc = Doc.Layout(doc);
         let height = () => this.getDocHeight(doc);
         let finalDxf = () => dxf().scale(this.columnWidth / layoutDoc[WidthSym]());
-        return <CollectionSchemaPreview
+        return <ContentFittingDocumentView
             Document={doc}
             DataDocument={dataDoc}
             fieldKey={this.props.fieldKey}
@@ -189,7 +189,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             pinToPres={this.props.pinToPres}
             setPreviewScript={emptyFunction}
             previewScript={undefined}>
-        </CollectionSchemaPreview>;
+        </ContentFittingDocumentView>;
     }
     getDocHeight(d?: Doc) {
         if (!d) return 0;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 89cc69ccf..8726726bb 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -24,7 +24,7 @@ import { MainView } from '../MainView';
 import { KeyValueBox } from '../nodes/KeyValueBox';
 import { Templates } from '../Templates';
 import { CollectionViewType } from './CollectionView';
-import { CollectionSchemaPreview } from './CollectionSchemaView';
+import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView';
 import { CollectionSubView } from "./CollectionSubView";
 import "./CollectionTreeView.scss";
 import React = require("react");
@@ -314,7 +314,7 @@ class TreeView extends React.Component<TreeViewProps> {
         } else {
             let layoutDoc = Doc.Layout(this.props.document);
             return <div ref={this._dref} style={{ display: "inline-block", height: this.docHeight() }} key={this.props.document[Id] + this.props.document.title}>
-                <CollectionSchemaPreview
+                <ContentFittingDocumentView
                     Document={layoutDoc}
                     DataDocument={this.templateDataDoc}
                     fieldKey={this.fieldKey}
diff --git a/src/client/views/nodes/ContentFittingDocumentView.scss b/src/client/views/nodes/ContentFittingDocumentView.scss
new file mode 100644
index 000000000..796e67269
--- /dev/null
+++ b/src/client/views/nodes/ContentFittingDocumentView.scss
@@ -0,0 +1,23 @@
+@import "../globalCssVariables";
+
+.contentFittingDocumentView {
+    position: relative;
+    height: auto !important;
+
+    .contentFittingDocumentView-previewDoc {
+        position: absolute;
+        display: inline;
+    }
+
+    .contentFittingDocumentView-input {
+        position: absolute;
+        max-width: 150px;
+        width: 100%;
+        bottom: 0px;
+    }
+
+    .documentView-node:first-child {
+        position: relative;
+        background: $light-color;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
new file mode 100644
index 000000000..f41c4fc91
--- /dev/null
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -0,0 +1,117 @@
+import React = require("react");
+import { action, computed } from "mobx";
+import { observer } from "mobx-react";
+import "react-table/react-table.css";
+import { Doc } from "../../../new_fields/Doc";
+import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
+import { NumCast, StrCast } from "../../../new_fields/Types";
+import { emptyFunction, returnEmptyString, returnOne } from "../../../Utils";
+import { DragManager } from "../../util/DragManager";
+import { Transform } from "../../util/Transform";
+import { undoBatch } from "../../util/UndoManager";
+import '../DocumentDecorations.scss';
+import { DocumentView } from "../nodes/DocumentView";
+import "./ContentFittingDocumentView.scss";
+import { CollectionView } from "../collections/CollectionView";
+
+interface ContentFittingDocumentViewProps {
+    Document?: Doc;
+    DataDocument?: Doc;
+    childDocs?: Doc[];
+    renderDepth: number;
+    fitToBox?: boolean;
+    fieldKey: string;
+    PanelWidth: () => number;
+    PanelHeight: () => number;
+    ruleProvider: Doc | undefined;
+    focus?: (doc: Doc) => void;
+    showOverlays?: (doc: Doc) => { title?: string, caption?: string };
+    CollectionView?: CollectionView;
+    CollectionDoc?: Doc;
+    onClick?: ScriptField;
+    getTransform: () => Transform;
+    addDocument: (document: Doc) => boolean;
+    moveDocument: (document: Doc, target: Doc, addDoc: ((doc: Doc) => boolean)) => boolean;
+    removeDocument: (document: Doc) => boolean;
+    active: () => boolean;
+    whenActiveChanged: (isActive: boolean) => void;
+    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    pinToPres: (document: Doc) => void;
+    setPreviewScript: (script: string) => void;
+    previewScript?: string;
+}
+
+@observer
+export class ContentFittingDocumentView extends React.Component<ContentFittingDocumentViewProps>{
+    private get layoutDoc() { return this.props.Document && Doc.Layout(this.props.Document); }
+    private get nativeWidth() { return NumCast(this.layoutDoc!.nativeWidth, this.props.PanelWidth()); }
+    private get nativeHeight() { return NumCast(this.layoutDoc!.nativeHeight, this.props.PanelHeight()); }
+    private contentScaling = () => {
+        let wscale = this.props.PanelWidth() / (this.nativeWidth ? this.nativeWidth : this.props.PanelWidth());
+        if (wscale * this.nativeHeight > this.props.PanelHeight()) {
+            return this.props.PanelHeight() / (this.nativeHeight ? this.nativeHeight : this.props.PanelHeight());
+        }
+        return wscale;
+    }
+
+    @undoBatch
+    @action
+    drop = (e: Event, de: DragManager.DropEvent) => {
+        if (de.data instanceof DragManager.DocumentDragData) {
+            this.props.childDocs && this.props.childDocs.map(otherdoc => {
+                let target = Doc.GetProto(otherdoc);
+                target.layout = ComputedField.MakeFunction("this.image_data[0]");
+                target.layoutCustom = Doc.MakeDelegate(de.data.draggedDocuments[0]);
+            });
+            e.stopPropagation();
+        }
+        return true;
+    }
+    private PanelWidth = () => this.nativeWidth && (!this.props.Document || !this.props.Document.fitWidth) ? this.nativeWidth * this.contentScaling() : this.props.PanelWidth();
+    private PanelHeight = () => this.nativeHeight && (!this.props.Document || !this.props.Document.fitWidth) ? this.nativeHeight * this.contentScaling() : this.props.PanelHeight();
+    private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, 0).scale(1 / this.contentScaling());
+    private get centeringOffset() { return this.nativeWidth && (!this.props.Document || !this.props.Document.fitWidth) ? (this.props.PanelWidth() - this.nativeWidth * this.contentScaling()) / 2 : 0; }
+
+    @computed get borderRounding() { return StrCast(this.props.Document!.borderRounding); }
+
+    render() {
+        return (<div className="contentFittingDocumentView" style={{ width: this.props.PanelWidth(), height: this.props.PanelHeight() }}>
+            {!this.props.Document || !this.props.PanelWidth ? (null) : (
+                <div className="contentFittingDocumentView-previewDoc"
+                    style={{
+                        transform: `translate(${this.centeringOffset}px, 0px)`,
+                        borderRadius: this.borderRounding,
+                        height: this.props.PanelHeight(),
+                        width: this.props.PanelWidth()
+                    }}>
+                    <DocumentView {...this.props}
+                        DataDoc={this.props.DataDocument}
+                        Document={this.props.Document}
+                        fitToBox={this.props.fitToBox}
+                        onClick={this.props.onClick}
+                        ruleProvider={this.props.ruleProvider}
+                        showOverlays={this.props.showOverlays}
+                        addDocument={this.props.addDocument}
+                        removeDocument={this.props.removeDocument}
+                        moveDocument={this.props.moveDocument}
+                        whenActiveChanged={this.props.whenActiveChanged}
+                        ContainingCollectionView={this.props.CollectionView}
+                        ContainingCollectionDoc={this.props.CollectionDoc}
+                        addDocTab={this.props.addDocTab}
+                        pinToPres={this.props.pinToPres}
+                        parentActive={this.props.active}
+                        ScreenToLocalTransform={this.getTransform}
+                        renderDepth={this.props.renderDepth + 1}
+                        ContentScaling={this.contentScaling}
+                        PanelWidth={this.PanelWidth}
+                        PanelHeight={this.PanelHeight}
+                        focus={this.props.focus || emptyFunction}
+                        backgroundColor={returnEmptyString}
+                        bringToFront={emptyFunction}
+                        zoomToScale={emptyFunction}
+                        getScale={returnOne}
+                    />
+                </div>)}
+        </div>);
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 54a687c34..93052ea73 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -577,27 +577,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         return anchor.type === DocumentType.AUDIO && NumCast(ept) ? false : true;
     }
 
-    render() {
-        if (!this.props.Document) return (null);
-        trace();
-        const animDims = this.Document.animateToDimensions ? Array.from(this.Document.animateToDimensions) : undefined;
-        const ruleColor = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleColor_" + this.Document.heading]) : undefined;
-        const ruleRounding = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleRounding_" + this.Document.heading]) : undefined;
-        const colorSet = this.setsLayoutProp("backgroundColor");
-        const clusterCol = this.props.ContainingCollectionDoc && this.props.ContainingCollectionDoc.clusterOverridesDefaultBackground;
-        const backgroundColor = this.Document.isBackground || (clusterCol && !colorSet) ?
-            this.props.backgroundColor(this.Document) || StrCast(this.layoutDoc.backgroundColor) :
-            ruleColor && !colorSet ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.Document);
-
-        const nativeWidth = this.layoutDoc.fitWidth ? this.props.PanelWidth() - 2 : this.nativeWidth > 0 && !this.layoutDoc.ignoreAspect ? `${this.nativeWidth}px` : "100%";
-        const nativeHeight = this.layoutDoc.fitWidth ? this.props.PanelHeight() - 2 : this.Document.ignoreAspect ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%";
+    @computed get innards() {
         const showOverlays = this.props.showOverlays ? this.props.showOverlays(this.Document) : undefined;
         const showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : this.getLayoutPropStr("showTitle");
         const showCaption = showOverlays && "caption" in showOverlays ? showOverlays.caption : this.getLayoutPropStr("showCaption");
         const showTextTitle = showTitle && StrCast(this.Document.layout).indexOf("FormattedTextBox") !== -1 ? showTitle : undefined;
-        const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document);
-        const borderRounding = this.getLayoutPropStr("borderRounding") || ruleRounding;
-        const localScale = this.props.ScreenToLocalTransform().Scale * fullDegree;
         const searchHighlight = (!this.Document.searchFields ? (null) :
             <div className="documentView-searchHighlight" style={{ width: `${100 * this.props.ContentScaling()}%`, transform: `scale(${1 / this.props.ContentScaling()})` }}>
                 {this.Document.searchFields}
@@ -623,29 +607,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                     SetValue={(value: string) => (Doc.GetProto(this.Document)[showTitle] = value) ? true : true}
                 />
             </div>);
-        let animheight = animDims ? animDims[1] : nativeHeight;
-        let animwidth = animDims ? animDims[0] : nativeWidth;
-
-        const highlightColors = ["transparent", "maroon", "maroon", "yellow", "magenta", "cyan", "orange"];
-        const highlightStyles = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid", "solid"];
-        let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc.viewType !== CollectionViewType.Linear;
-        return <div className={`documentView-node${this.topMost ? "-topmost" : ""}`}
-            ref={this._mainCont}
-            style={{
-                transition: this.Document.isAnimating !== undefined ? ".5s linear" : StrCast(this.Document.transition),
-                pointerEvents: this.Document.isBackground && !this.isSelected() ? "none" : "all",
-                color: StrCast(this.Document.color),
-                outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px",
-                border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined,
-                background: this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc.viewType === CollectionViewType.Linear ? undefined : backgroundColor,
-                width: animwidth,
-                height: animheight,
-                transform: `scale(${this.layoutDoc.fitWidth ? 1 : this.props.ContentScaling()})`,
-                opacity: this.Document.opacity
-            }}
-            onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick}
-            onPointerEnter={() => Doc.BrushDoc(this.props.Document)} onPointerLeave={() => Doc.UnBrushDoc(this.props.Document)}
-        >
+        return <>
             {this.Document.links && DocListCast(this.Document.links).filter((d) => !DocListCast(this.layoutDoc.hiddenLinks).some(hidden => Doc.AreProtosEqual(hidden, d))).filter(this.isNonTemporalLink).map((d, i) =>
                 <div className="documentView-docuLinkWrapper" key={`${d[Id]}`} style={{ transform: `scale(${this.layoutDoc.fitWidth ? 1 : 1 / this.props.ContentScaling()})` }}>
                     <DocumentView {...this.props} Document={d} layoutKey={this.linkEndpoint(d)} backgroundColor={returnTransparent} removeDocument={undoBatch(doc => Doc.AddDocToList(this.layoutDoc, "hiddenLinks", doc))} />
@@ -668,6 +630,48 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                     {searchHighlight}
                 </div>
             }
+        </>
+    }
+    render() {
+        if (!this.props.Document) return (null);
+        trace();
+        const animDims = this.Document.animateToDimensions ? Array.from(this.Document.animateToDimensions) : undefined;
+        const ruleColor = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleColor_" + this.Document.heading]) : undefined;
+        const ruleRounding = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleRounding_" + this.Document.heading]) : undefined;
+        const colorSet = this.setsLayoutProp("backgroundColor");
+        const clusterCol = this.props.ContainingCollectionDoc && this.props.ContainingCollectionDoc.clusterOverridesDefaultBackground;
+        const backgroundColor = this.Document.isBackground || (clusterCol && !colorSet) ?
+            this.props.backgroundColor(this.Document) || StrCast(this.layoutDoc.backgroundColor) :
+            ruleColor && !colorSet ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.Document);
+
+        const nativeWidth = this.layoutDoc.fitWidth ? this.props.PanelWidth() - 2 : this.nativeWidth > 0 && !this.layoutDoc.ignoreAspect ? `${this.nativeWidth}px` : "100%";
+        const nativeHeight = this.layoutDoc.fitWidth ? this.props.PanelHeight() - 2 : this.Document.ignoreAspect ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%";
+        const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document);
+        const borderRounding = this.getLayoutPropStr("borderRounding") || ruleRounding;
+        const localScale = this.props.ScreenToLocalTransform().Scale * fullDegree;
+
+        let animheight = animDims ? animDims[1] : nativeHeight;
+        let animwidth = animDims ? animDims[0] : nativeWidth;
+
+        const highlightColors = ["transparent", "maroon", "maroon", "yellow", "magenta", "cyan", "orange"];
+        const highlightStyles = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid", "solid"];
+        let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc.viewType !== CollectionViewType.Linear;
+        return <div className={`documentView-node${this.topMost ? "-topmost" : ""}`} ref={this._mainCont}
+            onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick}
+            onPointerEnter={() => Doc.BrushDoc(this.props.Document)} onPointerLeave={e => Doc.UnBrushDoc(this.props.Document)}
+            style={{
+                transition: this.Document.isAnimating !== undefined ? ".5s linear" : StrCast(this.Document.transition),
+                pointerEvents: this.Document.isBackground && !this.isSelected() ? "none" : "all",
+                color: StrCast(this.Document.color),
+                outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px",
+                border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined,
+                background: this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc.viewType === CollectionViewType.Linear ? undefined : backgroundColor,
+                width: animwidth,
+                height: animheight,
+                transform: `scale(${this.layoutDoc.fitWidth ? 1 : this.props.ContentScaling()})`,
+                opacity: this.Document.opacity
+            }} >
+            {this.innards}
         </div>;
     }
 }
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 7a1b4f9fb..17b2094ec 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -13,7 +13,7 @@ import { emptyFunction, returnFalse } from "../../../Utils";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { Transform } from "../../util/Transform";
 import { CollectionViewType } from '../collections/CollectionView';
-import { CollectionSchemaPreview } from '../collections/CollectionSchemaView';
+import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView';
 import { DocComponent } from '../DocComponent';
 import { FieldView, FieldViewProps } from '../nodes/FieldView';
 import "./PresElementBox.scss";
@@ -169,7 +169,7 @@ export class PresElementBox extends DocComponent<FieldViewProps, PresDocument>(P
                 height: propDocHeight === 0 ? NumCast(this.layoutDoc.height) - NumCast(this.layoutDoc.collapsedHeight) : propDocHeight * scale(),
                 width: propDocWidth === 0 ? "auto" : propDocWidth * scale(),
             }}>
-                <CollectionSchemaPreview
+                <ContentFittingDocumentView
                     fitToBox={StrCast(this.targetDoc.type).indexOf(DocumentType.COL) !== -1}
                     Document={this.targetDoc}
                     fieldKey={this.props.fieldKey}
-- 
cgit v1.2.3-70-g09d2

