From a8664face6f19cd2373bd928c2a2b3043bb6278d Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Tue, 2 Jul 2019 19:02:51 -0400
Subject: Added arrange script to freeform views

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

(limited to 'src/client/views/MainView.tsx')

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 04ecc47cf..cc39dc04c 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -38,6 +38,7 @@ import PDFMenu from './pdf/PDFMenu';
 import { InkTool } from '../../new_fields/InkField';
 import _ from "lodash";
 import KeyManager from './GlobalKeyHandler';
+import { OverlayView } from './OverlayView';
 
 @observer
 export class MainView extends React.Component {
@@ -291,7 +292,7 @@ export class MainView extends React.Component {
             } else {
                 CollectionDockingView.Instance.AddRightSplit(doc, dataDoc);
             }
-        }
+        };
         let flyout = <DocumentView
             Document={CurrentUserUtils.UserDocument}
             DataDoc={undefined}
@@ -441,6 +442,7 @@ export class MainView extends React.Component {
                 {this.miscButtons}
                 <PDFMenu />
                 <MainOverlayTextBox />
+                <OverlayView />
             </div>
         );
     }
-- 
cgit v1.2.3-70-g09d2


From ee7572ae3d5715ddbce57db3940204a3d0a3d826 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 2 Jul 2019 19:03:01 -0400
Subject: fixed collapsing of tree view items on resize.

---
 src/client/views/MainView.tsx | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

(limited to 'src/client/views/MainView.tsx')

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index ab9fe0118..9dccb883e 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -284,7 +284,7 @@ export class MainView extends React.Component {
         document.removeEventListener("pointerup", this.onPointerUp);
     }
     @computed
-    get mainContent() {
+    get flyout() {
         let addDocTab = (doc: Doc, dataDoc: Doc | undefined, location: string) => {
             if (doc.dockingConfig) {
                 this.openWorkspace(doc);
@@ -292,7 +292,7 @@ export class MainView extends React.Component {
                 CollectionDockingView.Instance.AddRightSplit(doc, dataDoc);
             }
         };
-        let flyout = <DocumentView
+        return <DocumentView
             Document={CurrentUserUtils.UserDocument}
             DataDoc={undefined}
             addDocument={undefined}
@@ -312,6 +312,9 @@ export class MainView extends React.Component {
             zoomToScale={emptyFunction}
             getScale={returnOne}>
         </DocumentView>;
+    }
+    @computed
+    get mainContent() {
         return <div>
             <div className="mainView-libraryHandle"
                 style={{ left: `${this.flyoutWidth - 10}px` }}
@@ -319,7 +322,7 @@ export class MainView extends React.Component {
                 <span title="library View Dragger" style={{ width: "100%", height: "100%", position: "absolute" }} />
             </div>
             <div className="mainView-libraryFlyout" style={{ width: `${this.flyoutWidth}px` }}>
-                {flyout}
+                {this.flyout}
             </div>
             {this.dockingContent}
         </div>;
-- 
cgit v1.2.3-70-g09d2


From c619bad0281ea6f248c48b8d418f324f67f530dd Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 3 Jul 2019 12:00:59 -0400
Subject: added to fitToBox to treeviews.  fixed some fitToBox issues.  moved
 notifications button to library tree view.

---
 src/client/northstar/dash-nodes/HistogramBox.tsx   |  2 +-
 .../dash-nodes/HistogramBoxPrimitives.tsx          |  2 -
 src/client/views/Main.scss                         |  4 +-
 src/client/views/MainView.tsx                      | 84 ++++++++--------------
 .../views/collections/CollectionSchemaView.tsx     |  4 +-
 .../views/collections/CollectionTreeView.tsx       | 38 +++++++++-
 .../views/collections/CollectionVideoView.tsx      |  1 -
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  6 +-
 src/client/views/nodes/DocumentView.tsx            |  5 +-
 src/client/views/nodes/FieldView.tsx               |  2 +-
 src/client/views/nodes/LinkEditor.tsx              |  1 -
 src/client/views/search/SearchItem.tsx             | 26 +++----
 src/new_fields/Doc.ts                              | 12 ++++
 13 files changed, 98 insertions(+), 89 deletions(-)

(limited to 'src/client/views/MainView.tsx')

diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx
index a60eaea85..b81eafbee 100644
--- a/src/client/northstar/dash-nodes/HistogramBox.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBox.tsx
@@ -36,7 +36,7 @@ export class HistogramBox extends React.Component<FieldViewProps> {
     @computed public get HistogramResult(): HistogramResult { return this.HistoOp.Result as HistogramResult; }
     @observable public SizeConverter: SizeConverter = new SizeConverter();
 
-    @computed get createOperationParamsCache() { trace(); return this.HistoOp.CreateOperationParameters(); }
+    @computed get createOperationParamsCache() { return this.HistoOp.CreateOperationParameters(); }
     @computed get BinRanges() { return this.HistogramResult ? this.HistogramResult.binRanges : undefined; }
     @computed get ChartType() {
         return !this.BinRanges ? ChartType.SinglePoint : this.BinRanges[0] instanceof AggregateBinRange ?
diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
index 350987695..5a16b3782 100644
--- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
@@ -62,7 +62,6 @@ export class HistogramBoxPrimitives extends React.Component<HistogramPrimitivesP
     }
 
     private renderGridLinesAndLabels(axis: number) {
-        trace();
         if (!this.props.HistoBox.SizeConverter.Initialized) {
             return (null);
         }
@@ -111,7 +110,6 @@ export class HistogramBoxPrimitives extends React.Component<HistogramPrimitivesP
             x={transXpercent} width={`${widthXpercent}`} y={transYpercent} height={`${heightYpercent}`} fill={color ? `${LABColor.RGBtoHexString(color)}` : "transparent"} />);
     }
     render() {
-        trace();
         return <div className="histogramboxprimitives-container">
             {this.xaxislines}
             {this.yaxislines}
diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss
index 08f5cb8a5..44c1cb9fc 100644
--- a/src/client/views/Main.scss
+++ b/src/client/views/Main.scss
@@ -111,8 +111,8 @@ button:hover {
 //toolbar stuff
 #toolbar {
     position: absolute;
-    bottom: 62px;
-    left: 24px;
+    right: 8px;
+    top: 5px;
 
     .toolbar-button {
         display: block;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 19a04595a..1542fedef 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,44 +1,43 @@
 import { IconName, library } from '@fortawesome/fontawesome-svg-core';
-import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faArrowDown, faArrowUp, faCheck, faPenNib, faThumbtack, faRedoAlt, faTable, faTree, faUndoAlt, faBell, faCommentAlt, faCut, faExclamation } from '@fortawesome/free-solid-svg-icons';
+import { faArrowDown, faArrowUp, faBell, faCheck, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, configure, observable, runInAction, trace } from 'mobx';
+import { action, computed, configure, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
-import { CirclePicker, SliderPicker, BlockPicker, TwitterPicker, SketchPicker } from 'react-color';
 import "normalize.css";
 import * as React from 'react';
+import { SketchPicker } from 'react-color';
 import Measure from 'react-measure';
 import * as request from 'request';
+import { Doc, DocListCast, Opt } from '../../new_fields/Doc';
+import { Id } from '../../new_fields/FieldSymbols';
+import { InkTool } from '../../new_fields/InkField';
+import { List } from '../../new_fields/List';
+import { listSpec } from '../../new_fields/Schema';
+import { Cast, FieldValue } from '../../new_fields/Types';
 import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
 import { RouteStore } from '../../server/RouteStore';
-import { emptyFunction, returnTrue, Utils, returnOne, returnZero } from '../../Utils';
-import { Docs, DocTypes } from '../documents/Documents';
-import { SetupDrag, DragManager } from '../util/DragManager';
+import { emptyFunction, returnOne, returnTrue } from '../../Utils';
+import { DocServer } from '../DocServer';
+import { Docs } from '../documents/Documents';
+import { SetupDrag } from '../util/DragManager';
+import { HistoryUtil } from '../util/History';
 import { Transform } from '../util/Transform';
 import { UndoManager } from '../util/UndoManager';
-import { PresentationView } from './presentationview/PresentationView';
+import { CollectionBaseView } from './collections/CollectionBaseView';
 import { CollectionDockingView } from './collections/CollectionDockingView';
 import { ContextMenu } from './ContextMenu';
 import { DocumentDecorations } from './DocumentDecorations';
+import KeyManager from './GlobalKeyHandler';
 import { InkingControl } from './InkingControl';
 import "./Main.scss";
 import { MainOverlayTextBox } from './MainOverlayTextBox';
 import { DocumentView } from './nodes/DocumentView';
+import { OverlayView } from './OverlayView';
+import PDFMenu from './pdf/PDFMenu';
+import { PresentationView } from './presentationview/PresentationView';
 import { PreviewCursor } from './PreviewCursor';
 import { FilterBox } from './search/FilterBox';
-import { SelectionManager } from '../util/SelectionManager';
-import { FieldResult, Field, Doc, Opt, DocListCast } from '../../new_fields/Doc';
-import { Cast, FieldValue, StrCast, PromiseValue } from '../../new_fields/Types';
-import { DocServer } from '../DocServer';
-import { listSpec } from '../../new_fields/Schema';
-import { Id } from '../../new_fields/FieldSymbols';
-import { HistoryUtil } from '../util/History';
-import { CollectionBaseView } from './collections/CollectionBaseView';
-import { List } from '../../new_fields/List';
-import PDFMenu from './pdf/PDFMenu';
-import { InkTool } from '../../new_fields/InkField';
-import _ from "lodash";
-import KeyManager from './GlobalKeyHandler';
-import { OverlayView } from './OverlayView';
+import { CollectionTreeView } from './collections/CollectionTreeView';
 
 @observer
 export class MainView extends React.Component {
@@ -184,8 +183,6 @@ export class MainView extends React.Component {
         }
     }
 
-    @observable _notifsCol: Opt<Doc>;
-
     @action
     openWorkspace = async (doc: Doc, fromHistory = false) => {
         CurrentUserUtils.MainDocId = doc[Id];
@@ -197,18 +194,12 @@ export class MainView extends React.Component {
             if (col) {
                 const l = Cast(col.data, listSpec(Doc));
                 if (l) {
-                    runInAction(() => this._notifsCol = col);
+                    runInAction(() => CollectionTreeView.NotifsCol = col);
                 }
             }
         }, 100);
     }
 
-    openNotifsCol = () => {
-        if (this._notifsCol && CollectionDockingView.Instance) {
-            CollectionDockingView.Instance.AddRightSplit(this._notifsCol, undefined);
-        }
-    }
-
     onDrop = (e: React.DragEvent<HTMLDivElement>) => {
         e.preventDefault();
         e.stopPropagation();
@@ -284,24 +275,25 @@ export class MainView extends React.Component {
         document.removeEventListener("pointermove", this.onPointerMove);
         document.removeEventListener("pointerup", this.onPointerUp);
     }
+    flyoutWidthFunc = () => this.flyoutWidth;
+    addDocTabFunc = (doc: Doc) => {
+        if (doc.dockingConfig) {
+            this.openWorkspace(doc);
+        } else {
+            CollectionDockingView.Instance.AddRightSplit(doc, undefined);
+        }
+    };
     @computed
     get flyout() {
-        let addDocTab = (doc: Doc, dataDoc: Doc | undefined, location: string) => {
-            if (doc.dockingConfig) {
-                this.openWorkspace(doc);
-            } else {
-                CollectionDockingView.Instance.AddRightSplit(doc, dataDoc);
-            }
-        };
         return <DocumentView
             Document={CurrentUserUtils.UserDocument}
             DataDoc={undefined}
             addDocument={undefined}
-            addDocTab={(doc: Doc) => addDocTab(doc, undefined, "onRight")}
+            addDocTab={this.addDocTabFunc}
             removeDocument={undefined}
             ScreenToLocalTransform={Transform.Identity}
             ContentScaling={returnOne}
-            PanelWidth={this.getPWidth}
+            PanelWidth={this.flyoutWidthFunc}
             PanelHeight={this.getPHeight}
             renderDepth={0}
             selectOnLoad={false}
@@ -403,23 +395,9 @@ export class MainView extends React.Component {
     /* @TODO this should really be moved into a moveable toolbar component, but for now let's put it here to meet the deadline */
     @computed
     get miscButtons() {
-        const length = this._notifsCol ? DocListCast(this._notifsCol.data).length : 0;
-        const notifsRef = React.createRef<HTMLDivElement>();
-        const dragNotifs = action(() => this._notifsCol!);
         let logoutRef = React.createRef<HTMLDivElement>();
 
         return [
-            <div id="toolbar" key="toolbar">
-                <div ref={notifsRef}>
-                    <button className="toolbar-button round-button" title="Notifs"
-                        onClick={this.openNotifsCol} onPointerDown={this._notifsCol ? SetupDrag(notifsRef, dragNotifs) : emptyFunction}>
-                        <FontAwesomeIcon icon={faBell} size="sm" />
-                    </button>
-                    <div className="main-notifs-badge" style={length > 0 ? { "display": "initial" } : { "display": "none" }}>
-                        {length}
-                    </div>
-                </div>
-            </div >,
             this.isSearchVisible ? <div className="main-searchDiv" key="search" style={{ top: '34px', right: '1px', position: 'absolute' }} > <FilterBox /> </div> : null,
             <div className="main-buttonDiv" key="logout" style={{ bottom: '0px', right: '1px', position: 'absolute' }} ref={logoutRef}>
                 <button onClick={() => request.get(DocServer.prepend(RouteStore.logout), emptyFunction)}>Log Out</button></div>
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index b0d46953c..d06d1dab6 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -334,7 +334,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
 
     @computed
     get reactTable() {
-        trace();
         let previewWidth = this.previewWidth() + 2 * this.borderWidth + this.DIVIDER_WIDTH + 1;
         return <ReactTable style={{ position: "relative", float: "left", width: `calc(100% - ${previewWidth}px` }} data={this.childDocs} page={0} pageSize={this.childDocs.length} showPagination={false}
             columns={this.tableColumns}
@@ -388,7 +387,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
     }
 
     render() {
-        trace();
         return (
             <div className="collectionSchemaView-container" onPointerDown={this.onPointerDown} onWheel={this.onWheel}
                 onDrop={(e: React.DragEvent) => this.onDrop(e, {})} onContextMenu={this.onContextMenu} ref={this.createTarget}>
@@ -404,6 +402,7 @@ interface CollectionSchemaPreviewProps {
     Document?: Doc;
     DataDocument?: Doc;
     childDocs?: Doc[];
+    fitToBox?: () => number[];
     renderDepth: number;
     width: () => number;
     height: () => number;
@@ -472,6 +471,7 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
                     <DocumentView
                         DataDoc={this.props.Document.layout instanceof Doc ? this.props.Document : this.props.DataDocument}
                         Document={this.props.Document}
+                        fitToBox={this.props.fitToBox}
                         renderDepth={this.props.renderDepth + 1}
                         selectOnLoad={false}
                         addDocument={this.props.addDocument}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index f5dd76b71..ef3868df6 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -1,9 +1,9 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { faAngleRight, faCaretDown, faCaretRight, faCaretSquareDown, faCaretSquareRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons';
+import { faAngleRight, faBell, faCaretDown, faCaretRight, faCaretSquareDown, faCaretSquareRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, DocListCast, HeightSym, WidthSym } from '../../../new_fields/Doc';
+import { Doc, DocListCast, HeightSym, WidthSym, Opt } from '../../../new_fields/Doc';
 import { Id } from '../../../new_fields/FieldSymbols';
 import { List } from '../../../new_fields/List';
 import { Document, listSpec } from '../../../new_fields/Schema';
@@ -50,6 +50,7 @@ export interface TreeViewProps {
 
 library.add(faTrashAlt);
 library.add(faAngleRight);
+library.add(faBell);
 library.add(faCaretDown);
 library.add(faCaretRight);
 library.add(faCaretSquareDown);
@@ -249,6 +250,7 @@ class TreeView extends React.Component<TreeViewProps> {
             }
             ContextMenu.Instance.displayMenu(e.pageX > 156 ? e.pageX - 156 : 0, e.pageY - 15);
             e.stopPropagation();
+            e.preventDefault();
         }
     }
 
@@ -312,6 +314,11 @@ class TreeView extends React.Component<TreeViewProps> {
         return ele;
     }
 
+    fitToBox = () => {
+        let layoutDoc = Doc.expandTemplateLayout(this.props.document, this.props.dataDoc);
+        let bounds = Doc.ComputeContentBounds(layoutDoc);
+        return [(bounds.x + bounds.r) / 2, (bounds.y + bounds.b) / 2, Math.min(this.props.panelHeight() / (bounds.b - bounds.y), this.props.panelWidth() / (bounds.r - bounds.x))];
+    }
     render() {
         let contentElement: (JSX.Element | null) = null;
         let docList = Cast(this.resolvedDataDoc[this._chosenKey], listSpec(Doc));
@@ -333,6 +340,7 @@ class TreeView extends React.Component<TreeViewProps> {
                         Document={layoutDoc}
                         DataDocument={this.resolvedDataDoc}
                         renderDepth={this.props.renderDepth}
+                        fitToBox={this.fitToBox}
                         width={docWidth}
                         height={layoutDoc[HeightSym]}
                         getTransform={this.docTransform}
@@ -456,6 +464,31 @@ export class CollectionTreeView extends CollectionSubView(Document) {
     outerXf = () => Utils.GetScreenTransform(this._mainEle!);
     onTreeDrop = (e: React.DragEvent) => this.onDrop(e, {});
 
+
+    @observable static NotifsCol: Opt<Doc>;
+
+    openNotifsCol = () => {
+        if (CollectionTreeView.NotifsCol && CollectionDockingView.Instance) {
+            CollectionDockingView.Instance.AddRightSplit(CollectionTreeView.NotifsCol, undefined);
+        }
+    }
+    @computed get notifsButton() {
+        const length = CollectionTreeView.NotifsCol ? DocListCast(CollectionTreeView.NotifsCol.data).length : 0;
+        const notifsRef = React.createRef<HTMLDivElement>();
+        const dragNotifs = action(() => CollectionTreeView.NotifsCol!);
+        return <div id="toolbar" key="toolbar">
+            <div ref={notifsRef}>
+                <button className="toolbar-button round-button" title="Notifs"
+                    onClick={this.openNotifsCol} onPointerDown={CollectionTreeView.NotifsCol ? SetupDrag(notifsRef, dragNotifs) : emptyFunction}>
+                    <FontAwesomeIcon icon={faBell} size="sm" />
+                </button>
+                <div className="main-notifs-badge" style={length > 0 ? { "display": "initial" } : { "display": "none" }}>
+                    {length}
+                </div>
+            </div>
+        </div >;
+    }
+
     render() {
         let dropAction = StrCast(this.props.Document.dropAction) as dropActionType;
         let addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before);
@@ -480,6 +513,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                         TreeView.loadId = doc[Id];
                         Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true);
                     }} />
+                {this.props.Document.excludeFromLibrary ? this.notifsButton : (null)}
                 <ul className="no-indent" style={{ width: "max-content" }} >
                     {
                         TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.Document, this.props.DataDoc, this.props.fieldKey, addDoc, this.remove,
diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx
index c1a6ca44e..1984965ba 100644
--- a/src/client/views/collections/CollectionVideoView.tsx
+++ b/src/client/views/collections/CollectionVideoView.tsx
@@ -122,7 +122,6 @@ export class CollectionVideoView extends React.Component<FieldViewProps> {
     }
 
     render() {
-        trace();
         return (
             <CollectionBaseView {...this.props} className="collectionVideoView-cont" onContextMenu={this.onContextMenu}>
                 {this.subView}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 23c0fdd0d..cb7be3f28 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -54,9 +54,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     @computed get nativeHeight() { return this.Document.nativeHeight || 0; }
     public get isAnnotationOverlay() { return this.props.fieldKey === "annotations" || this.props.fieldExt === "annotations"; }
     private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; }
-    private panX = () => this.props.fitToBox ? this.props.fitToBox[0] : this.Document.panX || 0;
-    private panY = () => this.props.fitToBox ? this.props.fitToBox[1] : this.Document.panY || 0;
-    private zoomScaling = () => this.props.fitToBox ? this.props.fitToBox[2] : this.Document.scale || 1;
+    private panX = () => this.props.fitToBox ? this.props.fitToBox()[0] : this.Document.panX || 0;
+    private panY = () => this.props.fitToBox ? this.props.fitToBox()[1] : this.Document.panY || 0;
+    private zoomScaling = () => this.props.fitToBox ? this.props.fitToBox()[2] : this.Document.scale || 1;
     private centeringShiftX = () => !this.nativeWidth ? this._pwidth / 2 : 0;  // shift so pan position is at center of window for non-overlay collections
     private centeringShiftY = () => !this.nativeHeight ? this._pheight / 2 : 0;// shift so pan position is at center of window for non-overlay collections
     private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth + 1, -this.borderWidth + 1).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform());
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3673cb0e2..8b75d0d25 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -71,7 +71,7 @@ export interface DocumentViewProps {
     ContainingCollectionView: Opt<CollectionView | CollectionPDFView | CollectionVideoView>;
     Document: Doc;
     DataDoc?: Doc;
-    fitToBox?: number[];
+    fitToBox?: () => number[];
     addDocument?: (doc: Doc, allowDuplicates?: boolean) => boolean;
     removeDocument?: (doc: Doc) => boolean;
     moveDocument?: (doc: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean;
@@ -573,8 +573,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     @computed get nativeWidth() { return this.Document.nativeWidth || 0; }
     @computed get nativeHeight() { return this.Document.nativeHeight || 0; }
     @computed get contents() {
-        return (
-            <DocumentContentsView {...this.props} isSelected={this.isSelected} select={this.select} selectOnLoad={this.props.selectOnLoad} layoutKey={"layout"} />);
+        return (<DocumentContentsView {...this.props} isSelected={this.isSelected} select={this.select} selectOnLoad={this.props.selectOnLoad} layoutKey={"layout"} />);
     }
 
     render() {
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 3f5a2e744..c5fc6c65a 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -31,7 +31,7 @@ export interface FieldViewProps {
     fieldKey: string;
     fieldExt: string;
     leaveNativeSize?: boolean;
-    fitToBox?: number[];
+    fitToBox?: () => number[];
     ContainingCollectionView: Opt<CollectionView | CollectionPDFView | CollectionVideoView>;
     Document: Doc;
     DataDoc?: Doc;
diff --git a/src/client/views/nodes/LinkEditor.tsx b/src/client/views/nodes/LinkEditor.tsx
index 22da732cf..e6cc50620 100644
--- a/src/client/views/nodes/LinkEditor.tsx
+++ b/src/client/views/nodes/LinkEditor.tsx
@@ -271,7 +271,6 @@ export class LinkGroupEditor extends React.Component<LinkGroupEditorProps> {
                 </>
             );
         }
-        trace();
         return (
             <div className="linkEditor-group">
                 <div className="linkEditor-group-row">
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 5a7bdd24d..129d71b3b 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -101,34 +101,23 @@ export class SearchItem extends React.Component<SearchItemProps> {
     @observable _useIcons = true;
     @observable _displayDim = 50;
 
+    fitToBox = () => {
+        let bounds = Doc.ComputeContentBounds(this.props.doc);
+        return [(bounds.x + bounds.r) / 2, (bounds.y + bounds.b) / 2, Number(SEARCH_THUMBNAIL_SIZE) / Math.max((bounds.b - bounds.y), (bounds.r - bounds.x)), this._displayDim];
+    }
     @computed
     public get DocumentIcon() {
-        let layoutresult = StrCast(this.props.doc.type);
         if (!this._useIcons) {
-            let renderDoc = this.props.doc;
-            let box: number[] = [];
-            if (layoutresult.indexOf(DocTypes.COL) !== -1) {
-                renderDoc = Doc.MakeDelegate(renderDoc);
-                let bounds = DocListCast(renderDoc.data).reduce((bounds, doc) => {
-                    var [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)];
-                    let [bptX, bptY] = [sptX + doc[WidthSym](), sptY + doc[HeightSym]()];
-                    return {
-                        x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y),
-                        r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b)
-                    };
-                }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE });
-                box = [(bounds.x + bounds.r) / 2, (bounds.y + bounds.b) / 2, Number(SEARCH_THUMBNAIL_SIZE) / (bounds.r - bounds.x), this._displayDim];
-            }
             let returnXDimension = () => this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE);
             let returnYDimension = () => this._displayDim;
-            let scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension());
+            let scale = () => returnXDimension() / NumCast(this.props.doc.nativeWidth, returnXDimension());
             return <div
                 onPointerDown={action(() => { this._useIcons = !this._useIcons; this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE); })}
                 onPointerEnter={action(() => this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE))}
                 onPointerLeave={action(() => this._displayDim = 50)} >
                 <DocumentView
-                    fitToBox={box}
-                    Document={renderDoc}
+                    fitToBox={StrCast(this.props.doc.type).indexOf(DocTypes.COL) !== -1 ? this.fitToBox : undefined}
+                    Document={this.props.doc}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
                     ScreenToLocalTransform={Transform.Identity}
@@ -149,6 +138,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
             </div>;
         }
 
+        let layoutresult = StrCast(this.props.doc.type);
         let button = layoutresult.indexOf(DocTypes.PDF) !== -1 ? faFilePdf :
             layoutresult.indexOf(DocTypes.IMG) !== -1 ? faImage :
                 layoutresult.indexOf(DocTypes.TEXT) !== -1 ? faStickyNote :
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 734a90731..29d35e19f 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -249,6 +249,18 @@ export namespace Doc {
         return true;
     }
 
+    export function ComputeContentBounds(doc: Doc) {
+        let bounds = DocListCast(doc.data).reduce((bounds, doc) => {
+            var [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)];
+            let [bptX, bptY] = [sptX + doc[WidthSym](), sptY + doc[HeightSym]()];
+            return {
+                x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y),
+                r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b)
+            };
+        }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE });
+        return bounds;
+    }
+
     //
     // Resolves a reference to a field by returning 'doc' if o field extension is specified,
     // otherwise, it returns the extension document stored in doc.<fieldKey>_ext.
-- 
cgit v1.2.3-70-g09d2


From d479f5e6bcdb7d1a0edb2f8cf366549abe2a910b Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 4 Jul 2019 14:08:00 -0400
Subject: added text font color setting.   adding interactive border radius.
 moved main toolbar.

---
 src/client/documents/Documents.ts                  |  4 +--
 src/client/util/DragManager.ts                     |  1 +
 src/client/util/RichTextSchema.tsx                 | 11 ++++++++
 src/client/util/TooltipTextMenu.tsx                |  3 +-
 src/client/views/DocumentDecorations.scss          | 22 +++++++++++++++
 src/client/views/DocumentDecorations.tsx           | 32 ++++++++++++++++++++++
 src/client/views/InkingControl.tsx                 |  3 ++
 src/client/views/Main.scss                         |  2 +-
 src/client/views/MainOverlayTextBox.tsx            |  5 ++++
 src/client/views/MainView.tsx                      |  2 +-
 .../collections/collectionFreeForm/MarqueeView.tsx | 16 ++++-------
 .../views/nodes/CollectionFreeFormDocumentView.tsx | 15 ++++++----
 src/client/views/nodes/DocumentView.tsx            |  4 +--
 src/client/views/nodes/FormattedTextBox.tsx        | 11 +++++++-
 14 files changed, 106 insertions(+), 25 deletions(-)

(limited to 'src/client/views/MainView.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 7a976e7d7..2bddf053a 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -77,7 +77,7 @@ export interface DocumentOptions {
     backgroundLayout?: string;
     curPage?: number;
     documentText?: string;
-    borderRounding?: number;
+    borderRounding?: string;
     schemaColumns?: List<string>;
     dockingConfig?: string;
     dbDoc?: Doc;
@@ -93,7 +93,7 @@ export namespace DocUtils {
         if (target === CurrentUserUtils.UserDocument) return;
 
         UndoManager.RunInBatch(() => {
-            let linkDoc = Docs.TextDocument({ width: 100, height: 30, borderRounding: -1 });
+            let linkDoc = Docs.TextDocument({ width: 100, height: 30, borderRounding: "100%" });
             linkDoc.type = DocTypes.LINK;
             let linkDocProto = Doc.GetProto(linkDoc);
 
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 7dc48fb78..d4b1bc8f4 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -315,6 +315,7 @@ export namespace DragManager {
             scaleYs.push(scaleY);
             let dragElement = ele.cloneNode(true) as HTMLElement;
             dragElement.style.opacity = "0.7";
+            dragElement.style.borderRadius = getComputedStyle(ele).borderRadius;
             dragElement.style.position = "absolute";
             dragElement.style.margin = "0";
             dragElement.style.top = "0";
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 63c879d67..2a57180d3 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -348,6 +348,17 @@ export const marks: { [index: string]: MarkSpec } = {
         }]
     },
 
+    pFontColor: {
+        attrs: {
+            color: { default: "yellow" }
+        },
+        parseDOM: [{ style: 'background: #d9dbdd' }],
+        toDOM: (node) => {
+            return ['span', {
+                style: `color: ${node.attrs.color}`
+            }];
+        }
+    },
 
     /** FONT SIZES */
     pFontSize: {
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 9f8d0b2f6..e3e26d1f4 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -111,7 +111,8 @@ export class TooltipTextMenu {
         this.fontSizeToNum.set(schema.marks.p32, 32);
         this.fontSizeToNum.set(schema.marks.p48, 48);
         this.fontSizeToNum.set(schema.marks.p72, 72);
-        //this.fontSizeToNum.set(schema.marks.pFontSize,schema.marks.pFontSize.)
+        this.fontSizeToNum.set(schema.marks.pFontSize, 10);
+        this.fontSizeToNum.set(schema.marks.pFontSize, 10);
         this.fontSizes = Array.from(this.fontSizeToNum.keys());
 
         //list types
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index ba9f32d7d..2d430512b 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -26,6 +26,14 @@ $linkGap : 3px;
         opacity: 0.8;
     }
 
+    .documentDecorations-radius {
+        pointer-events: auto;
+        background: black;
+        opacity: 0.8;
+        transform: translate(10px, 10px);
+        grid-row: 4;
+    }
+
     #documentDecorations-topLeftResizer,
     #documentDecorations-leftResizer,
     #documentDecorations-bottomLeftResizer {
@@ -44,11 +52,25 @@ $linkGap : 3px;
         grid-column-start: 5;
         grid-column-end: 7;
     }
+    
+    #documentDecorations-borderRadius{
+        grid-column-start: 5;
+        grid-column-end: 7;
+        border-radius: 100%;
+        .borderRadiusTooltip{
+            width:10px;
+            height:10px;
+            position:absolute;
+        }
+    }
 
     #documentDecorations-topLeftResizer,
     #documentDecorations-bottomRightResizer {
         cursor: nwse-resize;
     }
+    #documentDecorations-bottomRightResizer {
+        grid-row:4;
+    }
 
     #documentDecorations-topRightResizer,
     #documentDecorations-bottomLeftResizer {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 3df520428..c7990647a 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -341,6 +341,37 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         iconDoc.y = where[1] + NumCast(selView.props.Document.y);
     }
 
+    _radiusDown = [0, 0];
+    @action
+    onRadiusDown = (e: React.PointerEvent): void => {
+        e.stopPropagation();
+        if (e.button === 0) {
+            this._radiusDown = [e.clientX, e.clientY];
+            this._isPointerDown = true;
+            this._resizeUndo = UndoManager.StartBatch("DocDecs set radius");
+            document.removeEventListener("pointermove", this.onRadiusMove);
+            document.removeEventListener("pointerup", this.onRadiusUp);
+            document.addEventListener("pointermove", this.onRadiusMove);
+            document.addEventListener("pointerup", this.onRadiusUp);
+        }
+    }
+
+    onRadiusMove = (e: PointerEvent): void => {
+        let dist = Math.sqrt((e.clientX - this._radiusDown[0]) * (e.clientX - this._radiusDown[0]) + (e.clientY - this._radiusDown[1]) * (e.clientY - this._radiusDown[1]));
+        SelectionManager.SelectedDocuments().map(dv => Doc.GetProto(dv.props.Document).borderRounding = `${Math.min(100, dist)}%`);
+        e.stopPropagation();
+        e.preventDefault();
+    }
+
+    onRadiusUp = (e: PointerEvent): void => {
+        e.stopPropagation();
+        e.preventDefault();
+        this._isPointerDown = false;
+        this._resizeUndo && this._resizeUndo.end();
+        document.removeEventListener("pointermove", this.onRadiusMove);
+        document.removeEventListener("pointerup", this.onRadiusUp);
+    }
+
     @action
     onPointerDown = (e: React.PointerEvent): void => {
         e.stopPropagation();
@@ -705,6 +736,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 <div id="documentDecorations-bottomLeftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
                 <div id="documentDecorations-bottomResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
                 <div id="documentDecorations-bottomRightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+                <div id="documentDecorations-borderRadius" className="documentDecorations-radius" onPointerDown={this.onRadiusDown} onContextMenu={(e) => e.preventDefault()}><span className="borderRadiusTooltip" title="Drag Corner Radius"></span></div>
                 <div className="link-button-container">
                     <div className="linkButtonWrapper">
                         <div title="View Links" className="linkFlyout" ref={this._linkButton}> {linkButton}  </div>
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index 0461d7299..c7f7bdb66 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -10,6 +10,8 @@ import { InkTool } from "../../new_fields/InkField";
 import { Doc } from "../../new_fields/Doc";
 import { undoBatch, UndoManager } from "../util/UndoManager";
 import { StrCast } from "../../new_fields/Types";
+import { FormattedTextBox } from "./nodes/FormattedTextBox";
+import { MainOverlayTextBox } from "./MainOverlayTextBox";
 
 library.add(faPen, faHighlighter, faEraser, faBan);
 
@@ -42,6 +44,7 @@ export class InkingControl extends React.Component {
     switchColor = action((color: ColorResult): void => {
         this._selectedColor = color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff");
         if (InkingControl.Instance.selectedTool === InkTool.None) {
+            if (MainOverlayTextBox.Instance.SetColor(color.hex)) return;
             let selected = SelectionManager.SelectedDocuments();
             let oldColors = selected.map(view => {
                 let targetDoc = view.props.Document.isTemplate ? view.props.Document : Doc.GetProto(view.props.Document);
diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss
index 44c1cb9fc..b85a8040a 100644
--- a/src/client/views/Main.scss
+++ b/src/client/views/Main.scss
@@ -144,7 +144,7 @@ button:hover {
 #add-nodes-menu {
     position: absolute;
     bottom: 22px;
-    left: 24px;
+    left: 250px;
 
     > label {
         background: $dark-color;
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 7d15702a2..d8aaea259 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -36,6 +36,11 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
         this._outerdiv && this._tooltip && !this._outerdiv.contains(this._tooltip) && this._outerdiv.appendChild(this._tooltip);
     }
 
+    public SetColor(color: string) {
+        return this._textBox && this._textBox.setFontColor(color);
+    }
+
+
     constructor(props: MainOverlayTextBoxProps) {
         super(props);
         this._textProxyDiv = React.createRef();
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 1542fedef..61ccf4c1d 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -354,7 +354,7 @@ export class MainView extends React.Component {
             [React.createRef<HTMLDivElement>(), "tree", "Add Tree", addTreeNode],
         ];
 
-        return < div id="add-nodes-menu" >
+        return < div id="add-nodes-menu" style={{ left: this.flyoutWidth + 5 }} >
             <input type="checkbox" id="add-menu-toggle" ref={this.addMenuToggle} />
             <label htmlFor="add-menu-toggle" title="Add Node"><p>+</p></label>
 
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 31c0fe499..4850c6218 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -44,14 +44,12 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
     _commandExecuted = false;
 
     @action
-    cleanupInteractions = (all: boolean = false, rem_keydown: boolean = true) => {
+    cleanupInteractions = (all: boolean = false) => {
         if (all) {
             document.removeEventListener("pointerup", this.onPointerUp, true);
             document.removeEventListener("pointermove", this.onPointerMove, true);
         }
-        if (rem_keydown) {
-            document.removeEventListener("keydown", this.marqueeCommand, true);
-        }
+        document.removeEventListener("keydown", this.marqueeCommand, true);
         this._visible = false;
     }
 
@@ -191,12 +189,9 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
                 SelectionManager.DeselectAll(mselect.length ? undefined : this.props.container.props.Document);
             }
             this.props.selectDocuments(mselect.length ? mselect : [this.props.container.props.Document]);
-            mselect.length ? this.cleanupInteractions(true, false) : this.cleanupInteractions(true);
-        }
-        else {
-            //console.log("invisible");
-            this.cleanupInteractions(true);
         }
+        //console.log("invisible");
+        this.cleanupInteractions(true);
 
         if (e.altKey) {
             e.preventDefault();
@@ -266,13 +261,12 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
             }
             let ink = Cast(this.props.container.props.Document.ink, InkField);
             let inkData = ink ? ink.inkData : undefined;
-            let zoomBasis = NumCast(this.props.container.props.Document.scale, 1);
             let newCollection = Docs.FreeformDocument(selected, {
                 x: bounds.left,
                 y: bounds.top,
                 panX: 0,
                 panY: 0,
-                borderRounding: e.key === "e" ? -1 : undefined,
+                borderRounding: e.key === "e" ? "100%" : undefined,
                 backgroundColor: this.props.container.isAnnotationOverlay ? undefined : "white",
                 width: bounds.width,
                 height: bounds.height,
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 30cf74f3e..1c00687ed 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -70,11 +70,14 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     }
 
     borderRounding = () => {
-        let br = NumCast(this.props.Document.borderRounding);
-        return br >= 0 ? br :
-            NumCast(this.props.Document.nativeWidth) === 0 ?
-                Math.min(this.props.PanelWidth(), this.props.PanelHeight())
-                : Math.min(this.Document.nativeWidth || 0, this.Document.nativeHeight || 0);
+        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.props.Document.nativeWidth), NumCast(this.props.Document.nativeHeight));
+            let minDim = percent * (nativeDim ? nativeDim : Math.min(this.props.PanelWidth(), this.props.PanelHeight()));
+            return minDim;
+        }
+        return undefined;
     }
 
     render() {
@@ -84,7 +87,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                     transformOrigin: "left top",
                     position: "absolute",
                     backgroundColor: "transparent",
-                    borderRadius: `${this.borderRounding()}px`,
+                    borderRadius: this.borderRounding(),
                     transform: this.transform,
                     transition: StrCast(this.props.Document.transition),
                     width: this.width,
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f751a45fe..a84cac37f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -589,9 +589,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 style={{
                     outlineColor: "maroon",
                     outlineStyle: "dashed",
-                    outlineWidth: BoolCast(this.props.Document.libraryBrush) && !NumCast(this.props.Document.borderRounding) ?
+                    outlineWidth: BoolCast(this.props.Document.libraryBrush) && !StrCast(this.props.Document.borderRounding) ?
                         `${this.props.ScreenToLocalTransform().Scale}px` : "0px",
-                    border: BoolCast(this.props.Document.libraryBrush) && NumCast(this.props.Document.borderRounding) ?
+                    border: BoolCast(this.props.Document.libraryBrush) && StrCast(this.props.Document.borderRounding) ?
                         `dashed maroon ${this.props.ScreenToLocalTransform().Scale}px` : undefined,
                     borderRadius: "inherit",
                     background: backgroundColor,
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 1eeb04755..bf6f4c764 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -97,6 +97,15 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         return "";
     }
 
+    @undoBatch
+    public setFontColor(color: string) {
+        if (this._editorView!.state.selection.from === this._editorView!.state.selection.to) return false;
+        let colorMark = this._editorView!.state.schema.mark(this._editorView!.state.schema.marks.pFontColor, { color: color });
+        this._editorView!.dispatch(this._editorView!.state.tr.addMark(this._editorView!.state.selection.from,
+            this._editorView!.state.selection.to, colorMark));
+        return true;
+    }
+
     constructor(props: FieldViewProps) {
         super(props);
         if (this.props.outer_div) {
@@ -418,7 +427,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
     render() {
         let style = this.props.isOverlay ? "scroll" : "hidden";
-        let rounded = NumCast(this.props.Document.borderRounding) < 0 ? "-rounded" : "";
+        let rounded = StrCast(this.props.Document.borderRounding) === "100%" ? "-rounded" : "";
         let interactive = InkingControl.Instance.selectedTool ? "" : "interactive";
         return (
             <div className={`formattedTextBox-cont-${style}`} ref={this._ref}
-- 
cgit v1.2.3-70-g09d2


From 8b9fa667816378cc6cae2977f1c2d80c204b28d0 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Fri, 5 Jul 2019 14:45:15 -0400
Subject: added more options to sidebar

---
 src/client/views/Main.scss                         | 18 ++++++++++++++
 src/client/views/MainView.tsx                      | 28 ++++++++++++++++++----
 .../views/collections/CollectionDockingView.tsx    |  4 ++++
 .../views/collections/CollectionTreeView.tsx       |  7 ++++--
 src/new_fields/Doc.ts                              | 11 +++++----
 .../authentication/models/current_user_utils.ts    | 10 ++++++++
 6 files changed, 67 insertions(+), 11 deletions(-)

(limited to 'src/client/views/MainView.tsx')

diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss
index b85a8040a..f52e3b658 100644
--- a/src/client/views/Main.scss
+++ b/src/client/views/Main.scss
@@ -230,6 +230,8 @@ ul#add-options-list {
 .mainView-libraryFlyout {
     height: 100%;
     position: absolute;
+    display: flex;
+    flex-direction:column;
 }
 
 .mainView-libraryHandle {
@@ -241,4 +243,20 @@ ul#add-options-list {
     position: absolute;
     z-index: 1;
     background: gray;
+}
+
+.mainView-workspace {
+    height:200px;
+    position:relative;
+    display:flex;
+}
+.mainView-library {
+    height:75%;
+    position:relative;
+    display:flex;
+}
+.mainView-recentlyClosed {
+    height:25%;
+    position:relative;
+    display:flex;
 }
\ No newline at end of file
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 61ccf4c1d..92468e3fd 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -8,12 +8,12 @@ import * as React from 'react';
 import { SketchPicker } from 'react-color';
 import Measure from 'react-measure';
 import * as request from 'request';
-import { Doc, DocListCast, Opt } from '../../new_fields/Doc';
+import { Doc, DocListCast, Opt, HeightSym } from '../../new_fields/Doc';
 import { Id } from '../../new_fields/FieldSymbols';
 import { InkTool } from '../../new_fields/InkField';
 import { List } from '../../new_fields/List';
 import { listSpec } from '../../new_fields/Schema';
-import { Cast, FieldValue } from '../../new_fields/Types';
+import { Cast, FieldValue, NumCast } from '../../new_fields/Types';
 import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
 import { RouteStore } from '../../server/RouteStore';
 import { emptyFunction, returnOne, returnTrue } from '../../Utils';
@@ -163,7 +163,9 @@ export class MainView extends React.Component {
 
     @action
     createNewWorkspace = async (id?: string) => {
-        const list = Cast(CurrentUserUtils.UserDocument.data, listSpec(Doc));
+        let workspaces = Cast(CurrentUserUtils.UserDocument.workspaces, Doc);
+        if (!(workspaces instanceof Doc)) return;
+        const list = Cast((CurrentUserUtils.UserDocument.workspaces as Doc).data, listSpec(Doc));
         if (list) {
             let freeformDoc = Docs.FreeformDocument([], { x: 0, y: 400, width: this.pwidth * .7, height: this.pheight, title: `WS collection ${list.length + 1}` });
             var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(freeformDoc, freeformDoc, 600)] }] };
@@ -285,8 +287,24 @@ export class MainView extends React.Component {
     };
     @computed
     get flyout() {
+        let sidebar = CurrentUserUtils.UserDocument.sidebar;
+        let workspaces = CurrentUserUtils.UserDocument.workspaces;
+        let recent = CurrentUserUtils.UserDocument.recentlyClosed;
+        if (!(sidebar instanceof Doc)) return (null);
+        if (!(recent instanceof Doc)) return (null);
+        if (!(workspaces instanceof Doc)) return (null);
+        let workspacesDoc = workspaces as Doc;
+        let sidebarDoc = sidebar as Doc;
+        let recentDoc = recent as Doc;
+        let library = CurrentUserUtils.UserDocument;
+        let gridGap = NumCast(sidebar.gridGap, 10);
+        let yMargin = NumCast(sidebar.yMargin, 2 * gridGap);
+        let libraryHeight = this.getPHeight() - workspacesDoc[HeightSym]() - recentDoc[HeightSym]() - 2 * gridGap - 2 * yMargin;
+        if (library[HeightSym]() != libraryHeight) {
+            setTimeout(() => CurrentUserUtils.UserDocument.height = libraryHeight, 0);
+        }
         return <DocumentView
-            Document={CurrentUserUtils.UserDocument}
+            Document={sidebarDoc}
             DataDoc={undefined}
             addDocument={undefined}
             addDocTab={this.addDocTabFunc}
@@ -304,7 +322,7 @@ export class MainView extends React.Component {
             ContainingCollectionView={undefined}
             zoomToScale={emptyFunction}
             getScale={returnOne}>
-        </DocumentView>;
+        </DocumentView>
     }
     @computed
     get mainContent() {
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index c5f8fb728..e0270fab3 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -27,6 +27,7 @@ import { MainView } from '../MainView';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faFile } from '@fortawesome/free-solid-svg-icons';
+import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
 library.add(faFile);
 
 @observer
@@ -416,6 +417,9 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
                 if (doc instanceof Doc) {
                     let theDoc = doc;
                     CollectionDockingView.Instance._removedDocs.push(theDoc);
+                    if (CurrentUserUtils.UserDocument.recentlyClosed instanceof Doc) {
+                        Doc.AddDocToList(CurrentUserUtils.UserDocument.recentlyClosed, "data", doc, undefined, true, true);
+                    }
                     SelectionManager.DeselectAll();
                 }
                 tab.contentItem.remove();
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 93a1ec1eb..c83a2d2c6 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -471,9 +471,12 @@ export class CollectionTreeView extends CollectionSubView(Document) {
     }
     onContextMenu = (e: React.MouseEvent): void => {
         // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout
-        if (!e.isPropagationStopped() && this.props.Document.excludeFromLibrary) { // excludeFromLibrary means this is the user document
+        if (!e.isPropagationStopped() && this.props.Document.workspaceLibrary) { // excludeFromLibrary means this is the user document
             ContextMenu.Instance.addItem({ description: "Create Workspace", event: undoBatch(() => MainView.Instance.createNewWorkspace()) });
             ContextMenu.Instance.addItem({ description: "Delete Workspace", event: undoBatch(() => this.remove(this.props.Document)) });
+            e.stopPropagation();
+            e.preventDefault();
+            ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
         }
     }
 
@@ -531,7 +534,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                         TreeView.loadId = doc[Id];
                         Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true);
                     }} />
-                {this.props.Document.excludeFromLibrary ? this.notifsButton : (null)}
+                {this.props.Document.workspaceLibrary ? this.notifsButton : (null)}
                 <ul className="no-indent" style={{ width: "max-content" }} >
                     {
                         TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.Document, this.props.DataDoc, this.props.fieldKey, addDoc, this.remove,
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index c361e3032..092205f52 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -241,12 +241,15 @@ export namespace Doc {
         return Array.from(results);
     }
 
-    export function AddDocToList(target: Doc, key: string, doc: Doc, relativeTo?: Doc, before?: boolean) {
+    export function AddDocToList(target: Doc, key: string, doc: Doc, relativeTo?: Doc, before?: boolean, first?: boolean) {
         let list = Cast(target[key], listSpec(Doc));
         if (list) {
-            let ind = relativeTo ? list.indexOf(relativeTo) : -1;
-            if (ind === -1) list.push(doc);
-            else list.splice(before ? ind : ind + 1, 0, doc);
+            if (first) list.splice(0, 0, doc);
+            else {
+                let ind = relativeTo ? list.indexOf(relativeTo) : -1;
+                if (ind === -1) list.push(doc);
+                else list.splice(before ? ind : ind + 1, 0, doc);
+            }
         }
         return true;
     }
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 816c5f269..3134ecaff 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -31,6 +31,16 @@ export class CurrentUserUtils {
         doc.viewType = CollectionViewType.Tree;
         doc.dropAction = "alias";
         doc.layout = CollectionView.LayoutString();
+        doc.workspaces = Docs.TreeDocument([], { title: "Workspaces", height: 100 });
+        (doc.workspaces as Doc).excludeFromLibrary = true;
+        (doc.workspaces as Doc).workspaceLibrary = true;
+        doc.recentlyClosed = Docs.TreeDocument([], { title: "Recently Closed", height: 75 });
+        (doc.workspaces as Doc).excludeFromLibrary = true;
+        doc.sidebar = Docs.StackingDocument([doc.workspaces as Doc, doc, doc.recentlyClosed as Doc], { title: "Sidebar" });
+        (doc.sidebar as Doc).excludeFromLibrary = true;
+        (doc.sidebar as Doc).gridGap = 5;
+        (doc.sidebar as Doc).xMargin = 5;
+        (doc.sidebar as Doc).yMargin = 5;
         doc.title = this.email;
         doc.data = new List<Doc>();
         doc.excludeFromLibrary = true;
-- 
cgit v1.2.3-70-g09d2


From 6df84a8246826d211f304ac6aecf76b8635bd83f Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Fri, 5 Jul 2019 16:36:26 -0400
Subject: fix

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

(limited to 'src/client/views/MainView.tsx')

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 92468e3fd..49dc4a2a1 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -300,7 +300,7 @@ export class MainView extends React.Component {
         let gridGap = NumCast(sidebar.gridGap, 10);
         let yMargin = NumCast(sidebar.yMargin, 2 * gridGap);
         let libraryHeight = this.getPHeight() - workspacesDoc[HeightSym]() - recentDoc[HeightSym]() - 2 * gridGap - 2 * yMargin;
-        if (library[HeightSym]() != libraryHeight) {
+        if (Math.abs(library[HeightSym]() - libraryHeight) > 5) {
             setTimeout(() => CurrentUserUtils.UserDocument.height = libraryHeight, 0);
         }
         return <DocumentView
-- 
cgit v1.2.3-70-g09d2


From b8e41f32eba62a3e569e82e2908f4ff0c1e29f6c Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Fri, 5 Jul 2019 16:39:38 -0400
Subject: fix 2

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

(limited to 'src/client/views/MainView.tsx')

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 49dc4a2a1..d709a1a5b 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -300,7 +300,7 @@ export class MainView extends React.Component {
         let gridGap = NumCast(sidebar.gridGap, 10);
         let yMargin = NumCast(sidebar.yMargin, 2 * gridGap);
         let libraryHeight = this.getPHeight() - workspacesDoc[HeightSym]() - recentDoc[HeightSym]() - 2 * gridGap - 2 * yMargin;
-        if (Math.abs(library[HeightSym]() - libraryHeight) > 5) {
+        if (Math.abs(library[HeightSym]() - libraryHeight) > 25) {
             setTimeout(() => CurrentUserUtils.UserDocument.height = libraryHeight, 0);
         }
         return <DocumentView
-- 
cgit v1.2.3-70-g09d2


From 8a902049db8378e13a28b19b1ad34a36882fbcb1 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Fri, 5 Jul 2019 19:32:44 -0400
Subject: Added garbage collector

---
 src/client/views/MainView.tsx |  6 ++---
 src/server/GarbageColletor.ts | 51 +++++++++++++++++++++++++++++++++++++++++++
 src/server/database.ts        | 14 ++++++++----
 3 files changed, 64 insertions(+), 7 deletions(-)
 create mode 100644 src/server/GarbageColletor.ts

(limited to 'src/client/views/MainView.tsx')

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index d709a1a5b..82b17f142 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -293,9 +293,9 @@ export class MainView extends React.Component {
         if (!(sidebar instanceof Doc)) return (null);
         if (!(recent instanceof Doc)) return (null);
         if (!(workspaces instanceof Doc)) return (null);
-        let workspacesDoc = workspaces as Doc;
-        let sidebarDoc = sidebar as Doc;
-        let recentDoc = recent as Doc;
+        let workspacesDoc = workspaces;
+        let sidebarDoc = sidebar;
+        let recentDoc = recent;
         let library = CurrentUserUtils.UserDocument;
         let gridGap = NumCast(sidebar.gridGap, 10);
         let yMargin = NumCast(sidebar.yMargin, 2 * gridGap);
diff --git a/src/server/GarbageColletor.ts b/src/server/GarbageColletor.ts
new file mode 100644
index 000000000..f26b0cec6
--- /dev/null
+++ b/src/server/GarbageColletor.ts
@@ -0,0 +1,51 @@
+import { Database } from './database';
+
+function addDoc(doc: any, ids: string[]) {
+    for (const key in doc) {
+        if (!doc.hasOwnProperty(key)) {
+            continue;
+        }
+        const field = doc[key];
+        if (!(field instanceof Object)) {
+            continue;
+        }
+        if (field.__type === "proxy") {
+            ids.push(field.fieldId);
+        } else if (field.__type === "list") {
+            addDoc(field.fields, ids);
+        }
+    }
+}
+
+async function GarbageCollect() {
+    // await new Promise(res => setTimeout(res, 3000));
+    const cursor = await Database.Instance.query({}, 'users');
+    const users = await cursor.toArray();
+    const ids: string[] = users.map(user => user.userDocumentId);
+    const visited = new Set<string>();
+
+    while (ids.length) {
+        const id = ids.pop()!;
+        if (visited.has(id)) continue;
+        const doc = await new Promise<{ [key: string]: any }>(res => Database.Instance.getDocument(id, res, "newDocuments"));
+        if (doc === undefined) {
+            console.log(`Couldn't find field with Id ${id}`);
+            continue;
+        }
+        visited.add(id);
+        addDoc(doc.fields, ids);
+        console.log(`To Go: ${ids.length}, visited: ${visited.size}`);
+    }
+
+    console.log(`Done: ${visited.size}`);
+
+    cursor.close();
+
+    const toDeleteCursor = await Database.Instance.query({ _id: { $nin: Array.from(visited) } });
+    const toDelete = (await toDeleteCursor.toArray()).map(doc => doc._id);
+    toDeleteCursor.close();
+    const result = await Database.Instance.delete({ _id: { $in: toDelete } }, "newDocuments");
+    console.log(`${result.deletedCount} documents deleted`);
+}
+
+GarbageCollect();
diff --git a/src/server/database.ts b/src/server/database.ts
index d240bd909..a17447629 100644
--- a/src/server/database.ts
+++ b/src/server/database.ts
@@ -41,11 +41,17 @@ export class Database {
         }
     }
 
-    public delete(id: string, collectionName = Database.DocumentsCollection) {
+    public delete(query: any, collectionName?: string): Promise<mongodb.DeleteWriteOpResultObject>;
+    public delete(id: string, collectionName?: string): Promise<mongodb.DeleteWriteOpResultObject>;
+    public delete(id: any, collectionName = Database.DocumentsCollection) {
+        if (typeof id === "string") {
+            id = { _id: id };
+        }
         if (this.db) {
-            this.db.collection(collectionName).remove({ id: id });
+            const db = this.db;
+            return new Promise(res => db.collection(collectionName).deleteMany(id, (err, result) => res(result)));
         } else {
-            this.onConnect.push(() => this.delete(id, collectionName));
+            return new Promise(res => this.onConnect.push(() => res(this.delete(id, collectionName))));
         }
     }
 
@@ -125,7 +131,7 @@ export class Database {
             return Promise.resolve<mongodb.Cursor>(this.db.collection(collectionName).find(query));
         } else {
             return new Promise<mongodb.Cursor>(res => {
-                this.onConnect.push(() => res(this.query(query)));
+                this.onConnect.push(() => res(this.query(query, collectionName)));
             });
         }
     }
-- 
cgit v1.2.3-70-g09d2


From 8780f8652ce2cfdf37dd89be050123da3dc4eac4 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 6 Jul 2019 00:30:52 -0400
Subject: don't understand what could be happening..

---
 src/client/views/DocumentDecorations.tsx           |  6 ++--
 src/client/views/MainView.tsx                      | 39 ++++++++++++++++------
 .../views/collections/CollectionStackingView.tsx   |  8 ++---
 src/client/views/nodes/DocumentView.tsx            |  4 +--
 src/new_fields/util.ts                             |  2 +-
 .../authentication/models/current_user_utils.ts    | 10 +++++-
 6 files changed, 48 insertions(+), 21 deletions(-)

(limited to 'src/client/views/MainView.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index c7990647a..e565566c7 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -536,8 +536,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 let scale = element.props.ScreenToLocalTransform().Scale * element.props.ContentScaling();
                 let actualdW = Math.max(width + (dW * scale), 20);
                 let actualdH = Math.max(height + (dH * scale), 20);
-                doc.x = (doc.x || 0) + dX * (actualdW - width);
-                doc.y = (doc.y || 0) + dY * (actualdH - height);
+                // doc.x = (doc.x || 0) + dX * (actualdW - width);
+                // doc.y = (doc.y || 0) + dY * (actualdH - height);
                 let proto = Doc.GetProto(element.props.Document);
                 let fixedAspect = e.ctrlKey || (!BoolCast(proto.ignoreAspect, false) && nwidth && nheight);
                 if (fixedAspect && (!nwidth || !nheight)) {
@@ -567,7 +567,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 } else {
                     dW && (doc.width = actualdW);
                     dH && (doc.height = actualdH);
-                    Doc.SetInPlace(element.props.Document, "autoHeight", undefined, true);
+                    //Doc.SetInPlace(element.props.Document, "autoHeight", undefined, true);
                 }
             }
         });
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 82b17f142..f9a5b2bb7 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,7 +1,7 @@
 import { IconName, library } from '@fortawesome/fontawesome-svg-core';
 import { faArrowDown, faArrowUp, faBell, faCheck, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, configure, observable, runInAction } from 'mobx';
+import { action, computed, configure, observable, runInAction, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import "normalize.css";
 import * as React from 'react';
@@ -72,6 +72,31 @@ export class MainView extends React.Component {
 
         window.removeEventListener("pointerup", this.pointerUp);
         window.addEventListener("pointerup", this.pointerUp);
+
+        reaction(() => {
+            let workspaces = CurrentUserUtils.UserDocument.workspaces;
+            let recent = CurrentUserUtils.UserDocument.recentlyClosed;
+            let fakeLibrary = CurrentUserUtils.UserDocument.fakeLibrary;
+            if (!(recent instanceof Doc)) return 0;
+            if (!(workspaces instanceof Doc)) return 0;
+            if (!(fakeLibrary instanceof Doc)) return 0;
+            let workspacesDoc = workspaces;
+            let recentDoc = recent;
+            let fakeLibraryDoc = fakeLibrary;
+            // console.log("pheight = " + this.getPHeight() + " " + workspacesDoc[HeightSym]() + " " + recentDoc[HeightSym]());
+            let libraryHeight = this.getPHeight() - workspacesDoc[HeightSym]() - recentDoc[HeightSym]();
+            return libraryHeight;
+        }, (libraryHeight: number) => {
+            let fakeLibrary = CurrentUserUtils.UserDocument.fakeLibrary;
+            let cuser: Doc = fakeLibrary as Doc;//CurrentUserUtils.UserDocument;
+            console.log("BEFORE:" + cuser.title + ".height =" + cuser[HeightSym]() + "& .plight = " + cuser.plight);
+            if (libraryHeight && Math.abs(cuser[HeightSym]() - libraryHeight) > 5) {
+                console.log("ASSIGN to height & plight:" + libraryHeight);
+                cuser.height = libraryHeight;
+                cuser.plight = libraryHeight;
+            }
+            console.log("AFTER:" + cuser.title + ".height =" + cuser[HeightSym]() + "& .plight= " + cuser.plight);
+        }, { fireImmediately: true });
     }
 
     pointerDown = (e: PointerEvent) => this.isPointerDown = true;
@@ -285,24 +310,18 @@ export class MainView extends React.Component {
             CollectionDockingView.Instance.AddRightSplit(doc, undefined);
         }
     };
+    computing = false;
     @computed
     get flyout() {
         let sidebar = CurrentUserUtils.UserDocument.sidebar;
         let workspaces = CurrentUserUtils.UserDocument.workspaces;
         let recent = CurrentUserUtils.UserDocument.recentlyClosed;
+        let fakeLibrary = CurrentUserUtils.UserDocument.fakeLibrary;
         if (!(sidebar instanceof Doc)) return (null);
         if (!(recent instanceof Doc)) return (null);
         if (!(workspaces instanceof Doc)) return (null);
-        let workspacesDoc = workspaces;
+        if (!(fakeLibrary instanceof Doc)) return (null);
         let sidebarDoc = sidebar;
-        let recentDoc = recent;
-        let library = CurrentUserUtils.UserDocument;
-        let gridGap = NumCast(sidebar.gridGap, 10);
-        let yMargin = NumCast(sidebar.yMargin, 2 * gridGap);
-        let libraryHeight = this.getPHeight() - workspacesDoc[HeightSym]() - recentDoc[HeightSym]() - 2 * gridGap - 2 * yMargin;
-        if (Math.abs(library[HeightSym]() - libraryHeight) > 25) {
-            setTimeout(() => CurrentUserUtils.UserDocument.height = libraryHeight, 0);
-        }
         return <DocumentView
             Document={sidebarDoc}
             DataDoc={undefined}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 6b4eddec9..ffd05b52d 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -10,7 +10,6 @@ import { ContextMenu } from "../ContextMenu";
 import { CollectionSchemaPreview } from "./CollectionSchemaView";
 import "./CollectionStackingView.scss";
 import { CollectionSubView } from "./CollectionSubView";
-import { resolve } from "bluebird";
 import { undoBatch } from "../../util/UndoManager";
 import { DragManager } from "../../util/DragManager";
 
@@ -38,9 +37,10 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             () => {
                 if (this.singleColumn) {
                     let children = this.childDocs.filter(d => !d.isMinimized);
-                    this.props.Document.height = children.reduce((height, d, i) =>
-                        height + this.singleColDocHeight(d) + (i === children.length - 1 ? this.yMargin : this.gridGap)
-                        , this.yMargin);
+                    let hgtbefore = this.props.Document.height;
+                    // this.props.Document.height = children.reduce((height, d, i) =>
+                    //     height + this.singleColDocHeight(d) + (i === children.length - 1 ? this.yMargin : this.gridGap)
+                    //     , this.yMargin);
                 }
             }, { fireImmediately: true });
     }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index a84cac37f..8ecc77946 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -564,8 +564,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         });
     }
 
-    onPointerEnter = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = true; };
-    onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; };
+    onPointerEnter = (e: React.PointerEvent): void => { }//this.props.Document.libraryBrush = true; };
+    onPointerLeave = (e: React.PointerEvent): void => { }//this.props.Document.libraryBrush = false; };
 
     isSelected = () => SelectionManager.IsSelected(this);
     @action select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); };
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index abb777adf..c7bcdca34 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -2,7 +2,6 @@ import { UndoManager } from "../client/util/UndoManager";
 import { Doc, Field } from "./Doc";
 import { SerializationHelper } from "../client/util/SerializationHelper";
 import { ProxyField } from "./Proxy";
-import { FieldValue } from "./Types";
 import { RefField } from "./RefField";
 import { ObjectField } from "./ObjectField";
 import { action } from "mobx";
@@ -13,6 +12,7 @@ function _readOnlySetter(): never {
     throw new Error("Documents can't be modified in read-only mode");
 }
 const _setterImpl = action(function (target: any, prop: string | symbol | number, value: any, receiver: any): boolean {
+    console.log("-set " + target[SelfProxy].title + "(" + target[SelfProxy][prop] + ")." + prop.toString() + " = " + value);
     if (SerializationHelper.IsSerializing()) {
         target[prop] = value;
         return true;
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 30a6f108a..3e7b407a8 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -34,6 +34,9 @@ export class CurrentUserUtils {
         doc.title = this.email;
         this.updateUserDocument(doc);
         doc.data = new List<Doc>();
+        doc.gridGap = 5;
+        doc.xMargin = 5;
+        doc.yMargin = 5;
         doc.excludeFromLibrary = true;
         doc.optionalRightCollection = Docs.StackingDocument([], { title: "New mobile uploads" });
         // doc.library = Docs.TreeDocument([doc], { title: `Library: ${CurrentUserUtils.email}` });
@@ -53,8 +56,13 @@ export class CurrentUserUtils {
             recentlyClosed.excludeFromLibrary = true;
             doc.recentlyClosed = recentlyClosed;
         }
+        if (doc.fakeLibrary === undefined) {
+            const recentlyClosed = Docs.TreeDocument([], { title: "Fake Library", height: 200 });
+            recentlyClosed.excludeFromLibrary = true;
+            doc.fakeLibrary = recentlyClosed;
+        }
         if (doc.sidebar === undefined) {
-            const sidebar = Docs.StackingDocument([doc.workspaces as Doc, doc, doc.recentlyClosed as Doc], { title: "Sidebar" });
+            const sidebar = Docs.StackingDocument([doc.workspaces as Doc, doc.fakeLibrary as Doc, doc.recentlyClosed as Doc], { title: "Sidebar" });
             sidebar.excludeFromLibrary = true;
             sidebar.gridGap = 5;
             sidebar.xMargin = 5;
-- 
cgit v1.2.3-70-g09d2


From d07b56aec1b1698d8a49283aade3c12c82ae1d0b Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 6 Jul 2019 02:36:54 -0400
Subject: fixed sidebar problems with doc decorations.

---
 src/client/views/DocumentDecorations.tsx           |  6 +++---
 src/client/views/MainView.tsx                      | 25 ++++------------------
 .../views/collections/CollectionStackingView.tsx   | 21 +++++++++---------
 src/client/views/nodes/DocumentView.tsx            |  4 ++--
 src/new_fields/util.ts                             |  2 +-
 .../authentication/models/current_user_utils.ts    |  7 +-----
 6 files changed, 21 insertions(+), 44 deletions(-)

(limited to 'src/client/views/MainView.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index e565566c7..c7990647a 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -536,8 +536,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 let scale = element.props.ScreenToLocalTransform().Scale * element.props.ContentScaling();
                 let actualdW = Math.max(width + (dW * scale), 20);
                 let actualdH = Math.max(height + (dH * scale), 20);
-                // doc.x = (doc.x || 0) + dX * (actualdW - width);
-                // doc.y = (doc.y || 0) + dY * (actualdH - height);
+                doc.x = (doc.x || 0) + dX * (actualdW - width);
+                doc.y = (doc.y || 0) + dY * (actualdH - height);
                 let proto = Doc.GetProto(element.props.Document);
                 let fixedAspect = e.ctrlKey || (!BoolCast(proto.ignoreAspect, false) && nwidth && nheight);
                 if (fixedAspect && (!nwidth || !nheight)) {
@@ -567,7 +567,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 } else {
                     dW && (doc.width = actualdW);
                     dH && (doc.height = actualdH);
-                    //Doc.SetInPlace(element.props.Document, "autoHeight", undefined, true);
+                    Doc.SetInPlace(element.props.Document, "autoHeight", undefined, true);
                 }
             }
         });
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index f9a5b2bb7..8e5bb3615 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,7 +1,7 @@
 import { IconName, library } from '@fortawesome/fontawesome-svg-core';
 import { faArrowDown, faArrowUp, faBell, faCheck, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, configure, observable, runInAction, reaction } from 'mobx';
+import { action, computed, configure, observable, runInAction, reaction, trace } from 'mobx';
 import { observer } from 'mobx-react';
 import "normalize.css";
 import * as React from 'react';
@@ -76,26 +76,16 @@ export class MainView extends React.Component {
         reaction(() => {
             let workspaces = CurrentUserUtils.UserDocument.workspaces;
             let recent = CurrentUserUtils.UserDocument.recentlyClosed;
-            let fakeLibrary = CurrentUserUtils.UserDocument.fakeLibrary;
             if (!(recent instanceof Doc)) return 0;
             if (!(workspaces instanceof Doc)) return 0;
-            if (!(fakeLibrary instanceof Doc)) return 0;
             let workspacesDoc = workspaces;
             let recentDoc = recent;
-            let fakeLibraryDoc = fakeLibrary;
-            // console.log("pheight = " + this.getPHeight() + " " + workspacesDoc[HeightSym]() + " " + recentDoc[HeightSym]());
-            let libraryHeight = this.getPHeight() - workspacesDoc[HeightSym]() - recentDoc[HeightSym]();
+            let libraryHeight = this.getPHeight() - workspacesDoc[HeightSym]() - recentDoc[HeightSym]() + CurrentUserUtils.UserDocument[HeightSym]() * 0.00001;
             return libraryHeight;
         }, (libraryHeight: number) => {
-            let fakeLibrary = CurrentUserUtils.UserDocument.fakeLibrary;
-            let cuser: Doc = fakeLibrary as Doc;//CurrentUserUtils.UserDocument;
-            console.log("BEFORE:" + cuser.title + ".height =" + cuser[HeightSym]() + "& .plight = " + cuser.plight);
-            if (libraryHeight && Math.abs(cuser[HeightSym]() - libraryHeight) > 5) {
-                console.log("ASSIGN to height & plight:" + libraryHeight);
-                cuser.height = libraryHeight;
-                cuser.plight = libraryHeight;
+            if (libraryHeight && Math.abs(CurrentUserUtils.UserDocument[HeightSym]() - libraryHeight) > 5) {
+                CurrentUserUtils.UserDocument.height = libraryHeight;
             }
-            console.log("AFTER:" + cuser.title + ".height =" + cuser[HeightSym]() + "& .plight= " + cuser.plight);
         }, { fireImmediately: true });
     }
 
@@ -310,17 +300,10 @@ export class MainView extends React.Component {
             CollectionDockingView.Instance.AddRightSplit(doc, undefined);
         }
     };
-    computing = false;
     @computed
     get flyout() {
         let sidebar = CurrentUserUtils.UserDocument.sidebar;
-        let workspaces = CurrentUserUtils.UserDocument.workspaces;
-        let recent = CurrentUserUtils.UserDocument.recentlyClosed;
-        let fakeLibrary = CurrentUserUtils.UserDocument.fakeLibrary;
         if (!(sidebar instanceof Doc)) return (null);
-        if (!(recent instanceof Doc)) return (null);
-        if (!(workspaces instanceof Doc)) return (null);
-        if (!(fakeLibrary instanceof Doc)) return (null);
         let sidebarDoc = sidebar;
         return <DocumentView
             Document={sidebarDoc}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index ffd05b52d..b0fd865c6 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -1,6 +1,6 @@
 import React = require("react");
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, IReactionDisposer, reaction } from "mobx";
+import { action, computed, IReactionDisposer, reaction, untracked } from "mobx";
 import { observer } from "mobx-react";
 import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
@@ -37,10 +37,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             () => {
                 if (this.singleColumn) {
                     let children = this.childDocs.filter(d => !d.isMinimized);
-                    let hgtbefore = this.props.Document.height;
-                    // this.props.Document.height = children.reduce((height, d, i) =>
-                    //     height + this.singleColDocHeight(d) + (i === children.length - 1 ? this.yMargin : this.gridGap)
-                    //     , this.yMargin);
+                    this.props.Document.height = children.reduce((height, d, i) =>
+                        height + this.singleColDocHeight(d) + (i === children.length - 1 ? this.yMargin : this.gridGap)
+                        , this.yMargin);
                 }
             }, { fireImmediately: true });
     }
@@ -54,10 +53,12 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         addDocument(doc);
         return true;
     }
-    getDocTransform(doc: Doc, dref: HTMLDivElement) {
-        let { scale, translateX, translateY } = Utils.GetScreenTransform(dref);
+    getDocTransform(doc: Doc, ind: number, width: number) {
+        let localY = this.childDocs.filter(d => !d.isMinimized).reduce((height, d, i) =>
+            height + (i < ind ? this.singleColDocHeight(d) + this.gridGap : 0), this.yMargin);
+        let translate = this.props.ScreenToLocalTransform().inverse().transformPoint((this.props.PanelWidth() - width) / 2, localY);
         let outerXf = Utils.GetScreenTransform(this._masonryGridRef!);
-        let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY);
+        let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translate[0], outerXf.translateY - translate[1]);
         return this.props.ScreenToLocalTransform().translate(offset[0], offset[1]).scale(NumCast(doc.width, 1) / this.columnWidth);
     }
     createRef = (ele: HTMLDivElement | null) => {
@@ -70,13 +71,11 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         let children = this.childDocs.filter(d => !d.isMinimized);
         return children.map((d, i) => {
             let layoutDoc = Doc.expandTemplateLayout(d, this.props.DataDoc);
-            let dref = React.createRef<HTMLDivElement>();
-            let dxf = () => this.getDocTransform(layoutDoc, dref.current!).scale(this.columnWidth / d[WidthSym]());
             let width = () => d.nativeWidth ? Math.min(d[WidthSym](), this.columnWidth) : this.columnWidth;
             let height = () => this.singleColDocHeight(layoutDoc);
+            let dxf = () => this.getDocTransform(layoutDoc, i, width()).scale(this.columnWidth / d[WidthSym]());
             return <div className="collectionStackingView-columnDoc"
                 key={d[Id]}
-                ref={dref}
                 style={{ width: width(), height: height() }} >
                 <CollectionSchemaPreview
                     Document={layoutDoc}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 8ecc77946..a84cac37f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -564,8 +564,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         });
     }
 
-    onPointerEnter = (e: React.PointerEvent): void => { }//this.props.Document.libraryBrush = true; };
-    onPointerLeave = (e: React.PointerEvent): void => { }//this.props.Document.libraryBrush = false; };
+    onPointerEnter = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = true; };
+    onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; };
 
     isSelected = () => SelectionManager.IsSelected(this);
     @action select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); };
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index c7bcdca34..b5e50d501 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -12,7 +12,7 @@ function _readOnlySetter(): never {
     throw new Error("Documents can't be modified in read-only mode");
 }
 const _setterImpl = action(function (target: any, prop: string | symbol | number, value: any, receiver: any): boolean {
-    console.log("-set " + target[SelfProxy].title + "(" + target[SelfProxy][prop] + ")." + prop.toString() + " = " + value);
+    //console.log("-set " + target[SelfProxy].title + "(" + target[SelfProxy][prop] + ")." + prop.toString() + " = " + value);
     if (SerializationHelper.IsSerializing()) {
         target[prop] = value;
         return true;
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 3e7b407a8..e328d6e5c 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -56,13 +56,8 @@ export class CurrentUserUtils {
             recentlyClosed.excludeFromLibrary = true;
             doc.recentlyClosed = recentlyClosed;
         }
-        if (doc.fakeLibrary === undefined) {
-            const recentlyClosed = Docs.TreeDocument([], { title: "Fake Library", height: 200 });
-            recentlyClosed.excludeFromLibrary = true;
-            doc.fakeLibrary = recentlyClosed;
-        }
         if (doc.sidebar === undefined) {
-            const sidebar = Docs.StackingDocument([doc.workspaces as Doc, doc.fakeLibrary as Doc, doc.recentlyClosed as Doc], { title: "Sidebar" });
+            const sidebar = Docs.StackingDocument([doc.workspaces as Doc, doc, doc.recentlyClosed as Doc], { title: "Sidebar" });
             sidebar.excludeFromLibrary = true;
             sidebar.gridGap = 5;
             sidebar.xMargin = 5;
-- 
cgit v1.2.3-70-g09d2


From 544da3d4c1dbdbfe0854e0ed49fb01ed36ec6a47 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 6 Jul 2019 14:15:36 -0400
Subject: disabled dragging of containers in sidebar

---
 src/client/views/MainView.tsx           | 2 +-
 src/client/views/nodes/DocumentView.tsx | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

(limited to 'src/client/views/MainView.tsx')

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 8e5bb3615..d7674c26e 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -80,7 +80,7 @@ export class MainView extends React.Component {
             if (!(workspaces instanceof Doc)) return 0;
             let workspacesDoc = workspaces;
             let recentDoc = recent;
-            let libraryHeight = this.getPHeight() - workspacesDoc[HeightSym]() - recentDoc[HeightSym]() + CurrentUserUtils.UserDocument[HeightSym]() * 0.00001;
+            let libraryHeight = this.getPHeight() - workspacesDoc[HeightSym]() - recentDoc[HeightSym]() - 20 + CurrentUserUtils.UserDocument[HeightSym]() * 0.00001;
             return libraryHeight;
         }, (libraryHeight: number) => {
             if (libraryHeight && Math.abs(CurrentUserUtils.UserDocument[HeightSym]() - libraryHeight) > 5) {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index a84cac37f..ef397a824 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -375,7 +375,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
     onPointerMove = (e: PointerEvent): void => {
         if (!e.cancelBubble && this.active) {
-            if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
+            if (!this.props.Document.excludeFromLibrary && (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3)) {
                 document.removeEventListener("pointermove", this.onPointerMove);
                 document.removeEventListener("pointerup", this.onPointerUp);
                 if (!e.altKey && !this.topMost && e.buttons === 1 && !BoolCast(this.props.Document.lockedPosition)) {
-- 
cgit v1.2.3-70-g09d2

