From 25ec1ef48c36ad91dccc408fa6075f0915c36118 Mon Sep 17 00:00:00 2001
From: anika-ahluwalia <anika.ahluwalia@gmail.com>
Date: Tue, 21 Jul 2020 17:18:07 -0500
Subject: finished left side UI changes

---
 src/client/views/collections/CollectionView.tsx | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index c1da23470..21b0045d5 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -80,6 +80,7 @@ export interface CollectionViewCustomProps {
     childLayoutTemplate?: () => Opt<Doc>;  // specify a layout Doc template to use for children of the collection
     childLayoutString?: string;  // specify a layout string to use for children of the collection
     childOpacity?: () => number;
+    hideFilter?: true;
 }
 
 export interface CollectionRenderProps {
@@ -559,7 +560,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                         Utils.CorsProxy(Cast(d.data, ImageField)!.url.href) : Cast(d.data, ImageField)!.url.href
                     :
                     ""))}
-            {(!this.props.isSelected() || this.props.Document.hideFilterView) && !this.props.Document.forceActive ? (null) :
+            {this.props.hideFilter || this.props.Document.hideFilterView || !this.props.isSelected() && !this.props.Document.forceActive ? (null) :
                 <div className="collectionView-filterDragger" title="library View Dragger" onPointerDown={this.onPointerDown}
                     style={{ right: this.facetWidth() - 1, top: this.props.Document._viewType === CollectionViewType.Docking ? "25%" : "55%" }} />
             }
-- 
cgit v1.2.3-70-g09d2


From 47214818a4a6f423ed65ab90d2a5876bde370dc8 Mon Sep 17 00:00:00 2001
From: anika-ahluwalia <anika.ahluwalia@gmail.com>
Date: Wed, 22 Jul 2020 10:22:27 -0500
Subject: framework for properties panel

---
 src/client/views/MainView.scss                     |  5 ++-
 src/client/views/collections/CollectionView.scss   | 35 ++++++++++++++++
 src/client/views/collections/CollectionView.tsx    | 49 ++++++++++++++++++++--
 .../collectionFreeForm/PropertiesView.scss         | 32 ++++++++++++++
 .../collectionFreeForm/PropertiesView.tsx          | 38 +++++++++++++++++
 5 files changed, 154 insertions(+), 5 deletions(-)
 create mode 100644 src/client/views/collections/collectionFreeForm/PropertiesView.scss
 create mode 100644 src/client/views/collections/collectionFreeForm/PropertiesView.tsx

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index 9454b0c78..9c04458fe 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -142,7 +142,7 @@
             margin-left: -13px;
             border-radius: 8px;
             width: 65px;
-            position: absolute;
+            position: relative;
             text-align: center;
             font-size: 9.5px;
             margin-top: 4px;
@@ -290,7 +290,8 @@
         width: 10px;
         height: 10px;
         float: right;
-        margin-right: 1px;
+        margin-right: 3px;
+        padding-top: 19px;
     }
 
 }
diff --git a/src/client/views/collections/CollectionView.scss b/src/client/views/collections/CollectionView.scss
index b630f9cf8..585f6865e 100644
--- a/src/client/views/collections/CollectionView.scss
+++ b/src/client/views/collections/CollectionView.scss
@@ -24,6 +24,41 @@
         border-right: unset;
         z-index: 2;
     }
+
+    .collectionView-propertiesDragger {
+        background-color: rgb(140, 139, 139);
+        height: 55px;
+        width: 15.5px;
+        position: absolute;
+        top: 55%;
+        border: 1px black solid;
+        border-radius: 0;
+        border-top-left-radius: 10px;
+        border-bottom-left-radius: 10px;
+        border-right: unset;
+        z-index: 2;
+
+        .collectionView-propertiesDragger-icon {
+            width: 10px;
+            height: 10px;
+            float: left;
+            margin-left: 3px;
+            padding-top: 19px;
+        }
+    }
+
+    .collectionView-propertiesView {
+        display: flex;
+        flex-direction: column;
+        width: 200px;
+        height: 100%;
+        position: absolute;
+        right: 0;
+        top: 0;
+        border-left: solid 1px;
+        z-index: 10;
+    }
+
     .collectionTimeView-treeView {
         display: flex;
         flex-direction: column;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 8b09281d5..44d22dd5d 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -49,6 +49,7 @@ import { CollectionTreeView } from "./CollectionTreeView";
 import './CollectionView.scss';
 import CollectionMenu from './CollectionMenu';
 import { SharingPermissions } from '../../util/SharingManager';
+import { PropertiesView } from './collectionFreeForm/PropertiesView';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -367,9 +368,22 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
     get _facetWidth() { return NumCast(this.props.Document._facetWidth); }
     set _facetWidth(value) { this.props.Document._facetWidth = value; }
 
-    bodyPanelWidth = () => this.props.PanelWidth() - this.facetWidth();
+    get _propertiesWidth() { return NumCast(this.props.Document._propertiesWidth); }
+    set _propertiesWidth(value) { this.props.Document._propertiesWidth = value; }
+
+    bodyPanelWidth = () => this.props.PanelWidth() - this.propertiesWidth();
     facetWidth = () => Math.max(0, Math.min(this.props.PanelWidth() - 25, this._facetWidth));
 
+    propertiesWidth = () => Math.max(0, Math.min(this.props.PanelWidth() - 25, this._propertiesWidth));
+
+    @computed get propertiesIcon() {
+        if (this.propertiesWidth() < 10) {
+            return "chevron-left";
+        } else {
+            return "chevron-right";
+        }
+    }
+
     @computed get dataDoc() {
         return (this.props.DataDoc && this.props.Document.isTemplateForField ? Doc.GetProto(this.props.DataDoc) :
             this.props.Document.resolvedDataDoc ? this.props.Document : Doc.GetProto(this.props.Document)); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template
@@ -489,6 +503,14 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
             return false;
         }), returnFalse, action(() => this._facetWidth = this.facetWidth() < 15 ? Math.min(this.props.PanelWidth() - 25, 200) : 0), false);
     }
+
+    onDown = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
+            this._propertiesWidth = this.props.PanelWidth() - Math.max(this.props.ScreenToLocalTransform().transformPoint(e.clientX, 0)[0], 0);
+            return false;
+        }), returnFalse, action(() => this._propertiesWidth = this.propertiesWidth() < 15 ? Math.min(this.props.PanelWidth() - 25, 200) : 0), false);
+    }
+
     filterBackground = () => "rgba(105, 105, 105, 0.432)";
     get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; } // this makes the tree view collection ignore these filters (otherwise, the filters would filter themselves)
     @computed get scriptField() {
@@ -558,6 +580,18 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 </div>
             </div>;
     }
+
+    @computed get propertiesView() {
+        TraceMobx();
+        return !this._propertiesWidth || this.props.dontRegisterView ? (null) :
+            <div className="collectionView-propertiesView" style={{
+                width: `${this.propertiesWidth()}px`,
+                overflow: this.propertiesWidth() < 15 ? "hidden" : undefined
+            }}>
+                <PropertiesView />
+            </div>;
+    }
+
     childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null);
     childLayoutString = this.props.childLayoutString || StrCast(this.props.Document.childLayoutString);
 
@@ -588,11 +622,20 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                         Utils.CorsProxy(Cast(d.data, ImageField)!.url.href) : Cast(d.data, ImageField)!.url.href
                     :
                     ""))}
-            {this.props.hideFilter || this.props.Document.hideFilterView || !this.props.isSelected() && !this.props.Document.forceActive ? (null) :
+            {/* {this.props.hideFilter || this.props.Document.hideFilterView || !this.props.isSelected() && !this.props.Document.forceActive ? (null) :
                 <div className="collectionView-filterDragger" title="library View Dragger" onPointerDown={this.onPointerDown}
                     style={{ right: this.facetWidth() - 1, top: this.props.Document._viewType === CollectionViewType.Docking ? "25%" : "55%" }} />
             }
-            {this.facetWidth() < 10 ? (null) : this.filterView}
+            {this.facetWidth() < 10 ? (null) : this.filterView} */}
+
+            {this.props.hideFilter || this.props.Document.hideFilterView || !this.props.isSelected() && !this.props.Document.forceActive ? (null) :
+                <div className="collectionView-propertiesDragger" title="Properties View Dragger" onPointerDown={this.onDown}
+                    style={{ right: this.propertiesWidth() - 1, top: this.props.Document._viewType === CollectionViewType.Docking ? "25%" : "55%" }}>
+                    <div className="collectionView-propertiesDragger-icon">
+                        <FontAwesomeIcon icon={this.propertiesIcon} color="white" size="sm" /> </div>
+                </div>
+            }
+            {this.propertiesWidth() < 10 ? (null) : this.propertiesView}
         </div>);
     }
 }
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.scss b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
new file mode 100644
index 000000000..d4cc53bfa
--- /dev/null
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
@@ -0,0 +1,32 @@
+.propertiesView {
+
+    background-color: rgb(168, 168, 168);
+    height: 100%;
+    z-index: 1;
+
+    .propertiesView-title {
+        background-color: rgb(134, 134, 134);
+        border-top: 1px solid black;
+        border-bottom: 1px solid black;
+    }
+
+    .propertiesView-name {
+        border-top: 1px solid black;
+        border-bottom: 1px solid black;
+    }
+
+    .propertiesView-settings {
+        border-top: 1px solid black;
+        border-bottom: 1px solid black;
+    }
+
+    .propertiesView-fields {
+        border-top: 1px solid black;
+        border-bottom: 1px solid black;
+    }
+
+    .propertiesView-layout {
+        border-top: 1px solid black;
+        border-bottom: 1px solid black;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
new file mode 100644
index 000000000..4306453ea
--- /dev/null
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -0,0 +1,38 @@
+import React = require("react");
+import { observer } from "mobx-react";
+import "./PropertiesView.scss";
+import { observable, action } from "mobx";
+import { Doc } from "../../../../fields/Doc";
+import { DocumentView } from "../../nodes/DocumentView";
+
+
+// interface PropertiesViewProps {
+//     document: Doc;
+//     dataDoc: Doc;
+//     docView: DocumentView;
+//     width: number;
+// }
+
+@observer
+export class PropertiesView extends React.Component<{}> {
+
+    render() {
+        return <div className="propertiesView" >
+            <div className="propertiesView-title">
+                Properties
+            </div>
+            <div className="propertiesView-name">
+                Properties
+            </div>
+            <div className="propertiesView-settings">
+                Settings
+            </div>
+            <div className="propertiesView-fields">
+                Fields
+            </div>
+            <div className="propertiesView-layout">
+                Layout
+            </div>
+        </div>;
+    }
+} 
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 5b025537f60ef9222c0203db378c0298cd3dc86f Mon Sep 17 00:00:00 2001
From: anika-ahluwalia <anika.ahluwalia@gmail.com>
Date: Wed, 22 Jul 2020 12:57:05 -0500
Subject: adding fields to properties column

---
 src/client/util/CurrentUserUtils.ts                |  8 +--
 src/client/views/EditableView.tsx                  |  2 +-
 src/client/views/MainView.scss                     |  5 +-
 src/client/views/collections/CollectionView.tsx    |  2 +-
 .../collectionFreeForm/PropertiesView.scss         | 43 +++++++++++++---
 .../collectionFreeForm/PropertiesView.tsx          | 60 +++++++++++++++++-----
 6 files changed, 93 insertions(+), 27 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 088e20a3e..1dd25ae30 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -660,7 +660,7 @@ export class CurrentUserUtils {
 
         CurrentUserUtils.workspaceStack = new PrefetchProxy(Docs.Create.TreeDocument([workspaces], {
             title: " ", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
-            treeViewTruncateTitleWidth: 150, hideFilterView: true,
+            treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false,
             lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
         })) as any as Doc;
 
@@ -679,7 +679,7 @@ export class CurrentUserUtils {
 
         CurrentUserUtils.catalogStack = new PrefetchProxy(Docs.Create.TreeDocument([catalog], {
             title: " ", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
-            treeViewTruncateTitleWidth: 150, hideFilterView: true,
+            treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false,
             lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
         })) as any as Doc;
 
@@ -703,7 +703,7 @@ export class CurrentUserUtils {
 
         CurrentUserUtils.closedStack = new PrefetchProxy(Docs.Create.TreeDocument([recentlyClosed], {
             title: " ", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
-            treeViewTruncateTitleWidth: 150, hideFilterView: true,
+            treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false,
             lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
         })) as any as Doc;
 
@@ -718,7 +718,7 @@ export class CurrentUserUtils {
         if (doc["tabs-button-library"] === undefined) {
             const libraryStack = new PrefetchProxy(Docs.Create.TreeDocument([workspaces, documents, recentlyClosed, doc], {
                 title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
-                treeViewTruncateTitleWidth: 150, hideFilterView: true,
+                treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false,
                 lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
             })) as any as Doc;
             doc["tabs-button-library"] = new PrefetchProxy(Docs.Create.ButtonDocument({
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 25a87ab56..259a803a2 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -192,7 +192,7 @@ export class EditableView extends React.Component<EditableProps> {
             return (this.props.contents instanceof ObjectField ? (null) :
                 <div className={`editableView-container-editing${this.props.oneLine ? "-oneLine" : ""}`}
                     ref={this._ref}
-                    style={{ display: this.props.display, minHeight: "20px", height: `${this.props.height ? this.props.height : "auto"}`, maxHeight: `${this.props.maxHeight}` }}
+                    style={{ display: this.props.display, minHeight: "17px", whiteSpace: "nowrap", height: `${this.props.height ? this.props.height : "auto"}`, maxHeight: `${this.props.maxHeight}` }}
                     onClick={this.onClick} placeholder={this.props.placeholder}>
                     <span style={{
                         fontStyle: this.props.fontStyle, fontSize: this.props.fontSize,
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index 9c04458fe..55280b231 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -121,6 +121,9 @@
     padding: 20px;
     padding-right: 50px;
 
+    overflow-y: scroll;
+    overflow-x: hidden;
+
     .mainView-menuPanel-button {
         width: 45px;
         height: 45px;
@@ -174,7 +177,7 @@
         background-color: dimgray;
         border-radius: 100%;
         transform-origin: top left;
-        margin-bottom: 23px;
+        margin-bottom: 20px;
         margin-top: 5px;
 
         margin-right: 25px;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 44d22dd5d..616e7995d 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -588,7 +588,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 width: `${this.propertiesWidth()}px`,
                 overflow: this.propertiesWidth() < 15 ? "hidden" : undefined
             }}>
-                <PropertiesView />
+                <PropertiesView document={this.dataDoc} />
             </div>;
     }
 
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.scss b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
index d4cc53bfa..bb5b80abd 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.scss
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
@@ -1,32 +1,59 @@
 .propertiesView {
 
-    background-color: rgb(168, 168, 168);
+    background-color: rgb(205, 205, 205);
     height: 100%;
     z-index: 1;
+    font-family: "Noto Sans";
+    cursor: auto;
+
+    //overflow-y: scroll;
 
     .propertiesView-title {
-        background-color: rgb(134, 134, 134);
-        border-top: 1px solid black;
-        border-bottom: 1px solid black;
+        background-color: rgb(159, 159, 159);
+        text-align: center;
+        font-size: 18px;
+        font-weight: bold;
+        padding-top: 12px;
+        padding-bottom: 12px;
     }
 
     .propertiesView-name {
-        border-top: 1px solid black;
         border-bottom: 1px solid black;
+        padding: 8.5px;
+        font-size: 12.5px;
     }
 
     .propertiesView-settings {
-        border-top: 1px solid black;
         border-bottom: 1px solid black;
+        padding: 8.5px;
+        font-size: 12.5px;
+        font-weight: bold;
     }
 
     .propertiesView-fields {
-        border-top: 1px solid black;
         border-bottom: 1px solid black;
+        padding: 8.5px;
+
+        .propertiesView-fields-title {
+            font-size: 12.5px;
+            font-weight: bold;
+            padding-bottom: 7px;
+        }
+
+        .propertiesView-fields-content {
+            font-size: 10px;
+            margin-left: 5px;
+
+            &:hover {
+                cursor: pointer;
+            }
+        }
     }
 
     .propertiesView-layout {
-        border-top: 1px solid black;
         border-bottom: 1px solid black;
+        padding: 8.5px;
+        font-size: 12.5px;
+        font-weight: bold;
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index 4306453ea..bc78fccdf 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -1,20 +1,54 @@
 import React = require("react");
 import { observer } from "mobx-react";
 import "./PropertiesView.scss";
-import { observable, action } from "mobx";
-import { Doc } from "../../../../fields/Doc";
+import { observable, action, computed } from "mobx";
+import { Doc, Field, DocListCast } from "../../../../fields/Doc";
 import { DocumentView } from "../../nodes/DocumentView";
+import { ComputedField } from "../../../../fields/ScriptField";
+import { EditableView } from "../../EditableView";
+import { KeyValueBox } from "../../nodes/KeyValueBox";
+import { Cast } from "../../../../fields/Types";
+import { listSpec } from "../../../../fields/Schema";
 
 
-// interface PropertiesViewProps {
-//     document: Doc;
-//     dataDoc: Doc;
-//     docView: DocumentView;
-//     width: number;
-// }
+interface PropertiesViewProps {
+    document: Doc;
+    //dataDoc: Doc;
+    //docView: DocumentView;
+}
 
 @observer
-export class PropertiesView extends React.Component<{}> {
+export class PropertiesView extends React.Component<PropertiesViewProps> {
+
+    @computed get expandedField() {
+        const ids: { [key: string]: string } = {};
+        const doc = this.props.document;
+        doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
+
+        const rows: JSX.Element[] = [];
+        for (const key of Object.keys(ids).slice().sort()) {
+            const contents = doc[key];
+            let contentElement: (JSX.Element | null)[] | JSX.Element = [];
+            contentElement = <EditableView key="editableView"
+                contents={contents !== undefined ? Field.toString(contents as Field) : "null"}
+                height={13}
+                fontSize={10}
+                GetValue={() => Field.toKeyValueString(doc, key)}
+                SetValue={(value: string) => KeyValueBox.SetField(doc, key, value, true)}
+            />;
+
+            rows.push(<div style={{ display: "flex", overflowY: "visible", marginBottom: "-1px" }} key={key}>
+                <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key + ":"}</span>
+                &nbsp;
+                {contentElement}
+            </div>);
+        }
+        return rows;
+    }
+
+    @computed get layoutPreview() {
+        return "layout";
+    }
 
     render() {
         return <div className="propertiesView" >
@@ -22,16 +56,18 @@ export class PropertiesView extends React.Component<{}> {
                 Properties
             </div>
             <div className="propertiesView-name">
-                Properties
+                Collection
             </div>
             <div className="propertiesView-settings">
                 Settings
             </div>
             <div className="propertiesView-fields">
-                Fields
+                <div className="propertiesView-fields-title"> Fields</div>
+                <div className="propertiesView-fields-content"> {this.expandedField} </div>
             </div>
             <div className="propertiesView-layout">
-                Layout
+                <div>Layout</div>
+                <div>{this.layoutPreview}</div>
             </div>
         </div>;
     }
-- 
cgit v1.2.3-70-g09d2


From fd741cddf64fe1b068b7a1de5bc3840798afe75d Mon Sep 17 00:00:00 2001
From: andy temp <andytemp@Kates-MBP.fios-router.home>
Date: Wed, 22 Jul 2020 14:42:32 -0400
Subject: search results open and close as panel under bar

---
 src/client/util/CurrentUserUtils.ts                |  2 +-
 .../views/collections/CollectionSchemaView.tsx     |  2 +-
 src/client/views/collections/CollectionView.tsx    |  2 +-
 src/client/views/nodes/FieldView.tsx               |  2 ++
 src/client/views/search/SearchBox.scss             |  2 +-
 src/client/views/search/SearchBox.tsx              | 28 ++++++++++++++++++----
 6 files changed, 29 insertions(+), 9 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 582cc2d5c..f16ef399c 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -658,7 +658,7 @@ export class CurrentUserUtils {
         const libraryBtn = CurrentUserUtils.setupLibraryPanel(doc, sidebarContainer);
         const searchBtn = CurrentUserUtils.setupSearchBtnPanel(doc, sidebarContainer);
         if (doc["search-panel"] === undefined) {
-            doc["search-panel"] = new PrefetchProxy(Docs.Create.SearchDocument({ ignoreClick: true, childDropAction: "alias", lockedPosition: true, _viewType: CollectionViewType.Schema, title: "sidebar search stack", })) as any as Doc;
+            doc["search-panel"] = new PrefetchProxy(Docs.Create.SearchDocument({_width: 500, _height: 400, backgroundColor: "dimGray", ignoreClick: true, childDropAction: "alias", lockedPosition: true, _viewType: CollectionViewType.Schema, title: "sidebar search stack", })) as any as Doc;
     }
         // Finally, setup the list of buttons to display in the sidebar
         if (doc["tabs-buttons"] === undefined) {
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 50eea5059..be4f7c888 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -631,7 +631,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
         return <div className="collectionSchemaView-container"
             style={{
                 pointerEvents: !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined,
-                width: this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%"
+                width: this.props.PanelWidth() || "100%", height: this.props.PanelPosition === "absolute" ? this.props.PanelHeight() : this.props.PanelHeight()  || "100%", top: this.props.PanelPosition === "absolute" ? 32 : 0, position: this.props.PanelPosition || "relative",
             }}  >
             <div className="collectionSchemaView-tableContainer"
                 style={{ width: `calc(100% - ${this.previewWidth()}px)` }}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 43bfbc913..0178cc2e9 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -554,7 +554,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
         return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
             style={{ pointerEvents: this.props.Document.isBackground ? "none" : undefined, boxShadow }}>
             {this.showIsTagged()}
-            <div className="collectionView-facetCont" style={{ width: `calc(100% - ${this.facetWidth()}px)` }}>
+            <div className="collectionView-facetCont" style={{ display: this.props.PanelPosition==="absolute"? "flex" : "", justifyContent: this.props.PanelPosition==="absolute"? "center" : "", width: `calc(100% - ${this.facetWidth()}px)` }}>
                 {this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
             </div>
             {this.lightbox(DocListCast(this.props.Document[this.props.fieldKey]).filter(d => d.type === DocumentType.IMG).map(d =>
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 3aabd5d6b..8b83a29b2 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -48,10 +48,12 @@ export interface FieldViewProps {
     ignoreAutoHeight?: boolean;
     PanelWidth: () => number;
     PanelHeight: () => number;
+    PanelPosition: string;
     NativeHeight: () => number;
     NativeWidth: () => number;
     setVideoBox?: (player: VideoBox) => void;
     ContentScaling: () => number;
+
     ChromeHeight?: () => number;
     childLayoutTemplate?: () => Opt<Doc>;
     highlighting?: string[];
diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss
index 4d057f782..8cd2f00b4 100644
--- a/src/client/views/search/SearchBox.scss
+++ b/src/client/views/search/SearchBox.scss
@@ -17,7 +17,7 @@
 .searchBox-bar {
     height: 32px;
     display: flex;
-    justify-content: flex-end;
+    justify-content: center;
     align-items: center;
     background-color: black;
     .searchBox-barChild {
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 884aa6a68..21f476ea4 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -199,13 +199,26 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
 
     enter = (e: React.KeyboardEvent) => {
         if (e.key === "Enter") {
-            if (this._icons !== this._allIcons) {
-                runInAction(() => { this.expandedBucket = false });
+            // if (this._icons !== this._allIcons) {
+            //     runInAction(() => { this.expandedBucket = false });
+            // }
+            console.log(StrCast(this.layoutDoc._searchString));
+            if (StrCast(this.layoutDoc._searchString)!==""){
+                console.log("OPEN");
+                runInAction(()=>{this.open=true});
+            }
+            else {
+                console.log("CLOSE");
+                runInAction(()=>{this.open=false});
+
             }
             this.submitSearch();
         }
     }
 
+    @observable open: boolean = false;
+
+
     public static async convertDataUri(imageUri: string, returnedFilename: string) {
         try {
             const posting = Utils.prepend("/uploadURI");
@@ -377,7 +390,6 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
     get fieldFiltersApplied() { return !(this._authorFieldStatus && this._titleFieldStatus); }
 
 
-    @observable expandedBucket: boolean = false;
     @action
     submitSearch = async (reset?: boolean) => {
         this.checkIcons();
@@ -1109,7 +1121,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                     </span> */}
                     <input value={StrCast(this.layoutDoc._searchString)} onChange={this.onChange} type="text" placeholder="Search..." id="search-input" ref={this.inputRef}
                         className="searchBox-barChild searchBox-input" onPointerDown={this.openSearch} onKeyPress={this.enter} onFocus={this.openSearch}
-                        style={{ width: this._searchbarOpen ? "500px" : "100px" }} />
+                        style={{ width: this._searchbarOpen ? "200px" : "200px" }} />
                     {/* <button className="searchBox-barChild searchBox-filter" style={{ transform: "none" }} title="Advanced Filtering Options" onClick={() => this.handleFilterChange()}><FontAwesomeIcon icon="ellipsis-v" color="white" /></button> */}
                 </div>
                 <div id={`filterhead${this.props.Document[Id]}`} className="filter-form" style={this._filterOpen && this._numTotalResults > 0 ? { overflow: "visible" } : { overflow: "hidden" }}>
@@ -1123,12 +1135,18 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                         {this.keyButtons}
                     </div>
                 </div>
+                <div style={{zIndex:2000}}>
                 {this.headerscale > 0 ? <CollectionView {...this.props}
                     Document={this.props.Document}
                     moveDocument={returnFalse}
                     removeDocument={returnFalse}
+                    PanelHeight={this.open===true?()=>200 :()=>0}
+                    PanelWidth={this.open===true? ()=>600 : ()=>0}
+                    PanelPosition={"absolute"}
                     focus={this.selectElement}
-                    ScreenToLocalTransform={Transform.Identity} /> : undefined}
+                    ScreenToLocalTransform={Transform.Identity}
+                     /> : undefined}
+                     </div>
 
                 <div className="searchBox-results" onScroll={this.resultsScrolled} style={{
                     display: this._resultsOpen ? "flex" : "none",
-- 
cgit v1.2.3-70-g09d2


From a99cef9945c1c4f9e5ff07663fc6db5cda2dcd50 Mon Sep 17 00:00:00 2001
From: anika-ahluwalia <anika.ahluwalia@gmail.com>
Date: Wed, 22 Jul 2020 16:27:27 -0500
Subject: added layout section

---
 src/client/views/collections/CollectionView.tsx    |  7 +-
 .../collectionFreeForm/PropertiesView.scss         | 15 +++-
 .../collectionFreeForm/PropertiesView.tsx          | 82 +++++++++++++++++++---
 3 files changed, 92 insertions(+), 12 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 616e7995d..eec68f9fc 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -588,7 +588,12 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 width: `${this.propertiesWidth()}px`,
                 overflow: this.propertiesWidth() < 15 ? "hidden" : undefined
             }}>
-                <PropertiesView document={this.dataDoc} />
+                <PropertiesView dataDoc={this.dataDoc} Document={this.props.Document}
+                    width={this._propertiesWidth}
+                    height={this.props.PanelHeight()}
+                    renderDepth={this.props.renderDepth}
+                    ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+                />
             </div>;
     }
 
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.scss b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
index bb5b80abd..e81b1eeb4 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.scss
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
@@ -51,9 +51,18 @@
     }
 
     .propertiesView-layout {
-        border-bottom: 1px solid black;
         padding: 8.5px;
-        font-size: 12.5px;
-        font-weight: bold;
+
+        .propertiesView-layout-title {
+            font-weight: bold;
+            font-size: 12.5px;
+            padding-bottom: 7px;
+        }
+
+        .propertiesView-layout-content {
+            margin-left: 5px;
+            overflow: hidden;
+        }
+
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index bc78fccdf..27b0dbd9e 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -2,27 +2,58 @@ import React = require("react");
 import { observer } from "mobx-react";
 import "./PropertiesView.scss";
 import { observable, action, computed } from "mobx";
-import { Doc, Field, DocListCast } from "../../../../fields/Doc";
+import { Doc, Field, DocListCast, WidthSym, HeightSym } from "../../../../fields/Doc";
 import { DocumentView } from "../../nodes/DocumentView";
 import { ComputedField } from "../../../../fields/ScriptField";
 import { EditableView } from "../../EditableView";
 import { KeyValueBox } from "../../nodes/KeyValueBox";
-import { Cast } from "../../../../fields/Types";
+import { Cast, StrCast, NumCast } from "../../../../fields/Types";
 import { listSpec } from "../../../../fields/Schema";
+import { ContentFittingDocumentView } from "../../nodes/ContentFittingDocumentView";
+import { returnFalse, returnOne, emptyFunction, emptyPath, returnTrue, returnZero, returnEmptyFilter, Utils } from "../../../../Utils";
+import { Id } from "../../../../fields/FieldSymbols";
+import { Transform } from "../../../util/Transform";
 
 
 interface PropertiesViewProps {
-    document: Doc;
-    //dataDoc: Doc;
+    dataDoc: Doc;
+    Document: Doc;
+    width: number;
+    height: number;
+    renderDepth: number;
+    ScreenToLocalTransform: () => Transform;
     //docView: DocumentView;
 }
 
 @observer
 export class PropertiesView extends React.Component<PropertiesViewProps> {
 
+    @computed get MAX_EMBED_HEIGHT() { return 200; }
+
+    rtfWidth = () => Math.min(this.props.Document?.[WidthSym](), this.props.width - 20);
+    rtfHeight = () => this.rtfWidth() <= this.props.Document?.[WidthSym]() ? Math.min(this.props.Document?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
+
+    docWidth = () => {
+        const layoutDoc = this.props.Document;
+        const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
+        if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.width - 20));
+        return NumCast(layoutDoc._nativeWidth) ? Math.min(layoutDoc[WidthSym](), this.props.width - 20) : this.props.width - 20;
+    }
+    docHeight = () => {
+        const layoutDoc = this.props.Document;
+        return Math.max(70, Math.min(this.MAX_EMBED_HEIGHT, (() => {
+            const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
+            if (aspect) return this.docWidth() * aspect;
+            return layoutDoc._fitWidth ? (!this.props.dataDoc._nativeHeight ? NumCast(this.props.height) :
+                Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, NumCast(layoutDoc._nativeHeight)) / NumCast(layoutDoc._nativeWidth,
+                    NumCast(this.props.height)))) :
+                NumCast(layoutDoc._height) ? NumCast(layoutDoc._height) : 50;
+        })()));
+    }
+
     @computed get expandedField() {
         const ids: { [key: string]: string } = {};
-        const doc = this.props.document;
+        const doc = this.props.dataDoc;
         doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
 
         const rows: JSX.Element[] = [];
@@ -47,7 +78,42 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     @computed get layoutPreview() {
-        return "layout";
+        const layoutDoc = Doc.Layout(this.props.Document);
+        const panelHeight = StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : this.docHeight;
+        const panelWidth = StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : this.docWidth;
+        return <div style={{ display: "inline-block", height: panelHeight() }} key={this.props.dataDoc[Id]}>
+            <ContentFittingDocumentView
+                Document={layoutDoc}
+                DataDoc={this.props.dataDoc}
+                LibraryPath={emptyPath}
+                renderDepth={this.props.renderDepth + 1}
+                rootSelected={returnFalse}
+                treeViewDoc={undefined}
+                backgroundColor={() => "lightgrey"}
+                fitToBox={false}
+                FreezeDimensions={true}
+                NativeWidth={layoutDoc.type ===
+                    StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : returnZero}
+                NativeHeight={layoutDoc.type ===
+                    StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : returnZero}
+                PanelWidth={panelWidth}
+                PanelHeight={panelHeight}
+                focus={returnFalse}
+                ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+                docFilters={returnEmptyFilter}
+                ContainingCollectionDoc={undefined}
+                ContainingCollectionView={undefined}
+                addDocument={returnFalse}
+                moveDocument={undefined}
+                removeDocument={returnFalse}
+                parentActive={() => false}
+                whenActiveChanged={emptyFunction}
+                addDocTab={returnFalse}
+                pinToPres={emptyFunction}
+                bringToFront={returnFalse}
+                ContentScaling={returnOne}
+            />
+        </div>;
     }
 
     render() {
@@ -66,8 +132,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 <div className="propertiesView-fields-content"> {this.expandedField} </div>
             </div>
             <div className="propertiesView-layout">
-                <div>Layout</div>
-                <div>{this.layoutPreview}</div>
+                <div className="propertiesView-layout-title" >Layout</div>
+                <div className="propertiesView-layout-content">{this.layoutPreview}</div>
             </div>
         </div>;
     }
-- 
cgit v1.2.3-70-g09d2


From 66bcfb6364ca5d8b4a0fd26139966ea9d6c12f87 Mon Sep 17 00:00:00 2001
From: anika-ahluwalia <anika.ahluwalia@gmail.com>
Date: Wed, 22 Jul 2020 18:07:45 -0500
Subject: adding buttons

---
 src/client/views/PropertiesButtons.scss            | 105 ++++++++
 src/client/views/PropertiesButtons.tsx             | 296 +++++++++++++++++++++
 src/client/views/collections/CollectionView.tsx    |   2 +
 .../collectionFreeForm/PropertiesView.scss         |  12 +
 .../collectionFreeForm/PropertiesView.tsx          |   8 +-
 5 files changed, 421 insertions(+), 2 deletions(-)
 create mode 100644 src/client/views/PropertiesButtons.scss
 create mode 100644 src/client/views/PropertiesButtons.tsx

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/PropertiesButtons.scss b/src/client/views/PropertiesButtons.scss
new file mode 100644
index 000000000..8dd5cec03
--- /dev/null
+++ b/src/client/views/PropertiesButtons.scss
@@ -0,0 +1,105 @@
+@import "globalCssVariables";
+
+$linkGap : 3px;
+
+.propertiesButtons-linkFlyout {
+    grid-column: 2/4;
+}
+
+.propertiesButtons-linkButton-empty:hover {
+    background: $main-accent;
+    transform: scale(1.05);
+    cursor: pointer;
+}
+
+.propertiesButtons-linkButton-nonempty:hover {
+    background: $main-accent;
+    transform: scale(1.05);
+    cursor: pointer;
+}
+
+.propertiesButtons-linkButton-empty,
+.propertiesButtons-linkButton-nonempty {
+    height: 20px;
+    width: 20px;
+    border-radius: 50%;
+    opacity: 0.9;
+    pointer-events: auto;
+    background-color: $dark-color;
+    color: $light-color;
+    text-transform: uppercase;
+    letter-spacing: 2px;
+    font-size: 75%;
+    transition: transform 0.2s;
+    text-align: center;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+
+    &:hover {
+        background: $main-accent;
+        transform: scale(1.05);
+        cursor: pointer;
+    }
+}
+
+.propertiesButtons {
+    margin-top: $linkGap;
+    grid-column: 1/4;
+    width: max-content;
+    height: auto;
+    display: flex;
+    flex-direction: row;
+}
+
+.propertiesButtons-button {
+    pointer-events: auto;
+    padding-right: 5px;
+    width: 25px;
+}
+
+.propertiesButtons-linker {
+    height: 20px;
+    width: 20px;
+    text-align: center;
+    border-radius: 50%;
+    pointer-events: auto;
+    color: $dark-color;
+    border: $dark-color 1px solid;
+    transition: 0.2s ease all;
+}
+
+.propertiesButtons-linker:hover {
+    cursor: pointer;
+    transform: scale(1.05);
+}
+
+
+@-moz-keyframes spin {
+    100% {
+        -moz-transform: rotate(360deg);
+    }
+}
+
+@-webkit-keyframes spin {
+    100% {
+        -webkit-transform: rotate(360deg);
+    }
+}
+
+@keyframes spin {
+    100% {
+        -webkit-transform: rotate(360deg);
+        transform: rotate(360deg);
+    }
+}
+
+@keyframes shadow-pulse {
+    0% {
+        box-shadow: 0 0 0 0px rgba(0, 0, 0, 0.8);
+    }
+
+    100% {
+        box-shadow: 0 0 0 10px rgba(0, 255, 0, 0);
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
new file mode 100644
index 000000000..842d0320f
--- /dev/null
+++ b/src/client/views/PropertiesButtons.tsx
@@ -0,0 +1,296 @@
+import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
+import { faArrowAltCircleDown, faArrowAltCircleRight, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faPhotoVideo, faShare, faStopCircle, faSyncAlt, faTag, faTimes } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action, computed, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import { Doc, DocListCast } from "../../fields/Doc";
+import { RichTextField } from '../../fields/RichTextField';
+import { Cast, NumCast } from "../../fields/Types";
+import { emptyFunction, setupMoveUpEvents } from "../../Utils";
+import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
+import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils';
+import { Docs, DocUtils } from '../documents/Documents';
+import { DragManager } from '../util/DragManager';
+import { CollectionDockingView, DockedFrameRenderer } from './collections/CollectionDockingView';
+import { ParentDocSelector } from './collections/ParentDocumentSelector';
+import './collections/ParentDocumentSelector.scss';
+import './PropertiesButtons.scss';
+import { MetadataEntryMenu } from './MetadataEntryMenu';
+import { DocumentView } from './nodes/DocumentView';
+import { GoogleRef } from "./nodes/formattedText/FormattedTextBox";
+import { TemplateMenu } from "./TemplateMenu";
+import { Template, Templates } from "./Templates";
+import React = require("react");
+import { Tooltip } from '@material-ui/core';
+const higflyout = require("@hig/flyout");
+export const { anchorPoints } = higflyout;
+export const Flyout = higflyout.default;
+
+library.add(faLink);
+library.add(faTag);
+library.add(faTimes);
+library.add(faArrowAltCircleDown);
+library.add(faArrowAltCircleUp);
+library.add(faArrowAltCircleRight);
+library.add(faStopCircle);
+library.add(faCheckCircle);
+library.add(faCloudUploadAlt);
+library.add(faSyncAlt);
+library.add(faShare);
+library.add(faPhotoVideo);
+
+const cloud: IconProp = "cloud-upload-alt";
+const fetch: IconProp = "sync-alt";
+
+enum UtilityButtonState {
+    Default,
+    OpenRight,
+    OpenExternally
+}
+
+@observer
+export class PropertiesButtons extends React.Component<{ doc: Doc }, {}> {
+    private _dragRef = React.createRef<HTMLDivElement>();
+    private _pullAnimating = false;
+    private _pushAnimating = false;
+    private _pullColorAnimating = false;
+
+    @observable private pushIcon: IconProp = "arrow-alt-circle-up";
+    @observable private pullIcon: IconProp = "arrow-alt-circle-down";
+    @observable private pullColor: string = "white";
+    @observable public isAnimatingFetch = false;
+    @observable public isAnimatingPulse = false;
+
+    @observable private openHover: UtilityButtonState = UtilityButtonState.Default;
+
+    @observable public static Instance: PropertiesButtons;
+    public static hasPushedHack = false;
+    public static hasPulledHack = false;
+
+    public startPullOutcome = action((success: boolean) => {
+        if (!this._pullAnimating) {
+            this._pullAnimating = true;
+            this.pullIcon = success ? "check-circle" : "stop-circle";
+            setTimeout(() => runInAction(() => {
+                this.pullIcon = "arrow-alt-circle-down";
+                this._pullAnimating = false;
+            }), 1000);
+        }
+    });
+
+    public startPushOutcome = action((success: boolean) => {
+        this.isAnimatingPulse = false;
+        if (!this._pushAnimating) {
+            this._pushAnimating = true;
+            this.pushIcon = success ? "check-circle" : "stop-circle";
+            setTimeout(() => runInAction(() => {
+                this.pushIcon = "arrow-alt-circle-up";
+                this._pushAnimating = false;
+            }), 1000);
+        }
+    });
+
+    public setPullState = action((unchanged: boolean) => {
+        this.isAnimatingFetch = false;
+        if (!this._pullColorAnimating) {
+            this._pullColorAnimating = true;
+            this.pullColor = unchanged ? "lawngreen" : "red";
+            setTimeout(this.clearPullColor, 1000);
+        }
+    });
+
+    private clearPullColor = action(() => {
+        this.pullColor = "white";
+        this._pullColorAnimating = false;
+    });
+
+    //get view0() { return this.props.views()?.[0]; }
+
+    @computed
+    get considerGoogleDocsPush() {
+        const targetDoc = this.props.doc;
+        const published = targetDoc && Doc.GetProto(targetDoc)[GoogleRef] !== undefined;
+        const animation = this.isAnimatingPulse ? "shadow-pulse 1s linear infinite" : "none";
+        return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{`${published ? "Push" : "Publish"} to Google Docs`}</div></>}>
+            <div
+                className="propertiesButtons-linker"
+                style={{ animation }}
+                onClick={async () => {
+                    await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken();
+                    !published && runInAction(() => this.isAnimatingPulse = true);
+                    PropertiesButtons.hasPushedHack = false;
+                    targetDoc[Pushes] = NumCast(targetDoc[Pushes]) + 1;
+                }}>
+                <FontAwesomeIcon className="documentdecorations-icon" icon={published ? (this.pushIcon as any) : cloud} size={published ? "sm" : "xs"} />
+            </div></Tooltip>;
+    }
+
+    @computed
+    get considerGoogleDocsPull() {
+        const targetDoc = this.props.doc;
+        const dataDoc = targetDoc && Doc.GetProto(targetDoc);
+        const animation = this.isAnimatingFetch ? "spin 0.5s linear infinite" : "none";
+
+        const title = (() => {
+            switch (this.openHover) {
+                default:
+                case UtilityButtonState.Default: return `${!dataDoc?.unchanged ? "Pull from" : "Fetch"} Google Docs`;
+                case UtilityButtonState.OpenRight: return "Open in Right Split";
+                case UtilityButtonState.OpenExternally: return "Open in new Browser Tab";
+            }
+        })();
+
+        return !targetDoc || !dataDoc || !dataDoc[GoogleRef] ? (null) : <Tooltip
+            title={<><div className="dash-tooltip">{title}</div></>}>
+            <div className="propertiesButtons-linker"
+                style={{ backgroundColor: this.pullColor }}
+                onPointerEnter={action(e => {
+                    if (e.altKey) {
+                        this.openHover = UtilityButtonState.OpenExternally;
+                    } else if (e.shiftKey) {
+                        this.openHover = UtilityButtonState.OpenRight;
+                    }
+                })}
+                onPointerLeave={action(() => this.openHover = UtilityButtonState.Default)}
+                onClick={async e => {
+                    const googleDocUrl = `https://docs.google.com/document/d/${dataDoc[GoogleRef]}/edit`;
+                    if (e.shiftKey) {
+                        e.preventDefault();
+                        let googleDoc = await Cast(dataDoc.googleDoc, Doc);
+                        if (!googleDoc) {
+                            const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false, UseCors: false };
+                            googleDoc = Docs.Create.WebDocument(googleDocUrl, options);
+                            dataDoc.googleDoc = googleDoc;
+                        }
+                        CollectionDockingView.AddRightSplit(googleDoc);
+                    } else if (e.altKey) {
+                        e.preventDefault();
+                        window.open(googleDocUrl);
+                    } else {
+                        this.clearPullColor();
+                        PropertiesButtons.hasPulledHack = false;
+                        targetDoc[Pulls] = NumCast(targetDoc[Pulls]) + 1;
+                        dataDoc.unchanged && runInAction(() => this.isAnimatingFetch = true);
+                    }
+                }}>
+                <FontAwesomeIcon className="documentdecorations-icon" size="sm"
+                    style={{ WebkitAnimation: animation, MozAnimation: animation }}
+                    icon={(() => {
+                        switch (this.openHover) {
+                            default:
+                            case UtilityButtonState.Default: return dataDoc.unchanged === false ? (this.pullIcon as any) : fetch;
+                            case UtilityButtonState.OpenRight: return "arrow-alt-circle-right";
+                            case UtilityButtonState.OpenExternally: return "share";
+                        }
+                    })()}
+                />
+            </div></Tooltip>;
+    }
+    @computed
+    get pinButton() {
+        const targetDoc = this.props.doc;
+        const isPinned = targetDoc && Doc.isDocPinned(targetDoc);
+        return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div></>}>
+            <div className="propertiesButtons-linker"
+                style={{ backgroundColor: isPinned ? "black" : "white", color: isPinned ? "white" : "black" }}
+                onClick={e => DockedFrameRenderer.PinDoc(targetDoc, isPinned)}>
+                <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin"
+                />
+            </div></Tooltip>;
+    }
+
+    @computed
+    get metadataButton() {
+        //const view0 = this.view0;
+        return <Tooltip title={<><div className="dash-tooltip">Show metadata panel</div></>}>
+            <div className="propertiesButtons-linkFlyout">
+                <Flyout anchorPoint={anchorPoints.LEFT_TOP}
+                    content={<MetadataEntryMenu docs={[this.props.doc]} suggestWithFunction />  /* tfs: @bcz This might need to be the data document? */}>
+                    <div className={"propertiesButtons-linkButton-" + "empty"} onPointerDown={e => e.stopPropagation()} >
+                        {<FontAwesomeIcon className="documentdecorations-icon" icon="tag" size="sm" />}
+                    </div>
+                </Flyout>
+            </div></Tooltip>;
+    }
+
+    // @computed
+    // get contextButton() {
+    //     return <ParentDocSelector Document={this.Document} addDocTab={(doc, where) => {
+    //         where === "onRight" ? CollectionDockingView.AddRightSplit(doc) :
+    //                 this.props.doc.props.addDocTab(doc, "onRight");
+    //         return true;
+    //     }} />;
+    // }
+
+    @observable _aliasDown = false;
+    onAliasButtonDown = (e: React.PointerEvent): void => {
+        //setupMoveUpEvents(this, e, this.onAliasButtonMoved, emptyFunction, emptyFunction);
+
+    }
+
+    // onAliasButtonMoved = () => {
+    //     if (this._dragRef.current) {
+    //         const dragDocView = this.props.doc!;
+    //         if (dragDocView.props){
+    //             const dragData = new DragManager.DocumentDragData([dragDocView.props.Document]);
+    //             const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+    //             dragData.dropAction = "alias";
+    //             DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, left, top, {
+    //             offsetX: dragData.offset[0],
+    //             offsetY: dragData.offset[1],
+    //             hideSource: false
+    //         });
+    //         return true;
+    //         }
+
+    //     }
+    //     return false;
+    // }
+
+    // @computed
+    // get templateButton() {
+    //     //const view0 = this.view0;
+    //     const templates: Map<Template, boolean> = new Map();
+    //     //const views = this.props.views();
+    //     Array.from(Object.values(Templates.TemplateList)).map(template =>
+    //         templates.set(template, views.reduce((checked, doc) => checked || doc?.props.Document["_show" + template.Name] ? true : false, false as boolean)));
+    //     return !this.props.doc ? (null) :
+    //         <Tooltip title={<><div className="dash-tooltip">Tap: Customize layout.  Drag: Create alias</div></>}>
+    //             <div className="propertiesButtons-linkFlyout" ref={this._dragRef}>
+    //                 <Flyout anchorPoint={anchorPoints.LEFT_TOP} onOpen={action(() => this._aliasDown = true)} onClose={action(() => this._aliasDown = false)}
+    //                     content={!this._aliasDown ? (null) : <TemplateMenu docViews={views.filter(v => v).map(v => v as DocumentView)} templates={templates} />}>
+    //                     <div className={"propertiesButtons-linkButton-empty"} ref={this._dragRef} onPointerDown={this.onAliasButtonDown} >
+    //                         {<FontAwesomeIcon className="documentdecorations-icon" icon="edit" size="sm" />}
+    //                     </div>
+    //                 </Flyout>
+    //             </div></Tooltip>;
+    // }
+
+    render() {
+        if (!this.props.doc) return (null);
+
+        const isText = this.props.doc[Doc.LayoutFieldKey(this.props.doc)] instanceof RichTextField;
+        const considerPull = isText && this.considerGoogleDocsPull;
+        const considerPush = isText && this.considerGoogleDocsPush;
+        return <div className="propertiesButtons">
+            {/* <div className="propertiesButtons-button">
+                {this.templateButton}
+            </div> */}
+            <div className="propertiesButtons-button">
+                {this.metadataButton}
+            </div>
+            {/* <div className="propertiesButtons-button">
+                {this.contextButton}
+            </div> */}
+            <div className="propertiesButtons-button">
+                {this.pinButton}
+            </div>
+            <div className="propertiesButtons-button" style={{ display: !considerPush ? "none" : "" }}>
+                {this.considerGoogleDocsPush}
+            </div>
+            <div className="propertiesButtons-button" style={{ display: !considerPull ? "none" : "" }}>
+                {this.considerGoogleDocsPull}
+            </div>
+        </div>;
+    }
+}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index eec68f9fc..853321d3c 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -50,6 +50,7 @@ import './CollectionView.scss';
 import CollectionMenu from './CollectionMenu';
 import { SharingPermissions } from '../../util/SharingManager';
 import { PropertiesView } from './collectionFreeForm/PropertiesView';
+import { DocumentView } from '../nodes/DocumentView';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -589,6 +590,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 overflow: this.propertiesWidth() < 15 ? "hidden" : undefined
             }}>
                 <PropertiesView dataDoc={this.dataDoc} Document={this.props.Document}
+                    docView={CollectionView as unknown as DocumentView}
                     width={this._propertiesWidth}
                     height={this.props.PanelHeight()}
                     renderDepth={this.props.renderDepth}
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.scss b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
index e81b1eeb4..98eae1ac7 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.scss
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
@@ -28,6 +28,18 @@
         padding: 8.5px;
         font-size: 12.5px;
         font-weight: bold;
+
+        .propertiesView-settings-title {
+            font-weight: bold;
+            font-size: 12.5px;
+            padding-bottom: 7px;
+        }
+
+        .propertiesView-settings-content {
+            margin-left: 5px;
+            padding-bottom: 10px;
+        }
+
     }
 
     .propertiesView-fields {
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index 27b0dbd9e..5242aa8fd 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -13,6 +13,7 @@ import { ContentFittingDocumentView } from "../../nodes/ContentFittingDocumentVi
 import { returnFalse, returnOne, emptyFunction, emptyPath, returnTrue, returnZero, returnEmptyFilter, Utils } from "../../../../Utils";
 import { Id } from "../../../../fields/FieldSymbols";
 import { Transform } from "../../../util/Transform";
+import { PropertiesButtons } from "../../PropertiesButtons";
 
 
 interface PropertiesViewProps {
@@ -22,7 +23,7 @@ interface PropertiesViewProps {
     height: number;
     renderDepth: number;
     ScreenToLocalTransform: () => Transform;
-    //docView: DocumentView;
+    docView: DocumentView;
 }
 
 @observer
@@ -125,7 +126,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 Collection
             </div>
             <div className="propertiesView-settings">
-                Settings
+                <div className="propertiesView-settings-title"> Settings</div>
+                <div className="propertiesView-settings-content">
+                    <PropertiesButtons doc={this.props.Document} />
+                </div>
             </div>
             <div className="propertiesView-fields">
                 <div className="propertiesView-fields-title"> Fields</div>
-- 
cgit v1.2.3-70-g09d2


From 831fbc76ec1c6e9829da547cdef791ac087677d9 Mon Sep 17 00:00:00 2001
From: anika-ahluwalia <anika.ahluwalia@gmail.com>
Date: Thu, 23 Jul 2020 11:08:54 -0500
Subject: moved right panel into mainview

---
 src/client/util/SelectionManager.ts                |  24 +++
 src/client/views/MainView.scss                     |  38 ++++
 src/client/views/MainView.tsx                      |  65 ++++++-
 src/client/views/PropertiesButtons.tsx             |  39 +++--
 src/client/views/collections/CollectionView.scss   |  34 ----
 src/client/views/collections/CollectionView.tsx    |  49 +-----
 .../collectionFreeForm/PropertiesView.tsx          | 193 +++++++++++++--------
 7 files changed, 262 insertions(+), 180 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 9a968aeda..6fb758eac 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -12,9 +12,14 @@ export namespace SelectionManager {
 
         @observable IsDragging: boolean = false;
         SelectedDocuments: ObservableMap<DocumentView, boolean> = new ObservableMap();
+
+        @observable public lastSelection: DocumentView | undefined;
+
         @action
         SelectDoc(docView: DocumentView, ctrlPressed: boolean): void {
 
+            this.lastSelection = docView;
+
             // if doc is not in SelectedDocuments, add it
             if (!manager.SelectedDocuments.get(docView)) {
                 if (!ctrlPressed) {
@@ -33,6 +38,15 @@ export namespace SelectionManager {
         }
         @action
         DeselectDoc(docView: DocumentView): void {
+
+            if (this.lastSelection === docView) {
+                const list = Array.from(manager.SelectedDocuments.keys());
+                if (list.length > 0) {
+                    this.lastSelection = list[list.length - 1];
+                } else {
+                    this.lastSelection = undefined;
+                }
+            }
             if (manager.SelectedDocuments.get(docView)) {
                 manager.SelectedDocuments.delete(docView);
                 docView.props.whenActiveChanged(false);
@@ -41,10 +55,16 @@ export namespace SelectionManager {
         }
         @action
         DeselectAll(): void {
+            this.lastSelection = undefined;
             Array.from(manager.SelectedDocuments.keys()).map(dv => dv.props.whenActiveChanged(false));
             manager.SelectedDocuments.clear();
             Doc.UserDoc().activeSelection = new List<Doc>([]);
         }
+
+        @action
+        getLast(): DocumentView | undefined {
+            return this.lastSelection;
+        }
     }
 
     const manager = new Manager();
@@ -56,6 +76,10 @@ export namespace SelectionManager {
         manager.SelectDoc(docView, ctrlPressed);
     }
 
+    export function LastSelection(): DocumentView | undefined {
+        return manager.getLast();
+    }
+
     // computed functions, such as used in IsSelected generate errors if they're called outside of a
     // reaction context.  Specifying the context with 'outsideReaction' allows an efficiency feature
     // to avoid unnecessary mobx invalidations when running inside a reaction.
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index 55280b231..f64129600 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -102,6 +102,44 @@
     user-select: none;
 }
 
+.mainView-propertiesDragger {
+    background-color: rgb(140, 139, 139);
+    height: 55px;
+    width: 15.5px;
+    position: absolute;
+    top: 55%;
+    border: 1px black solid;
+    border-radius: 0;
+    border-top-left-radius: 10px;
+    border-bottom-left-radius: 10px;
+    border-right: unset;
+    z-index: 2;
+
+    .mainView-propertiesDragger-icon {
+        width: 10px;
+        height: 10px;
+        float: left;
+        margin-left: 3px;
+        padding-top: 19px;
+    }
+
+    &:hover {
+        cursor: pointer;
+    }
+}
+
+.mainiView-propertiesView {
+    display: flex;
+    flex-direction: column;
+    width: 200px;
+    height: 100%;
+    position: absolute;
+    right: 0;
+    top: 0;
+    border-left: solid 1px;
+    z-index: 10;
+}
+
 .mainView-flyoutContainer {
     display: flex;
     flex-direction: column;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 766626a82..88f072493 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -21,10 +21,10 @@ import { Doc, DocListCast, Field, Opt } from '../../fields/Doc';
 import { Id } from '../../fields/FieldSymbols';
 import { List } from '../../fields/List';
 import { listSpec } from '../../fields/Schema';
-import { BoolCast, Cast, FieldValue, StrCast } from '../../fields/Types';
+import { BoolCast, Cast, FieldValue, StrCast, NumCast } from '../../fields/Types';
 import { TraceMobx } from '../../fields/util';
 import { CurrentUserUtils } from '../util/CurrentUserUtils';
-import { emptyFunction, emptyPath, returnFalse, returnOne, returnZero, returnTrue, Utils, returnEmptyFilter } from '../../Utils';
+import { emptyFunction, emptyPath, returnFalse, returnOne, returnZero, returnTrue, Utils, returnEmptyFilter, setupMoveUpEvents } from '../../Utils';
 import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
 import { DocServer } from '../DocServer';
 import { Docs, DocumentOptions } from '../documents/Documents';
@@ -66,7 +66,9 @@ import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup';
 import FormatShapePane from "./collections/collectionFreeForm/FormatShapePane";
 import HypothesisAuthenticationManager from '../apis/HypothesisAuthenticationManager';
 import CollectionMenu from './collections/CollectionMenu';
-import { Tooltip } from '@material-ui/core';
+import { Tooltip, AccordionActions } from '@material-ui/core';
+import { PropertiesView } from './collections/collectionFreeForm/PropertiesView';
+import { SelectionManager } from '../util/SelectionManager';
 
 @observer
 export class MainView extends React.Component {
@@ -90,9 +92,24 @@ export class MainView extends React.Component {
 
     @observable public sidebarContent: any = this.userDoc?.["tabs-panelContainer"];
     @observable public panelContent: string = "none";
+    @observable public showProperties: boolean = false;
 
+    @computed get selectedDocumentView() { return SelectionManager.LastSelection(); }
+    @observable selectedDoc: Doc | undefined = this.selectedDocumentView?.props.Document;
+    @observable selectedDataDoc: Doc | undefined = this.selectedDocumentView?.props.DataDoc ? this.selectedDocumentView.props.DataDoc : this.selectedDoc;
     public isPointerDown = false;
 
+    @observable _propertiesWidth: number = 0;
+    propertiesWidth = () => Math.max(0, Math.min(this._panelWidth - 50, this._propertiesWidth));
+
+    @computed get propertiesIcon() {
+        if (this.propertiesWidth() < 10) {
+            return "chevron-left";
+        } else {
+            return "chevron-right";
+        }
+    }
+
     componentDidMount() {
         DocServer.setPlaygroundFields(["dataTransition", "_viewTransition", "_panX", "_panY", "_viewScale", "_viewType", "_chromeStatus"]); // can play with these fields on someone else's
 
@@ -216,7 +233,7 @@ export class MainView extends React.Component {
         const freeformOptions: DocumentOptions = {
             x: 0,
             y: 400,
-            _width: this._panelWidth * .7,
+            _width: this._panelWidth * .7 - this._propertiesWidth,
             _height: this._panelHeight,
             title: "Collection " + workspaceCount,
         };
@@ -282,10 +299,13 @@ export class MainView extends React.Component {
 
     @action
     onResize = (r: any) => {
-        this._panelWidth = r.offset.width;
+        this._panelWidth = r.offset.width - this._propertiesWidth;
         this._panelHeight = r.offset.height;
     }
-    getPWidth = () => this._panelWidth;
+
+    @action
+    getPWidth = () => this._panelWidth - this._propertiesWidth;
+
     getPHeight = () => this._panelHeight;
     getContentsHeight = () => this._panelHeight - this._buttonBarHeight;
 
@@ -329,7 +349,6 @@ export class MainView extends React.Component {
             NativeWidth={returnZero}
             PanelWidth={this.getPWidth}
             PanelHeight={this.getPHeight}
-            renderDepth={0}
             focus={emptyFunction}
             parentActive={returnTrue}
             whenActiveChanged={emptyFunction}
@@ -570,6 +589,30 @@ export class MainView extends React.Component {
         }
     }
 
+    @action
+    onDown = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
+            this._propertiesWidth = this._panelWidth - Math.max(Transform.Identity().transformPoint(e.clientX, 0)[0], 0);
+            return false;
+        }), returnFalse, action(() => this._propertiesWidth = this.propertiesWidth() < 15 ? Math.min(this._panelWidth - 50, 200) : 0), false);
+    }
+
+    @computed get propertiesView() {
+        TraceMobx();
+        return this._propertiesWidth === 0 ? (null) :
+            <div className="mainView-propertiesView" style={{
+                width: `${this.propertiesWidth()}px`,
+                overflow: this.propertiesWidth() < 15 ? "hidden" : undefined
+            }}>
+                <PropertiesView
+                    width={this._propertiesWidth}
+                    height={this._panelHeight}
+                    renderDepth={1}
+                    ScreenToLocalTransform={Transform.Identity}
+                />
+            </div>;
+    }
+
     @computed get mainContent() {
         const n = (RichTextMenu.Instance?.Pinned ? 1 : 0) + (CollectionMenu.Instance?.Pinned ? 1 : 0);
         const height = `calc(100% - ${n * Number(ANTIMODEMENU_HEIGHT.replace("px", ""))}px)`;
@@ -606,6 +649,14 @@ export class MainView extends React.Component {
                         </div>
                     </div>
                     {this.dockingContent}
+                    {this.showProperties ? (null) :
+                        <div className="mainView-propertiesDragger" title="Properties View Dragger" onPointerDown={this.onDown}
+                            style={{ right: this._propertiesWidth - 1, top: "45%" }}>
+                            <div className="mainView-propertiesDragger-icon">
+                                <FontAwesomeIcon icon={this.propertiesIcon} color="white" size="sm" /> </div>
+                        </div>
+                    }
+                    {this.propertiesWidth() < 10 ? (null) : this.propertiesView}
                 </div>
             </div>);
     }
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 842d0320f..1b06a41fa 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -22,6 +22,7 @@ import { TemplateMenu } from "./TemplateMenu";
 import { Template, Templates } from "./Templates";
 import React = require("react");
 import { Tooltip } from '@material-ui/core';
+import { SelectionManager } from '../util/SelectionManager';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -49,7 +50,7 @@ enum UtilityButtonState {
 }
 
 @observer
-export class PropertiesButtons extends React.Component<{ doc: Doc }, {}> {
+export class PropertiesButtons extends React.Component<{}, {}> {
     private _dragRef = React.createRef<HTMLDivElement>();
     private _pullAnimating = false;
     private _pushAnimating = false;
@@ -67,6 +68,9 @@ export class PropertiesButtons extends React.Component<{ doc: Doc }, {}> {
     public static hasPushedHack = false;
     public static hasPulledHack = false;
 
+    @observable selectedDocumentView: DocumentView | undefined = SelectionManager.LastSelection();
+    @observable selectedDoc: Doc | undefined = this.selectedDocumentView?.props.Document;
+
     public startPullOutcome = action((success: boolean) => {
         if (!this._pullAnimating) {
             this._pullAnimating = true;
@@ -108,7 +112,7 @@ export class PropertiesButtons extends React.Component<{ doc: Doc }, {}> {
 
     @computed
     get considerGoogleDocsPush() {
-        const targetDoc = this.props.doc;
+        const targetDoc = this.selectedDoc;
         const published = targetDoc && Doc.GetProto(targetDoc)[GoogleRef] !== undefined;
         const animation = this.isAnimatingPulse ? "shadow-pulse 1s linear infinite" : "none";
         return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{`${published ? "Push" : "Publish"} to Google Docs`}</div></>}>
@@ -127,7 +131,7 @@ export class PropertiesButtons extends React.Component<{ doc: Doc }, {}> {
 
     @computed
     get considerGoogleDocsPull() {
-        const targetDoc = this.props.doc;
+        const targetDoc = this.selectedDoc;
         const dataDoc = targetDoc && Doc.GetProto(targetDoc);
         const animation = this.isAnimatingFetch ? "spin 0.5s linear infinite" : "none";
 
@@ -188,7 +192,7 @@ export class PropertiesButtons extends React.Component<{ doc: Doc }, {}> {
     }
     @computed
     get pinButton() {
-        const targetDoc = this.props.doc;
+        const targetDoc = this.selectedDoc;
         const isPinned = targetDoc && Doc.isDocPinned(targetDoc);
         return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div></>}>
             <div className="propertiesButtons-linker"
@@ -202,15 +206,20 @@ export class PropertiesButtons extends React.Component<{ doc: Doc }, {}> {
     @computed
     get metadataButton() {
         //const view0 = this.view0;
-        return <Tooltip title={<><div className="dash-tooltip">Show metadata panel</div></>}>
-            <div className="propertiesButtons-linkFlyout">
-                <Flyout anchorPoint={anchorPoints.LEFT_TOP}
-                    content={<MetadataEntryMenu docs={[this.props.doc]} suggestWithFunction />  /* tfs: @bcz This might need to be the data document? */}>
-                    <div className={"propertiesButtons-linkButton-" + "empty"} onPointerDown={e => e.stopPropagation()} >
-                        {<FontAwesomeIcon className="documentdecorations-icon" icon="tag" size="sm" />}
-                    </div>
-                </Flyout>
-            </div></Tooltip>;
+        if (this.selectedDoc) {
+            return <Tooltip title={<><div className="dash-tooltip">Show metadata panel</div></>}>
+                <div className="propertiesButtons-linkFlyout">
+                    <Flyout anchorPoint={anchorPoints.LEFT_TOP}
+                        content={<MetadataEntryMenu docs={[this.selectedDoc]} suggestWithFunction />  /* tfs: @bcz This might need to be the data document? */}>
+                        <div className={"propertiesButtons-linkButton-" + "empty"} onPointerDown={e => e.stopPropagation()} >
+                            {<FontAwesomeIcon className="documentdecorations-icon" icon="tag" size="sm" />}
+                        </div>
+                    </Flyout>
+                </div></Tooltip>;
+        } else {
+            return null;
+        }
+
     }
 
     // @computed
@@ -267,9 +276,9 @@ export class PropertiesButtons extends React.Component<{ doc: Doc }, {}> {
     // }
 
     render() {
-        if (!this.props.doc) return (null);
+        if (!this.selectedDoc) return (null);
 
-        const isText = this.props.doc[Doc.LayoutFieldKey(this.props.doc)] instanceof RichTextField;
+        const isText = this.selectedDoc[Doc.LayoutFieldKey(this.selectedDoc)] instanceof RichTextField;
         const considerPull = isText && this.considerGoogleDocsPull;
         const considerPush = isText && this.considerGoogleDocsPush;
         return <div className="propertiesButtons">
diff --git a/src/client/views/collections/CollectionView.scss b/src/client/views/collections/CollectionView.scss
index 585f6865e..a5aef86de 100644
--- a/src/client/views/collections/CollectionView.scss
+++ b/src/client/views/collections/CollectionView.scss
@@ -25,40 +25,6 @@
         z-index: 2;
     }
 
-    .collectionView-propertiesDragger {
-        background-color: rgb(140, 139, 139);
-        height: 55px;
-        width: 15.5px;
-        position: absolute;
-        top: 55%;
-        border: 1px black solid;
-        border-radius: 0;
-        border-top-left-radius: 10px;
-        border-bottom-left-radius: 10px;
-        border-right: unset;
-        z-index: 2;
-
-        .collectionView-propertiesDragger-icon {
-            width: 10px;
-            height: 10px;
-            float: left;
-            margin-left: 3px;
-            padding-top: 19px;
-        }
-    }
-
-    .collectionView-propertiesView {
-        display: flex;
-        flex-direction: column;
-        width: 200px;
-        height: 100%;
-        position: absolute;
-        right: 0;
-        top: 0;
-        border-left: solid 1px;
-        z-index: 10;
-    }
-
     .collectionTimeView-treeView {
         display: flex;
         flex-direction: column;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 853321d3c..19a82a113 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -49,7 +49,6 @@ import { CollectionTreeView } from "./CollectionTreeView";
 import './CollectionView.scss';
 import CollectionMenu from './CollectionMenu';
 import { SharingPermissions } from '../../util/SharingManager';
-import { PropertiesView } from './collectionFreeForm/PropertiesView';
 import { DocumentView } from '../nodes/DocumentView';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
@@ -369,22 +368,9 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
     get _facetWidth() { return NumCast(this.props.Document._facetWidth); }
     set _facetWidth(value) { this.props.Document._facetWidth = value; }
 
-    get _propertiesWidth() { return NumCast(this.props.Document._propertiesWidth); }
-    set _propertiesWidth(value) { this.props.Document._propertiesWidth = value; }
-
-    bodyPanelWidth = () => this.props.PanelWidth() - this.propertiesWidth();
+    bodyPanelWidth = () => this.props.PanelWidth();
     facetWidth = () => Math.max(0, Math.min(this.props.PanelWidth() - 25, this._facetWidth));
 
-    propertiesWidth = () => Math.max(0, Math.min(this.props.PanelWidth() - 25, this._propertiesWidth));
-
-    @computed get propertiesIcon() {
-        if (this.propertiesWidth() < 10) {
-            return "chevron-left";
-        } else {
-            return "chevron-right";
-        }
-    }
-
     @computed get dataDoc() {
         return (this.props.DataDoc && this.props.Document.isTemplateForField ? Doc.GetProto(this.props.DataDoc) :
             this.props.Document.resolvedDataDoc ? this.props.Document : Doc.GetProto(this.props.Document)); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template
@@ -505,13 +491,6 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
         }), returnFalse, action(() => this._facetWidth = this.facetWidth() < 15 ? Math.min(this.props.PanelWidth() - 25, 200) : 0), false);
     }
 
-    onDown = (e: React.PointerEvent) => {
-        setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
-            this._propertiesWidth = this.props.PanelWidth() - Math.max(this.props.ScreenToLocalTransform().transformPoint(e.clientX, 0)[0], 0);
-            return false;
-        }), returnFalse, action(() => this._propertiesWidth = this.propertiesWidth() < 15 ? Math.min(this.props.PanelWidth() - 25, 200) : 0), false);
-    }
-
     filterBackground = () => "rgba(105, 105, 105, 0.432)";
     get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; } // this makes the tree view collection ignore these filters (otherwise, the filters would filter themselves)
     @computed get scriptField() {
@@ -582,23 +561,6 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
             </div>;
     }
 
-    @computed get propertiesView() {
-        TraceMobx();
-        return !this._propertiesWidth || this.props.dontRegisterView ? (null) :
-            <div className="collectionView-propertiesView" style={{
-                width: `${this.propertiesWidth()}px`,
-                overflow: this.propertiesWidth() < 15 ? "hidden" : undefined
-            }}>
-                <PropertiesView dataDoc={this.dataDoc} Document={this.props.Document}
-                    docView={CollectionView as unknown as DocumentView}
-                    width={this._propertiesWidth}
-                    height={this.props.PanelHeight()}
-                    renderDepth={this.props.renderDepth}
-                    ScreenToLocalTransform={this.props.ScreenToLocalTransform}
-                />
-            </div>;
-    }
-
     childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null);
     childLayoutString = this.props.childLayoutString || StrCast(this.props.Document.childLayoutString);
 
@@ -634,15 +596,6 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                     style={{ right: this.facetWidth() - 1, top: this.props.Document._viewType === CollectionViewType.Docking ? "25%" : "55%" }} />
             }
             {this.facetWidth() < 10 ? (null) : this.filterView} */}
-
-            {this.props.hideFilter || this.props.Document.hideFilterView || !this.props.isSelected() && !this.props.Document.forceActive ? (null) :
-                <div className="collectionView-propertiesDragger" title="Properties View Dragger" onPointerDown={this.onDown}
-                    style={{ right: this.propertiesWidth() - 1, top: this.props.Document._viewType === CollectionViewType.Docking ? "25%" : "55%" }}>
-                    <div className="collectionView-propertiesDragger-icon">
-                        <FontAwesomeIcon icon={this.propertiesIcon} color="white" size="sm" /> </div>
-                </div>
-            }
-            {this.propertiesWidth() < 10 ? (null) : this.propertiesView}
         </div>);
     }
 }
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index 5242aa8fd..5aa0066d2 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -14,121 +14,162 @@ import { returnFalse, returnOne, emptyFunction, emptyPath, returnTrue, returnZer
 import { Id } from "../../../../fields/FieldSymbols";
 import { Transform } from "../../../util/Transform";
 import { PropertiesButtons } from "../../PropertiesButtons";
+import { SelectionManager } from "../../../util/SelectionManager";
 
 
 interface PropertiesViewProps {
-    dataDoc: Doc;
-    Document: Doc;
     width: number;
     height: number;
     renderDepth: number;
     ScreenToLocalTransform: () => Transform;
-    docView: DocumentView;
 }
 
 @observer
 export class PropertiesView extends React.Component<PropertiesViewProps> {
 
     @computed get MAX_EMBED_HEIGHT() { return 200; }
+    @observable numSelected: number = SelectionManager.SelectedDocuments().length;
+    @computed get selectedDocumentView() { return SelectionManager.LastSelection(); }
+    @observable selectedDoc: Doc | undefined = this.selectedDocumentView?.props.Document;
+    @observable dataDoc: Doc | undefined = this.selectedDocumentView?.props.DataDoc ? this.selectedDocumentView.props.DataDoc : this.selectedDoc;
 
-    rtfWidth = () => Math.min(this.props.Document?.[WidthSym](), this.props.width - 20);
-    rtfHeight = () => this.rtfWidth() <= this.props.Document?.[WidthSym]() ? Math.min(this.props.Document?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
+    @action
+    rtfWidth = () => {
+        if (this.selectedDoc) {
+            return Math.min(this.selectedDoc?.[WidthSym](), this.props.width - 20);
+        } else {
+            return 0;
+        }
+    }
+    @action
+    rtfHeight = () => {
+        if (this.selectedDoc) {
+            return this.rtfWidth() <= this.selectedDoc?.[WidthSym]() ? Math.min(this.selectedDoc?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
+        } else {
+            return 0;
+        }
+    }
 
+    @action
     docWidth = () => {
-        const layoutDoc = this.props.Document;
-        const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
-        if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.width - 20));
-        return NumCast(layoutDoc._nativeWidth) ? Math.min(layoutDoc[WidthSym](), this.props.width - 20) : this.props.width - 20;
+        if (this.selectedDoc) {
+            const layoutDoc = this.selectedDoc;
+            const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
+            if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.width - 20));
+            return NumCast(layoutDoc._nativeWidth) ? Math.min(layoutDoc[WidthSym](), this.props.width - 20) : this.props.width - 20;
+        } else {
+            return 0;
+        }
     }
+
+    @action
     docHeight = () => {
-        const layoutDoc = this.props.Document;
-        return Math.max(70, Math.min(this.MAX_EMBED_HEIGHT, (() => {
-            const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
-            if (aspect) return this.docWidth() * aspect;
-            return layoutDoc._fitWidth ? (!this.props.dataDoc._nativeHeight ? NumCast(this.props.height) :
-                Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, NumCast(layoutDoc._nativeHeight)) / NumCast(layoutDoc._nativeWidth,
-                    NumCast(this.props.height)))) :
-                NumCast(layoutDoc._height) ? NumCast(layoutDoc._height) : 50;
-        })()));
+        if (this.selectedDoc && this.dataDoc) {
+            const layoutDoc = this.selectedDoc;
+            return Math.max(70, Math.min(this.MAX_EMBED_HEIGHT, (() => {
+                const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
+                if (aspect) return this.docWidth() * aspect;
+                return layoutDoc._fitWidth ? (!this.dataDoc._nativeHeight ? NumCast(this.props.height) :
+                    Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, NumCast(layoutDoc._nativeHeight)) / NumCast(layoutDoc._nativeWidth,
+                        NumCast(this.props.height)))) :
+                    NumCast(layoutDoc._height) ? NumCast(layoutDoc._height) : 50;
+            })()));
+        } else {
+            return 0;
+        }
     }
 
     @computed get expandedField() {
-        const ids: { [key: string]: string } = {};
-        const doc = this.props.dataDoc;
-        doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
+        if (this.dataDoc) {
+            const ids: { [key: string]: string } = {};
+            const doc = this.dataDoc;
+            doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
 
-        const rows: JSX.Element[] = [];
-        for (const key of Object.keys(ids).slice().sort()) {
-            const contents = doc[key];
-            let contentElement: (JSX.Element | null)[] | JSX.Element = [];
-            contentElement = <EditableView key="editableView"
-                contents={contents !== undefined ? Field.toString(contents as Field) : "null"}
-                height={13}
-                fontSize={10}
-                GetValue={() => Field.toKeyValueString(doc, key)}
-                SetValue={(value: string) => KeyValueBox.SetField(doc, key, value, true)}
-            />;
+            const rows: JSX.Element[] = [];
+            for (const key of Object.keys(ids).slice().sort()) {
+                const contents = doc[key];
+                let contentElement: (JSX.Element | null)[] | JSX.Element = [];
+                contentElement = <EditableView key="editableView"
+                    contents={contents !== undefined ? Field.toString(contents as Field) : "null"}
+                    height={13}
+                    fontSize={10}
+                    GetValue={() => Field.toKeyValueString(doc, key)}
+                    SetValue={(value: string) => KeyValueBox.SetField(doc, key, value, true)}
+                />;
 
-            rows.push(<div style={{ display: "flex", overflowY: "visible", marginBottom: "-1px" }} key={key}>
-                <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key + ":"}</span>
-                &nbsp;
-                {contentElement}
-            </div>);
+                rows.push(<div style={{ display: "flex", overflowY: "visible", marginBottom: "-1px" }} key={key}>
+                    <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key + ":"}</span>
+                    &nbsp;
+                    {contentElement}
+                </div>);
+            }
+            return rows;
         }
-        return rows;
     }
 
     @computed get layoutPreview() {
-        const layoutDoc = Doc.Layout(this.props.Document);
-        const panelHeight = StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : this.docHeight;
-        const panelWidth = StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : this.docWidth;
-        return <div style={{ display: "inline-block", height: panelHeight() }} key={this.props.dataDoc[Id]}>
-            <ContentFittingDocumentView
-                Document={layoutDoc}
-                DataDoc={this.props.dataDoc}
-                LibraryPath={emptyPath}
-                renderDepth={this.props.renderDepth + 1}
-                rootSelected={returnFalse}
-                treeViewDoc={undefined}
-                backgroundColor={() => "lightgrey"}
-                fitToBox={false}
-                FreezeDimensions={true}
-                NativeWidth={layoutDoc.type ===
-                    StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : returnZero}
-                NativeHeight={layoutDoc.type ===
-                    StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : returnZero}
-                PanelWidth={panelWidth}
-                PanelHeight={panelHeight}
-                focus={returnFalse}
-                ScreenToLocalTransform={this.props.ScreenToLocalTransform}
-                docFilters={returnEmptyFilter}
-                ContainingCollectionDoc={undefined}
-                ContainingCollectionView={undefined}
-                addDocument={returnFalse}
-                moveDocument={undefined}
-                removeDocument={returnFalse}
-                parentActive={() => false}
-                whenActiveChanged={emptyFunction}
-                addDocTab={returnFalse}
-                pinToPres={emptyFunction}
-                bringToFront={returnFalse}
-                ContentScaling={returnOne}
-            />
-        </div>;
+        if (this.selectedDoc) {
+            const layoutDoc = Doc.Layout(this.selectedDoc);
+            const panelHeight = StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : this.docHeight;
+            const panelWidth = StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : this.docWidth;
+            return <div style={{ display: "inline-block", height: panelHeight() }} key={this.selectedDoc[Id]}>
+                <ContentFittingDocumentView
+                    Document={layoutDoc}
+                    DataDoc={this.dataDoc}
+                    LibraryPath={emptyPath}
+                    renderDepth={this.props.renderDepth + 1}
+                    rootSelected={returnFalse}
+                    treeViewDoc={undefined}
+                    backgroundColor={() => "lightgrey"}
+                    fitToBox={false}
+                    FreezeDimensions={true}
+                    NativeWidth={layoutDoc.type ===
+                        StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : returnZero}
+                    NativeHeight={layoutDoc.type ===
+                        StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : returnZero}
+                    PanelWidth={panelWidth}
+                    PanelHeight={panelHeight}
+                    focus={returnFalse}
+                    ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+                    docFilters={returnEmptyFilter}
+                    ContainingCollectionDoc={undefined}
+                    ContainingCollectionView={undefined}
+                    addDocument={returnFalse}
+                    moveDocument={undefined}
+                    removeDocument={returnFalse}
+                    parentActive={() => false}
+                    whenActiveChanged={emptyFunction}
+                    addDocTab={returnFalse}
+                    pinToPres={emptyFunction}
+                    bringToFront={returnFalse}
+                    ContentScaling={returnOne}
+                />
+            </div>;
+        } else {
+            return null;
+        }
     }
 
     render() {
+
+        if (!this.selectedDocumentView || !this.selectedDoc || !this.dataDoc) {
+            return <div className="propertiesView" >
+                <div className="propertiesView-title">
+                    No Document Selected
+            </div> </div>;
+        }
+
         return <div className="propertiesView" >
             <div className="propertiesView-title">
                 Properties
             </div>
             <div className="propertiesView-name">
-                Collection
+                {this.dataDoc.title}
             </div>
             <div className="propertiesView-settings">
                 <div className="propertiesView-settings-title"> Settings</div>
                 <div className="propertiesView-settings-content">
-                    <PropertiesButtons doc={this.props.Document} />
+                    <PropertiesButtons />
                 </div>
             </div>
             <div className="propertiesView-fields">
-- 
cgit v1.2.3-70-g09d2


From 8f250a359e957b01e281cfad1bd92043a2f1b165 Mon Sep 17 00:00:00 2001
From: anika-ahluwalia <anika.ahluwalia@gmail.com>
Date: Sat, 25 Jul 2020 10:49:33 -0500
Subject: merge fix

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

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 2ea391b19..2d360d13c 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -48,7 +48,7 @@ import { CollectionTimeView } from './CollectionTimeView';
 import { CollectionTreeView } from "./CollectionTreeView";
 import './CollectionView.scss';
 import CollectionMenu from './CollectionMenu';
-import { SharingPermissions } from '../../util/SharingManager';
+//import SharingPermissions from '../../util/SharingManager';
 import { DocumentView } from '../nodes/DocumentView';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 85e8409d1..bb1c43e6b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1041,7 +1041,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     @computed get contents() {
         const pos = this.props.relative ? "relative " : "absolute";
         TraceMobx();
-        return (<div style={{ position: pos, width: "100%", height: "100%" }}>
+        return (<div style={{ width: "100%", height: "100%" }}>
             <DocumentContentsView key={1}
                 docFilters={this.props.docFilters}
                 ContainingCollectionView={this.props.ContainingCollectionView}
-- 
cgit v1.2.3-70-g09d2


From f869c7a75eb6a2f6e6301aa76c57e383b41d3fea Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 27 Jul 2020 11:52:37 -0400
Subject: added hypothesis icon to toolbar. fixed toolbar to update to any
 document selection with specific items for each type.

---
 package-lock.json                                  |  15 ++
 package.json                                       |   1 +
 src/client/views/MainView.tsx                      |   5 +-
 src/client/views/collections/CollectionMenu.tsx    | 221 ++++++++++++---------
 src/client/views/collections/CollectionSubView.tsx |   4 +-
 src/client/views/collections/CollectionView.tsx    |   2 +-
 src/client/views/nodes/DocumentView.tsx            |   1 +
 7 files changed, 149 insertions(+), 100 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/package-lock.json b/package-lock.json
index 698bd60cc..51105842a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -301,6 +301,21 @@
                 "@fortawesome/fontawesome-common-types": "^0.2.29"
             }
         },
+        "@fortawesome/free-brands-svg-icons": {
+            "version": "5.14.0",
+            "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.14.0.tgz",
+            "integrity": "sha512-WsqPFTvJFI7MYkcy0jeFE2zY+blC4OrnB9MJOcn1NxRXT/sSfEEhrI7CwzIkiYajLiVDBKWeErYOvpsMeodmCQ==",
+            "requires": {
+                "@fortawesome/fontawesome-common-types": "^0.2.30"
+            },
+            "dependencies": {
+                "@fortawesome/fontawesome-common-types": {
+                    "version": "0.2.30",
+                    "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.30.tgz",
+                    "integrity": "sha512-TsRwpTuKwFNiPhk1UfKgw7zNPeV5RhNp2Uw3pws+9gDAkPGKrtjR1y2lI3SYn7+YzyfuNknflpBA1LRKjt7hMg=="
+                }
+            }
+        },
         "@fortawesome/free-regular-svg-icons": {
             "version": "5.13.1",
             "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.13.1.tgz",
diff --git a/package.json b/package.json
index 6c466825e..3b7b5f391 100644
--- a/package.json
+++ b/package.json
@@ -117,6 +117,7 @@
     },
     "dependencies": {
         "@fortawesome/fontawesome-svg-core": "^1.2.29",
+        "@fortawesome/free-brands-svg-icons": "^5.14.0",
         "@fortawesome/free-regular-svg-icons": "^5.13.1",
         "@fortawesome/free-solid-svg-icons": "^5.13.1",
         "@fortawesome/react-fontawesome": "^0.1.11",
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index ae3f05fb7..9fad612ee 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,5 +1,8 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 
+import {
+    faHireAHelper
+} from '@fortawesome/free-brands-svg-icons';
 import {
     faTasks, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus,
     faTerminal, faToggleOn, faFile as fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard,
@@ -150,7 +153,7 @@ export class MainView extends React.Component {
             faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faTrashAlt, faAngleRight, faBell,
             faThumbtack, faTree, faTv, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faArrowsAlt, faQuoteLeft, faSortAmountDown, faAlignLeft, faAlignCenter, faAlignRight,
             faHeading, faRulerCombined, faFillDrip, faLink, faUnlink, faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSuperscript, faSubscript, faIndent, faEyeDropper,
-            faPaintRoller, faBars, faBrush, faShapes, faEllipsisH, faHandPaper, faMap, faUser);
+            faPaintRoller, faBars, faBrush, faShapes, faEllipsisH, faHandPaper, faMap, faUser, faHireAHelper);
         this.initEventListeners();
         this.initAuthenticationRouters();
     }
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 24be69050..0b30b5a5f 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -30,16 +30,28 @@ import { ObjectField } from "../../../fields/ObjectField";
 export default class CollectionMenu extends AntimodeMenu {
     static Instance: CollectionMenu;
 
-    @observable SelectedCollection: CollectionView | undefined;
+    @observable SelectedCollection: DocumentView | undefined;
+    @observable FieldKey: string;
 
     constructor(props: Readonly<{}>) {
         super(props);
+        this.FieldKey = "";
         CollectionMenu.Instance = this;
         this._canFade = false; // don't let the inking menu fade away
         this.Pinned = Cast(Doc.UserDoc()["menuCollections-pinned"], "boolean", true);
         this.jumpTo(300, 300);
     }
 
+    componentDidMount() {
+        reaction(() => SelectionManager.SelectedDocuments().length && SelectionManager.SelectedDocuments()[0],
+            (doc) => doc && this.SetSelection(doc))
+    }
+
+    @action
+    SetSelection(view: DocumentView) {
+        this.SelectedCollection = view;
+    }
+
     @action
     toggleMenuPin = (e: React.MouseEvent) => {
         Doc.UserDoc()["menuCollections-pinned"] = this.Pinned = !this.Pinned;
@@ -54,14 +66,18 @@ export default class CollectionMenu extends AntimodeMenu {
         </button>;
 
         return this.getElement(!this.SelectedCollection ? [button] :
-            [<CollectionViewBaseChrome key="chrome" CollectionView={this.SelectedCollection} type={StrCast(this.SelectedCollection.props.Document._viewType) as CollectionViewType} />,
+            [<CollectionViewBaseChrome key="chrome"
+                docView={this.SelectedCollection}
+                fieldKey={Doc.LayoutFieldKey(this.SelectedCollection?.props.Document)}
+                type={StrCast(this.SelectedCollection?.props.Document._viewType, CollectionViewType.Invalid) as CollectionViewType} />,
                 button]);
     }
 }
 
 interface CollectionMenuProps {
-    CollectionView: CollectionView;
     type: CollectionViewType;
+    fieldKey: string;
+    docView: DocumentView;
 }
 
 const stopPropagation = (e: React.SyntheticEvent) => e.stopPropagation();
@@ -70,7 +86,8 @@ const stopPropagation = (e: React.SyntheticEvent) => e.stopPropagation();
 export class CollectionViewBaseChrome extends React.Component<CollectionMenuProps> {
     //(!)?\(\(\(doc.(\w+) && \(doc.\w+ as \w+\).includes\(\"(\w+)\"\)
 
-    get target() { return this.props.CollectionView.props.Document; }
+    get document() { return this.props.docView?.props.Document; }
+    get target() { return this.document; }
     _templateCommand = {
         params: ["target", "source"], title: "item view",
         script: "self.target.childLayoutTemplate = getDocTemplate(self.source?.[0])",
@@ -121,16 +138,16 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
     _tree_commands = [];
     private get _buttonizableCommands() {
         switch (this.props.type) {
+            default:
+            case CollectionViewType.Freeform: return this._freeform_commands;
             case CollectionViewType.Tree: return this._tree_commands;
             case CollectionViewType.Schema: return this._schema_commands;
             case CollectionViewType.Stacking: return this._stacking_commands;
             case CollectionViewType.Masonry: return this._stacking_commands;
-            case CollectionViewType.Freeform: return this._freeform_commands;
             case CollectionViewType.Time: return this._freeform_commands;
             case CollectionViewType.Carousel: return this._freeform_commands;
             case CollectionViewType.Carousel3D: return this._freeform_commands;
         }
-        return [];
     }
     private _picker: any;
     private _commandRef = React.createRef<HTMLInputElement>();
@@ -165,21 +182,16 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
 
     @computed get subChrome() {
         switch (this.props.type) {
-            case CollectionViewType.Freeform: return (<CollectionFreeFormViewChrome key="collchrome" CollectionView={this.props.CollectionView} type={this.props.type} />);
-            case CollectionViewType.Stacking: return (<CollectionStackingViewChrome key="collchrome" CollectionView={this.props.CollectionView} type={this.props.type} />);
-            case CollectionViewType.Schema: return (<CollectionSchemaViewChrome key="collchrome" CollectionView={this.props.CollectionView} type={this.props.type} />);
-            case CollectionViewType.Tree: return (<CollectionTreeViewChrome key="collchrome" CollectionView={this.props.CollectionView} type={this.props.type} />);
-            case CollectionViewType.Masonry: return (<CollectionStackingViewChrome key="collchrome" CollectionView={this.props.CollectionView} type={this.props.type} />);
-            case CollectionViewType.Carousel3D: return (<Collection3DCarouselViewChrome key="collchrome" CollectionView={this.props.CollectionView} type={this.props.type} />);
-            case CollectionViewType.Grid: return (<CollectionGridViewChrome key="collchrome" CollectionView={this.props.CollectionView} type={this.props.type} />);
-            default: return null;
+            default:
+            case CollectionViewType.Freeform: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={this.props.type === CollectionViewType.Invalid} />);
+            case CollectionViewType.Stacking: return (<CollectionStackingViewChrome key="collchrome" {...this.props} />);
+            case CollectionViewType.Schema: return (<CollectionSchemaViewChrome key="collchrome" {...this.props} />);
+            case CollectionViewType.Tree: return (<CollectionTreeViewChrome key="collchrome" {...this.props} />);
+            case CollectionViewType.Masonry: return (<CollectionStackingViewChrome key="collchrome" {...this.props} />);
+            case CollectionViewType.Carousel3D: return (<Collection3DCarouselViewChrome key="collchrome" {...this.props} />);
+            case CollectionViewType.Grid: return (<CollectionGridViewChrome key="collchrome" {...this.props} />);
         }
     }
-
-    private get document() {
-        return this.props.CollectionView.props.Document;
-    }
-
     private dropDisposer?: DragManager.DragDropDisposer;
     protected createDropTarget = (ele: HTMLDivElement) => {
         this.dropDisposer?.();
@@ -201,15 +213,15 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
 
     dragViewDown = (e: React.PointerEvent) => {
         setupMoveUpEvents(this, e, (e, down, delta) => {
-            const vtype = this.props.CollectionView.collectionViewType;
+            const vtype = this.props.type;
             const c = {
                 params: ["target"], title: vtype,
-                script: `this.target._viewType = '${StrCast(this.props.CollectionView.props.Document._viewType)}'`,
-                immediate: (source: Doc[]) => this.props.CollectionView.props.Document._viewType = Doc.getDocTemplate(source?.[0]),
+                script: `this.target._viewType = '${StrCast(this.props.type)}'`,
+                immediate: (source: Doc[]) => this.document._viewType = Doc.getDocTemplate(source?.[0]),
                 initialize: emptyFunction,
             };
             DragManager.StartButtonDrag([this._viewRef.current!], c.script, StrCast(c.title),
-                { target: this.props.CollectionView.props.Document }, c.params, c.initialize, e.clientX, e.clientY);
+                { target: this.document }, c.params, c.initialize, e.clientX, e.clientY);
             return true;
         }, emptyFunction, emptyFunction);
     }
@@ -217,7 +229,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         setupMoveUpEvents(this, e, (e, down, delta) => {
             this._buttonizableCommands.filter(c => c.title === this._currentKey).map(c =>
                 DragManager.StartButtonDrag([this._commandRef.current!], c.script, c.title,
-                    { target: this.props.CollectionView.props.Document }, c.params, c.initialize, e.clientX, e.clientY));
+                    { target: this.document }, c.params, c.initialize, e.clientX, e.clientY));
             return true;
         }, emptyFunction, () => {
             this._buttonizableCommands.filter(c => c.title === this._currentKey).map(c => c.immediate([]));
@@ -251,7 +263,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
                     className="collectionViewBaseChrome-viewPicker"
                     onPointerDown={stopPropagation}
                     onChange={this.viewChanged}
-                    value={StrCast(this.props.CollectionView.props.Document._viewType)}>
+                    value={StrCast(this.props.type)}>
                     {Object.values(CollectionViewType).map(type => [CollectionViewType.Invalid, CollectionViewType.Docking].includes(type) ? (null) : (
                         <option
                             key={Utils.GenerateGuid()}
@@ -271,7 +283,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
             <div className="collectionMenu-cont" >
                 <div className="collectionMenu">
                     <div className="collectionViewBaseChrome">
-                        {this.viewModes}
+                        {this.props.type === CollectionViewType.Invalid ? (null) : this.viewModes}
                         {this.templateChrome}
                         <div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: "grid" }}>
                             <button className={"antimodeMenu-button"} onClick={this.toggleViewSpecs} >
@@ -287,15 +299,15 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
 }
 
 @observer
-export class CollectionFreeFormViewChrome extends React.Component<CollectionMenuProps> {
+export class CollectionFreeFormViewChrome extends React.Component<CollectionMenuProps & { isOverlay: boolean }> {
     public static Instance: CollectionFreeFormViewChrome;
     constructor(props: any) {
         super(props);
         CollectionFreeFormViewChrome.Instance = this;
     }
-    get Document() { return this.props.CollectionView.props.Document; }
+    get document() { return this.props.docView.props.Document; }
     @computed get dataField() {
-        return this.props.CollectionView.props.Document[Doc.LayoutFieldKey(this.props.CollectionView.props.Document)];
+        return this.document[Doc.LayoutFieldKey(this.document)];
     }
     @computed get childDocs() {
         return DocListCast(this.dataField);
@@ -303,30 +315,30 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     @undoBatch
     @action
     nextKeyframe = (): void => {
-        const currentFrame = Cast(this.Document.currentFrame, "number", null);
+        const currentFrame = Cast(this.document.currentFrame, "number", null);
         if (currentFrame === undefined) {
-            this.Document.currentFrame = 0;
+            this.document.currentFrame = 0;
             CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0);
         }
         CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, currentFrame || 0);
-        this.Document.currentFrame = Math.max(0, (currentFrame || 0) + 1);
-        this.Document.lastFrame = Math.max(NumCast(this.Document.currentFrame), NumCast(this.Document.lastFrame));
+        this.document.currentFrame = Math.max(0, (currentFrame || 0) + 1);
+        this.document.lastFrame = Math.max(NumCast(this.document.currentFrame), NumCast(this.document.lastFrame));
     }
     @undoBatch
     @action
     prevKeyframe = (): void => {
-        const currentFrame = Cast(this.Document.currentFrame, "number", null);
+        const currentFrame = Cast(this.document.currentFrame, "number", null);
         if (currentFrame === undefined) {
-            this.Document.currentFrame = 0;
+            this.document.currentFrame = 0;
             CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0);
         }
         CollectionFreeFormDocumentView.gotoKeyframe(this.childDocs.slice());
-        this.Document.currentFrame = Math.max(0, (currentFrame || 0) - 1);
+        this.document.currentFrame = Math.max(0, (currentFrame || 0) - 1);
     }
     @undoBatch
     @action
     miniMap = (): void => {
-        this.Document.hideMinimap = !this.Document.hideMinimap;
+        this.document.hideMinimap = !this.document.hideMinimap;
     }
     private _palette = ["#D0021B", "#F5A623", "#F8E71C", "#8B572A", "#7ED321", "#417505", "#9013FE", "#4A90E2", "#50E3C2", "#B8E986", "#000000", "#4A4A4A", "#9B9B9B", "#FFFFFF", ""];
     private _width = ["1", "5", "10", "100"];
@@ -467,28 +479,39 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     }
 
     render() {
-        return this.Document.isAnnotationOverlay ? (null) :
-            <div className="collectionFreeFormMenu-cont">
+        return <div className="collectionFreeFormMenu-cont">
+            {this.props.docView.props.renderDepth !== 0 ? (null) :
                 <div key="map" title="mini map" className="backKeyframe" onClick={this.miniMap}>
                     <FontAwesomeIcon icon={"map"} size={"lg"} />
                 </div>
-                <div key="back" title="back frame" className="backKeyframe" onClick={this.prevKeyframe}>
-                    <FontAwesomeIcon icon={"caret-left"} size={"lg"} />
-                </div>
-                <div key="num" title="toggle view all" className="numKeyframe" style={{ backgroundColor: this.Document.editing ? "#759c75" : "#c56565" }}
-                    onClick={action(() => this.Document.editing = !this.Document.editing)} >
-                    {NumCast(this.Document.currentFrame)}
-                </div>
-                <div key="fwd" title="forward frame" className="fwdKeyframe" onClick={this.nextKeyframe}>
-                    <FontAwesomeIcon icon={"caret-right"} size={"lg"} />
-                </div>
+            }
+            <div key="back" title="back frame" className="backKeyframe" onClick={this.prevKeyframe}>
+                <FontAwesomeIcon icon={"caret-left"} size={"lg"} />
+            </div>
+            <div key="num" title="toggle view all" className="numKeyframe" style={{ backgroundColor: this.document.editing ? "#759c75" : "#c56565" }}
+                onClick={action(() => this.document.editing = !this.document.editing)} >
+                {NumCast(this.document.currentFrame)}
+            </div>
+            <div key="fwd" title="forward frame" className="fwdKeyframe" onClick={this.nextKeyframe}>
+                <FontAwesomeIcon icon={"caret-right"} size={"lg"} />
+            </div>
 
-                {this.widthPicker}
-                {this.colorPicker}
-                {this.fillPicker}
-                {this.drawButtons}
-                {this.formatPane}
-            </div>;
+            {!this.props.isOverlay ? (null) :
+                <button className={"antimodeMenu-button"} key="hypothesis" style={{ backgroundColor: !this.props.docView.layoutDoc.isAnnotating ? "121212" : undefined }} title="Use Hypothesis" onClick={() => this.props.docView.layoutDoc.isAnnotating = !this.props.docView.layoutDoc.isAnnotating}>
+                    <FontAwesomeIcon icon={["fab", "hire-a-helper"]} size={"lg"} />
+                </button>
+            }
+            {!this.props.isOverlay || this.props.docView.layoutDoc.isAnnotating ?
+                <>
+                    {this.widthPicker}
+                    {this.colorPicker}
+                    {this.fillPicker}
+                    {this.drawButtons}
+                    {this.formatPane}
+                </> :
+                (null)
+            }
+        </div>;
     }
 }
 @observer
@@ -496,12 +519,14 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu
     @observable private _currentKey: string = "";
     @observable private suggestions: string[] = [];
 
-    @computed private get descending() { return StrCast(this.props.CollectionView.props.Document._columnsSort) === "descending"; }
-    @computed get pivotField() { return StrCast(this.props.CollectionView.props.Document._pivotField); }
+    get document() { return this.props.docView.props.Document; }
+
+    @computed private get descending() { return StrCast(this.document._columnsSort) === "descending"; }
+    @computed get pivotField() { return StrCast(this.document._pivotField); }
 
     getKeySuggestions = async (value: string): Promise<string[]> => {
         value = value.toLowerCase();
-        const docs = DocListCast(this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey]);
+        const docs = DocListCast(this.document[this.props.fieldKey]);
         if (docs instanceof Doc) {
             return Object.keys(docs).filter(key => key.toLowerCase().startsWith(value));
         } else {
@@ -536,14 +561,14 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu
 
     @action
     setValue = (value: string) => {
-        this.props.CollectionView.props.Document._pivotField = value;
+        this.document._pivotField = value;
         return true;
     }
 
     @action toggleSort = () => {
-        this.props.CollectionView.props.Document._columnsSort =
-            this.props.CollectionView.props.Document._columnsSort === "descending" ? "ascending" :
-                this.props.CollectionView.props.Document._columnsSort === "ascending" ? undefined : "descending";
+        this.document._columnsSort =
+            this.document._columnsSort === "descending" ? "ascending" :
+                this.document._columnsSort === "ascending" ? undefined : "descending";
     }
     @action resetValue = () => { this._currentKey = this.pivotField; };
 
@@ -593,35 +618,36 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu
 
 @observer
 export class CollectionSchemaViewChrome extends React.Component<CollectionMenuProps> {
-    // private _textwrapAllRows: boolean = Cast(this.props.CollectionView.props.Document.textwrappedSchemaRows, listSpec("string"), []).length > 0;
+    // private _textwrapAllRows: boolean = Cast(this.document.textwrappedSchemaRows, listSpec("string"), []).length > 0;
+    get document() { return this.props.docView.props.Document; }
 
     @undoBatch
     togglePreview = () => {
         const dividerWidth = 4;
         const borderWidth = Number(COLLECTION_BORDER_WIDTH);
-        const panelWidth = this.props.CollectionView.props.PanelWidth();
-        const previewWidth = NumCast(this.props.CollectionView.props.Document.schemaPreviewWidth);
+        const panelWidth = this.props.docView.props.PanelWidth();
+        const previewWidth = NumCast(this.document.schemaPreviewWidth);
         const tableWidth = panelWidth - 2 * borderWidth - dividerWidth - previewWidth;
-        this.props.CollectionView.props.Document.schemaPreviewWidth = previewWidth === 0 ? Math.min(tableWidth / 3, 200) : 0;
+        this.document.schemaPreviewWidth = previewWidth === 0 ? Math.min(tableWidth / 3, 200) : 0;
     }
 
     @undoBatch
     @action
     toggleTextwrap = async () => {
-        const textwrappedRows = Cast(this.props.CollectionView.props.Document.textwrappedSchemaRows, listSpec("string"), []);
+        const textwrappedRows = Cast(this.document.textwrappedSchemaRows, listSpec("string"), []);
         if (textwrappedRows.length) {
-            this.props.CollectionView.props.Document.textwrappedSchemaRows = new List<string>([]);
+            this.document.textwrappedSchemaRows = new List<string>([]);
         } else {
-            const docs = DocListCast(this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey]);
+            const docs = DocListCast(this.document[this.props.fieldKey]);
             const allRows = docs instanceof Doc ? [docs[Id]] : docs.map(doc => doc[Id]);
-            this.props.CollectionView.props.Document.textwrappedSchemaRows = new List<string>(allRows);
+            this.document.textwrappedSchemaRows = new List<string>(allRows);
         }
     }
 
 
     render() {
-        const previewWidth = NumCast(this.props.CollectionView.props.Document.schemaPreviewWidth);
-        const textWrapped = Cast(this.props.CollectionView.props.Document.textwrappedSchemaRows, listSpec("string"), []).length > 0;
+        const previewWidth = NumCast(this.document.schemaPreviewWidth);
+        const textWrapped = Cast(this.document.textwrappedSchemaRows, listSpec("string"), []).length > 0;
 
         return (
             <div className="collectionSchemaViewChrome-cont">
@@ -641,11 +667,12 @@ export class CollectionSchemaViewChrome extends React.Component<CollectionMenuPr
 @observer
 export class CollectionTreeViewChrome extends React.Component<CollectionMenuProps> {
 
+    get document() { return this.props.docView.props.Document; }
     get sortAscending() {
-        return this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey + "-sortAscending"];
+        return this.document[this.props.fieldKey + "-sortAscending"];
     }
     set sortAscending(value) {
-        this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey + "-sortAscending"] = value;
+        this.document[this.props.fieldKey + "-sortAscending"] = value;
     }
     @computed private get ascending() {
         return Cast(this.sortAscending, "boolean", null);
@@ -676,15 +703,16 @@ export class CollectionTreeViewChrome extends React.Component<CollectionMenuProp
 // Enter scroll speed for 3D Carousel 
 @observer
 export class Collection3DCarouselViewChrome extends React.Component<CollectionMenuProps> {
+    get document() { return this.props.docView.props.Document; }
     @computed get scrollSpeed() {
-        return this.props.CollectionView.props.Document._autoScrollSpeed;
+        return this.document._autoScrollSpeed;
     }
 
     @action
     setValue = (value: string) => {
         const numValue = Number(StrCast(value));
         if (numValue > 0) {
-            this.props.CollectionView.props.Document._autoScrollSpeed = numValue;
+            this.document._autoScrollSpeed = numValue;
             return true;
         }
         return false;
@@ -721,13 +749,14 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
     private decrementLimitReached: boolean = false;
     @observable private resize = false;
     private resizeListenerDisposer: Opt<Lambda>;
+    get document() { return this.props.docView.props.Document; }
 
     componentDidMount() {
 
-        runInAction(() => this.resize = this.props.CollectionView.props.PanelWidth() < 700);
+        runInAction(() => this.resize = this.props.docView.props.PanelWidth() < 700);
 
         // listener to reduce text on chrome resize (panel resize)
-        this.resizeListenerDisposer = computed(() => this.props.CollectionView.props.PanelWidth()).observe(({ newValue }) => {
+        this.resizeListenerDisposer = computed(() => this.props.docView.props.PanelWidth()).observe(({ newValue }) => {
             runInAction(() => this.resize = newValue < 700);
         });
     }
@@ -736,7 +765,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
         this.resizeListenerDisposer?.();
     }
 
-    get numCols() { return NumCast(this.props.CollectionView.props.Document.gridNumCols, 10); }
+    get numCols() { return NumCast(this.document.gridNumCols, 10); }
 
     /**
      * Sets the value of `numCols` on the grid's Document to the value entered.
@@ -745,7 +774,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
     onNumColsEnter = (e: React.KeyboardEvent<HTMLInputElement>) => {
         if (e.key === "Enter" || e.key === "Tab") {
             if (e.currentTarget.valueAsNumber > 0) {
-                this.props.CollectionView.props.Document.gridNumCols = e.currentTarget.valueAsNumber;
+                this.document.gridNumCols = e.currentTarget.valueAsNumber;
             }
 
         }
@@ -757,8 +786,8 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
     // @undoBatch
     // onRowHeightEnter = (e: React.KeyboardEvent<HTMLInputElement>) => {
     //     if (e.key === "Enter" || e.key === "Tab") {
-    //         if (e.currentTarget.valueAsNumber > 0 && this.props.CollectionView.props.Document.rowHeight as number !== e.currentTarget.valueAsNumber) {
-    //             this.props.CollectionView.props.Document.rowHeight = e.currentTarget.valueAsNumber;
+    //         if (e.currentTarget.valueAsNumber > 0 && this.document.rowHeight as number !== e.currentTarget.valueAsNumber) {
+    //             this.document.rowHeight = e.currentTarget.valueAsNumber;
     //         }
     //     }
     // }
@@ -768,7 +797,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
      */
     @undoBatch
     toggleFlex = () => {
-        this.props.CollectionView.props.Document.gridFlex = !BoolCast(this.props.CollectionView.props.Document.gridFlex, true);
+        this.document.gridFlex = !BoolCast(this.document.gridFlex, true);
     }
 
     /**
@@ -776,8 +805,8 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
      */
     onIncrementButtonClick = () => {
         this.clicked = true;
-        this.entered && (this.props.CollectionView.props.Document.gridNumCols as number)--;
-        undoBatch(() => this.props.CollectionView.props.Document.gridNumCols = this.numCols + 1)();
+        this.entered && (this.document.gridNumCols as number)--;
+        undoBatch(() => this.document.gridNumCols = this.numCols + 1)();
         this.entered = false;
     }
 
@@ -787,8 +816,8 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
     onDecrementButtonClick = () => {
         this.clicked = true;
         if (!this.decrementLimitReached) {
-            this.entered && (this.props.CollectionView.props.Document.gridNumCols as number)++;
-            undoBatch(() => this.props.CollectionView.props.Document.gridNumCols = this.numCols - 1)();
+            this.entered && (this.document.gridNumCols as number)++;
+            undoBatch(() => this.document.gridNumCols = this.numCols - 1)();
         }
         this.entered = false;
     }
@@ -799,7 +828,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
     incrementValue = () => {
         this.entered = true;
         if (!this.clicked && !this.decrementLimitReached) {
-            this.props.CollectionView.props.Document.gridNumCols = this.numCols + 1;
+            this.document.gridNumCols = this.numCols + 1;
         }
         this.decrementLimitReached = false;
         this.clicked = false;
@@ -812,7 +841,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
         this.entered = true;
         if (!this.clicked) {
             if (this.numCols !== 1) {
-                this.props.CollectionView.props.Document.gridNumCols = this.numCols - 1;
+                this.document.gridNumCols = this.numCols - 1;
             }
             else {
                 this.decrementLimitReached = true;
@@ -826,7 +855,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
      * Toggles the value of preventCollision
      */
     toggleCollisions = () => {
-        this.props.CollectionView.props.Document.gridPreventCollision = !this.props.CollectionView.props.Document.gridPreventCollision;
+        this.document.gridPreventCollision = !this.document.gridPreventCollision;
     }
 
     /**
@@ -834,7 +863,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
      */
     changeCompactType = (e: React.ChangeEvent<HTMLSelectElement>) => {
         // need to change startCompaction so that this operation will be undoable.
-        this.props.CollectionView.props.Document.gridStartCompaction = e.target.selectedOptions[0].value;
+        this.document.gridStartCompaction = e.target.selectedOptions[0].value;
     }
 
     render() {
@@ -852,10 +881,10 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
                     <span className="grid-icon">
                         <FontAwesomeIcon icon="text-height" size="1x" />
                     </span>
-                    <input className="collectionGridViewChrome-entryBox" type="number" placeholder={this.props.CollectionView.props.Document.rowHeight as string} onKeyDown={this.onRowHeightEnter} onClick={(e: React.MouseEvent<HTMLInputElement, MouseEvent>) => { e.stopPropagation(); e.preventDefault(); e.currentTarget.focus(); }} />
+                    <input className="collectionGridViewChrome-entryBox" type="number" placeholder={this.document.rowHeight as string} onKeyDown={this.onRowHeightEnter} onClick={(e: React.MouseEvent<HTMLInputElement, MouseEvent>) => { e.stopPropagation(); e.preventDefault(); e.currentTarget.focus(); }} />
                 </span> */}
                 <span className="grid-control" style={{ width: this.resize ? "12%" : "20%" }}>
-                    <input type="checkbox" style={{ marginRight: 5 }} onChange={this.toggleCollisions} checked={!this.props.CollectionView.props.Document.gridPreventCollision} />
+                    <input type="checkbox" style={{ marginRight: 5 }} onChange={this.toggleCollisions} checked={!this.document.gridPreventCollision} />
                     <label className="flexLabel">{this.resize ? "Coll" : "Collisions"}</label>
                 </span>
 
@@ -863,7 +892,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
                     style={{ marginRight: 5 }}
                     onPointerDown={stopPropagation}
                     onChange={this.changeCompactType}
-                    value={StrCast(this.props.CollectionView.props.Document.gridStartCompaction, StrCast(this.props.CollectionView.props.Document.gridCompaction))}>
+                    value={StrCast(this.document.gridStartCompaction, StrCast(this.document.gridCompaction))}>
                     {["vertical", "horizontal", "none"].map(type =>
                         <option className="collectionGridViewChrome-viewOption"
                             onPointerDown={stopPropagation}
@@ -875,11 +904,11 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
 
                 <span className="grid-control" style={{ width: this.resize ? "12%" : "20%" }}>
                     <input style={{ marginRight: 5 }} type="checkbox" onChange={this.toggleFlex}
-                        checked={BoolCast(this.props.CollectionView.props.Document.gridFlex, true)} />
+                        checked={BoolCast(this.document.gridFlex, true)} />
                     <label className="flexLabel">{this.resize ? "Flex" : "Flexible"}</label>
                 </span>
 
-                <button onClick={() => this.props.CollectionView.props.Document.gridResetLayout = true}>
+                <button onClick={() => this.document.gridResetLayout = true}>
                     {!this.resize ? "Reset" :
                         <FontAwesomeIcon icon="redo-alt" size="1x" />}
                 </button>
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 8480a56cc..d9d9c0eb8 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -292,7 +292,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                             const reg = new RegExp(Utils.prepend(""), "g");
                             const modHtml = srcUrl ? html.replace(reg, srcUrl) : html;
                             const htmlDoc = Docs.Create.HtmlDocument(modHtml, { ...options, title: "-web page-", _width: 300, _height: 300 });
-                            Doc.GetProto(htmlDoc)["data-text"] = text;
+                            Doc.GetProto(htmlDoc)["data-text"] = Doc.GetProto(htmlDoc)["text"] = text;
                             this.props.addDocument(htmlDoc);
                             if (srcWeb) {
                                 const focusNode = (SelectionManager.SelectedDocuments()[0].ContentDiv?.getElementsByTagName("iframe")[0].contentDocument?.getSelection()?.focusNode as any);
@@ -300,7 +300,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                                     const rect = "getBoundingClientRect" in focusNode ? focusNode.getBoundingClientRect() : focusNode?.parentElement.getBoundingClientRect();
                                     const x = (rect?.x || 0);
                                     const y = NumCast(srcWeb._scrollTop) + (rect?.y || 0);
-                                    const anchor = Docs.Create.FreeformDocument([], { _backgroundColor: "transparent", _width: 25, _height: 25, x, y, annotationOn: srcWeb });
+                                    const anchor = Docs.Create.FreeformDocument([], { _backgroundColor: "transparent", _width: 75, _height: 40, x, y, annotationOn: srcWeb });
                                     anchor.context = srcWeb;
                                     const key = Doc.LayoutFieldKey(srcWeb);
                                     Doc.AddDocToList(srcWeb, key + "-annotations", anchor);
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index a82c91383..2c17254ed 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -577,7 +577,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
             ChildLayoutTemplate: this.childLayoutTemplate,
             ChildLayoutString: this.childLayoutString,
         };
-        setTimeout(action(() => this.props.isSelected(true) && (CollectionMenu.Instance.SelectedCollection = this)), 0);
+        setTimeout(() => this.props.isSelected(true) && CollectionMenu.Instance.SetSelection(this, this.props.fieldKey), 0);
         const boxShadow = Doc.UserDoc().renderStyle === "comic" || this.props.Document.isBackground || this.collectionViewType === CollectionViewType.Linear ? undefined :
             `${Cast(Doc.UserDoc().activeWorkspace, Doc, null)?.darkScheme ? "rgb(30, 32, 31) " : "#9c9396 "} ${StrCast(this.props.Document.boxShadow, "0.2vw 0.2vw 0.8vw")}`;
         return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b59875a7e..7f86ec98e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -44,6 +44,7 @@ import { MobileInterface } from '../../../mobile/MobileInterface';
 import { TaskCompletionBox } from './TaskCompletedBox';
 import { LinkDescriptionPopup } from './LinkDescriptionPopup';
 import { LinkManager } from '../../util/LinkManager';
+import CollectionMenu from '../collections/CollectionMenu';
 
 library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight,
     fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale,
-- 
cgit v1.2.3-70-g09d2


From 7693ca298392cb0551032b83b688366b1956bdd6 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 28 Jul 2020 10:52:02 -0400
Subject: cleaned up some font stuff.  cleaned up DocumentView a bit

---
 src/client/documents/Documents.ts                  |   1 +
 src/client/util/SharingManager.tsx                 |   5 +-
 src/client/views/DocComponent.tsx                  |   6 +-
 src/client/views/GestureOverlay.tsx                |   2 +-
 src/client/views/MainView.tsx                      |  38 +-
 src/client/views/Touchable.tsx                     |   2 +-
 .../views/collections/CollectionLinearView.tsx     |   2 +-
 src/client/views/collections/CollectionSubView.tsx |   8 +-
 src/client/views/collections/CollectionView.tsx    |   7 +-
 .../CollectionFreeFormLayoutEngines.tsx            |  24 --
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   5 -
 src/client/views/nodes/ComparisonBox.tsx           |   2 +-
 src/client/views/nodes/DocumentView.tsx            | 409 ++++-----------------
 src/client/views/nodes/ImageBox.tsx                |   2 +-
 src/client/views/nodes/ScriptingBox.tsx            |   2 +-
 src/fields/Doc.ts                                  |   5 +
 16 files changed, 110 insertions(+), 410 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index a1c66c2fe..2cd781a53 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1053,6 +1053,7 @@ export namespace DocUtils {
             }
         });
         batch.end();
+        return doc;
     }
     export function findTemplate(templateName: string, type: string, signature: string) {
         let docLayoutTemplate: Opt<Doc>;
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 452a58d21..0d8b33fbe 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -8,7 +8,6 @@ import * as RequestPromise from "request-promise";
 import { Utils } from "../../Utils";
 import "./SharingManager.scss";
 import { observer } from "mobx-react";
-import { library } from '@fortawesome/fontawesome-svg-core';
 import * as fa from '@fortawesome/free-solid-svg-icons';
 import { DocumentView } from "../views/nodes/DocumentView";
 import { SelectionManager } from "./SelectionManager";
@@ -23,8 +22,6 @@ import { List } from "../../fields/List";
 import { distributeAcls, SharingPermissions } from "../../fields/util";
 import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox";
 
-library.add(fa.faCopy, fa.faTimes);
-
 export interface User {
     email: string;
     userDocumentId: string;
@@ -447,7 +444,7 @@ export default class SharingManager extends React.Component<{}> {
                 <div className="sharing-contents">
                     <p className={"share-title"}><b>Share </b>{this.focusOn(StrCast(this.targetDoc?.title, "this document"))}</p>
                     <div className={"close-button"} onClick={this.close}>
-                        <FontAwesomeIcon icon={fa.faTimes} color={"black"} size={"lg"} />
+                        <FontAwesomeIcon icon={"times"} color={"black"} size={"lg"} />
                     </div>
                     {this.targetDoc?.author !== Doc.CurrentUserEmail ? null
                         :
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 9fd406407..4c82149e2 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -26,7 +26,7 @@ export function DocComponent<P extends DocComponentProps, T>(schemaCtor: (doc: D
         // This is the data part of a document -- ie, the data that is constant across all views of the document
         @computed get dataDoc() { return this.props.Document[DataSym] as Doc; }
 
-        protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
+        protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
     }
     return Component;
 }
@@ -59,7 +59,7 @@ export function ViewBoxBaseComponent<P extends ViewBoxBaseProps, T>(schemaCtor:
         lookupField = (field: string) => ScriptCast(this.layoutDoc.lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field, container: this.props.ContainingCollectionDoc }).result;
 
         active = (outsideReaction?: boolean) => !this.props.Document.isBackground && (this.props.rootSelected(outsideReaction) || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0 || this.layoutDoc.forceActive);//  && !Doc.SelectedTool();  // bcz: inking state shouldn't affect static tools 
-        protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
+        protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
     }
     return Component;
 }
@@ -114,7 +114,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
             return style;
         }
 
-        protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
+        protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
 
         _annotationKey: string = "annotations";
         public get annotationKey() { return this.fieldKey + "-" + this._annotationKey; }
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 2e588ceb5..ed77da8ca 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -63,7 +63,7 @@ export default class GestureOverlay extends Touchable {
     private _hands: Map<number, React.Touch[]> = new Map<number, React.Touch[]>();
     private _holdTimer: NodeJS.Timeout | undefined;
 
-    protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
+    protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
 
     constructor(props: Readonly<{}>) {
         super(props);
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 9fad612ee..33cd43678 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,18 +1,6 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
-
-import {
-    faHireAHelper
-} from '@fortawesome/free-brands-svg-icons';
-import {
-    faTasks, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus,
-    faTerminal, faToggleOn, faFile as fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard,
-    faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt,
-    faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter,
-    faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faTimesCircle,
-    faThumbtack, faTree, faTv, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faArrowsAlt, faQuoteLeft, faSortAmountDown, faAlignLeft, faAlignCenter, faAlignRight,
-    faHeading, faRulerCombined, faFillDrip, faLink, faUnlink, faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSuperscript, faSubscript, faIndent, faEyeDropper,
-    faPaintRoller, faBars, faBrush, faShapes, faEllipsisH, faHandPaper, faMap, faUser
-} from '@fortawesome/free-solid-svg-icons';
+import { faHireAHelper } from '@fortawesome/free-brands-svg-icons';
+import * as fa from '@fortawesome/free-solid-svg-icons';
 import { ANTIMODEMENU_HEIGHT } from './globalCssVariables.scss';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
@@ -146,14 +134,20 @@ export class MainView extends React.Component {
             }
         }
 
-        library.add(faTasks, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus,
-            faTerminal, faToggleOn, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faTimesCircle, faWindowMaximize, faAddressCard, fileSolid,
-            faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt,
-            faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter,
-            faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faTrashAlt, faAngleRight, faBell,
-            faThumbtack, faTree, faTv, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faArrowsAlt, faQuoteLeft, faSortAmountDown, faAlignLeft, faAlignCenter, faAlignRight,
-            faHeading, faRulerCombined, faFillDrip, faLink, faUnlink, faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSuperscript, faSubscript, faIndent, faEyeDropper,
-            faPaintRoller, faBars, faBrush, faShapes, faEllipsisH, faHandPaper, faMap, faUser, faHireAHelper);
+        library.add(fa.faEdit, fa.faTrash, fa.faTrashAlt, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt,
+            fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock,
+            fa.faLock, fa.faLaptopCode, fa.faMale, fa.faCopy, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone, fa.faKeyboard,
+            fa.faQuestion, fa.faTasks, fa.faPalette, fa.faAngleRight, fa.faBell, fa.faCamera, fa.faExpand, fa.faCaretDown, fa.faCaretLeft, fa.faCaretRight,
+            fa.faCaretSquareDown, fa.faCaretSquareRight, fa.faArrowsAltH, fa.faPlus, fa.faMinus, fa.faTerminal, fa.faToggleOn, fa.faFile, fa.faLocationArrow,
+            fa.faSearch, fa.faFileDownload, fa.faStop, fa.faCalculator, fa.faWindowMaximize, fa.faAddressCard, fa.faQuestionCircle, fa.faArrowLeft,
+            fa.faArrowRight, fa.faArrowDown, fa.faArrowUp, fa.faBolt, fa.faBullseye, fa.faCaretUp, fa.faCat, fa.faCheck, fa.faChevronRight, fa.faClipboard,
+            fa.faClone, fa.faCloudUploadAlt, fa.faCommentAlt, fa.faCompressArrowsAlt, fa.faCut, fa.faEllipsisV, fa.faEraser, fa.faExclamation, fa.faFileAlt,
+            fa.faFileAudio, fa.faFilePdf, fa.faFilm, fa.faFilter, fa.faFont, fa.faGlobeAsia, fa.faHighlighter, fa.faLongArrowAltRight, fa.faMousePointer,
+            fa.faMusic, fa.faObjectGroup, fa.faPause, fa.faPen, fa.faPenNib, fa.faPhone, fa.faPlay, fa.faPortrait, fa.faRedoAlt, fa.faStamp, fa.faStickyNote,
+            fa.faTimesCircle, fa.faThumbtack, fa.faTree, fa.faTv, fa.faUndoAlt, fa.faVideo, fa.faAsterisk, fa.faBrain, fa.faImage, fa.faPaintBrush, fa.faTimes,
+            fa.faEye, fa.faArrowsAlt, fa.faQuoteLeft, fa.faSortAmountDown, fa.faAlignLeft, fa.faAlignCenter, fa.faAlignRight, fa.faHeading, fa.faRulerCombined,
+            fa.faFillDrip, fa.faLink, fa.faUnlink, fa.faBold, fa.faItalic, fa.faChevronLeft, fa.faUnderline, fa.faStrikethrough, fa.faSuperscript, fa.faSubscript,
+            fa.faIndent, fa.faEyeDropper, fa.faPaintRoller, fa.faBars, fa.faBrush, fa.faShapes, fa.faEllipsisH, fa.faHandPaper, fa.faMap, fa.faUser, faHireAHelper);
         this.initEventListeners();
         this.initAuthenticationRouters();
     }
diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx
index c4cae7e8d..bb9e108cb 100644
--- a/src/client/views/Touchable.tsx
+++ b/src/client/views/Touchable.tsx
@@ -12,7 +12,7 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
     private holdEndDisposer?: InteractionUtils.MultiTouchEventDisposer;
 
 
-    protected abstract multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
+    protected abstract _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
     protected _touchDrag: boolean = false;
     protected prevPoints: Map<number, React.Touch> = new Map<number, React.Touch>();
 
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 407524353..3b31947f7 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -176,7 +176,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                 }}
                     onPointerDown={e => e.stopPropagation()} >
                     <span className="bottomPopup-text" >
-                        Creating link from: {DocumentLinksButton.StartLink.title}
+                        Creating link from: {DocumentLinksButton.StartLink.props.Document.title}
                     </span>
 
                     <Tooltip title={<><div className="dash-tooltip">{LinkDescriptionPopup.showDescriptions ? "Turn off description pop-up" :
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index d9d9c0eb8..99acfdcc2 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -55,17 +55,17 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
     class CollectionSubView extends DocComponent<X & SubCollectionViewProps, T>(schemaCtor) {
         private dropDisposer?: DragManager.DragDropDisposer;
         private gestureDisposer?: GestureUtils.GestureEventDisposer;
-        protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
+        protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
         protected _mainCont?: HTMLDivElement;
         protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view
             this.dropDisposer?.();
             this.gestureDisposer?.();
-            this.multiTouchDisposer?.();
+            this._multiTouchDisposer?.();
             if (ele) {
                 this._mainCont = ele;
                 this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc, this.onInternalPreDrop.bind(this));
                 this.gestureDisposer = GestureUtils.MakeGestureTarget(ele, this.onGesture.bind(this));
-                this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(ele, this.onTouchStart.bind(this));
+                this._multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(ele, this.onTouchStart.bind(this));
             }
         }
         protected CreateDropTarget(ele: HTMLDivElement) { //used in schema view
@@ -74,7 +74,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
 
         componentWillUnmount() {
             this.gestureDisposer?.();
-            this.multiTouchDisposer?.();
+            this._multiTouchDisposer?.();
         }
 
         @computed get dataDoc() {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 2c17254ed..e7a504e61 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -27,12 +27,10 @@ import { InteractionUtils } from '../../util/InteractionUtils';
 import { UndoManager } from '../../util/UndoManager';
 import { ContextMenu } from "../ContextMenu";
 import { FieldView, FieldViewProps } from '../nodes/FieldView';
-import { ScriptBox } from '../ScriptBox';
 import { Touchable } from '../Touchable';
 import { CollectionCarousel3DView } from './CollectionCarousel3DView';
 import { CollectionCarouselView } from './CollectionCarouselView';
 import { CollectionDockingView } from "./CollectionDockingView";
-import { AddCustomFreeFormLayout } from './collectionFreeForm/CollectionFreeFormLayoutEngines';
 import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
 import { CollectionGridView } from './collectionGrid/CollectionGridView';
 import { CollectionLinearView } from './CollectionLinearView';
@@ -105,7 +103,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
     @observable private static _safeMode = false;
     public static SetSafeMode(safeMode: boolean) { this._safeMode = safeMode; }
 
-    protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
+    protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
 
     private AclMap = new Map<symbol, string>([
         [AclPrivate, SharingPermissions.None],
@@ -289,9 +287,6 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
         subItems.push({ description: "Pivot/Time", event: () => func(CollectionViewType.Time), icon: "columns" });
         subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" });
         subItems.push({ description: "Grid", event: () => func(CollectionViewType.Grid), icon: "th-list" });
-        if (addExtras && this.props.Document._viewType === CollectionViewType.Freeform) {
-            subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) });
-        }
         addExtras && subItems.push({ description: "lightbox", event: action(() => this._isLightboxOpen = true), icon: "eye" });
 
         const existingVm = ContextMenu.Instance.findByDescription(category);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index 183ed3119..b00074cc6 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -434,27 +434,3 @@ function normalizeResults(
         payload: gname.payload
     })));
 }
-
-export function AddCustomFreeFormLayout(doc: Doc, dataKey: string): () => void {
-    return () => {
-        const addOverlay = (key: "arrangeScript" | "arrangeInit", options: OverlayElementOptions, params?: Record<string, string>, requiredType?: string) => {
-            let overlayDisposer: () => void = emptyFunction; // filled in below after we have a reference to the scriptingBox
-            const scriptField = Cast(doc[key], ScriptField);
-            const scriptingBox = <ScriptBox initialText={scriptField && scriptField.script.originalScript}
-                // tslint:disable-next-line: no-unnecessary-callback-wrapper
-                onCancel={() => overlayDisposer()}  // don't get rid of the function wrapper-- we don't want to use the current value of overlayDiposer, but the one set below
-                onSave={(text, onError) => {
-                    const script = CompileScript(text, { params, requiredType, typecheck: false });
-                    if (!script.compiled) {
-                        onError(script.errors.map(error => error.messageText).join("\n"));
-                    } else {
-                        doc[key] = new ScriptField(script);
-                        overlayDisposer();
-                    }
-                }} />;
-            overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, options);
-        };
-        addOverlay("arrangeInit", { x: 400, y: 100, width: 400, height: 300, title: "Layout Initialization" }, { collection: "Doc", docs: "Doc[]" }, undefined);
-        addOverlay("arrangeScript", { x: 400, y: 500, width: 400, height: 300, title: "Layout Script" }, { doc: "Doc", index: "number", collection: "Doc", state: "any", docs: "Doc[]" }, "{x: number, y: number, width?: number, height?: number}");
-    };
-}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 792f3af5f..57336131a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -57,7 +57,6 @@ export const panZoomSchema = createSchema({
     currentTimecode: "number",
     displayTimecode: "number",
     currentFrame: "number",
-    arrangeScript: ScriptField,
     arrangeInit: ScriptField,
     useClusters: "boolean",
     fitToBox: "boolean",
@@ -1005,10 +1004,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         return this.props.addDocTab(doc, where);
     });
     getCalculatedPositions(params: { pair: { layout: Doc, data?: Doc }, index: number, collection: Doc, docs: Doc[], state: any }): PoolData {
-        const result = this.Document.arrangeScript?.script.run(params, console.log);
-        if (result?.success) {
-            return { x: 0, y: 0, transition: "transform 1s", ...result, pair: params.pair, replica: "" };
-        }
         const layoutDoc = Doc.Layout(params.pair.layout);
         const { x, y, opacity } = this.Document.currentFrame === undefined ? params.pair.layout :
             CollectionFreeFormDocumentView.getValues(params.pair.layout, this.Document.currentFrame || 0);
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index f140cc6e5..616cddfcf 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -24,7 +24,7 @@ const ComparisonDocument = makeInterface(comparisonSchema, documentSchema);
 @observer
 export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps, ComparisonDocument>(ComparisonDocument) {
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ComparisonBox, fieldKey); }
-    protected multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined;
+    protected _multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined;
     private _disposers: (DragManager.DragDropDisposer | undefined)[] = [undefined, undefined];
 
     @observable _animating = "";
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3b4dc3741..c47edefd6 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,31 +1,31 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import * as fa from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, DocListCast, HeightSym, Opt, WidthSym, DataSym, AclPrivate, AclEdit, AclAdmin } from "../../../fields/Doc";
+import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
 import { Document } from '../../../fields/documentSchemas';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { listSpec } from "../../../fields/Schema";
 import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
 import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from "../../../fields/Types";
-import { TraceMobx, GetEffectiveAcl, SharingPermissions } from '../../../fields/util';
+import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
+import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util';
+import { MobileInterface } from '../../../mobile/MobileInterface';
 import { GestureUtils } from '../../../pen-gestures/GestureUtils';
-import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils, emptyPath } from "../../../Utils";
+import { emptyFunction, emptyPath, OmitKeys, returnOne, returnTransparent, Utils } from "../../../Utils";
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { ClientRecommender } from '../../ClientRecommender';
 import { Docs, DocUtils } from "../../documents/Documents";
 import { DocumentType } from '../../documents/DocumentTypes';
 import { DocumentManager } from "../../util/DocumentManager";
-import { SnappingManager } from '../../util/SnappingManager';
 import { DragManager, dropActionType } from "../../util/DragManager";
 import { InteractionUtils } from '../../util/InteractionUtils';
+import { LinkManager } from '../../util/LinkManager';
 import { Scripting } from '../../util/Scripting';
 import { SearchUtil } from '../../util/SearchUtil';
 import { SelectionManager } from "../../util/SelectionManager";
 import SharingManager from '../../util/SharingManager';
+import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from "../../util/Transform";
 import { undoBatch, UndoManager } from "../../util/UndoManager";
 import { CollectionView, CollectionViewType } from '../collections/CollectionView';
@@ -35,20 +35,13 @@ import { DocComponent } from "../DocComponent";
 import { EditableView } from '../EditableView';
 import { KeyphraseQueryView } from '../KeyphraseQueryView';
 import { DocumentContentsView } from "./DocumentContentsView";
+import { DocumentLinksButton } from './DocumentLinksButton';
 import "./DocumentView.scss";
 import { LinkAnchorBox } from './LinkAnchorBox';
+import { LinkDescriptionPopup } from './LinkDescriptionPopup';
 import { RadialMenu } from './RadialMenu';
-import React = require("react");
-import { DocumentLinksButton } from './DocumentLinksButton';
-import { MobileInterface } from '../../../mobile/MobileInterface';
 import { TaskCompletionBox } from './TaskCompletedBox';
-import { LinkDescriptionPopup } from './LinkDescriptionPopup';
-import { LinkManager } from '../../util/LinkManager';
-import CollectionMenu from '../collections/CollectionMenu';
-
-library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight,
-    fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale,
-    fa.faCopy, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone, fa.faKeyboard, fa.faQuestion);
+import React = require("react");
 
 export type DocFocusFunc = () => boolean;
 
@@ -105,24 +98,25 @@ export interface DocumentViewProps {
 
 @observer
 export class DocumentView extends DocComponent<DocumentViewProps, Document>(Document) {
+    @observable _animateScalingTo = 0;
     private _downX: number = 0;
     private _downY: number = 0;
+    private _firstX: number = -1;
+    private _firstY: number = -1;
     private _lastTap: number = 0;
     private _doubleTap = false;
     private _mainCont = React.createRef<HTMLDivElement>();
     private _dropDisposer?: DragManager.DragDropDisposer;
     private _showKPQuery: boolean = false;
     private _queries: string = "";
-    private _gestureEventDisposer?: GestureUtils.GestureEventDisposer;
     private _titleRef = React.createRef<EditableView>();
+    private _gestureEventDisposer?: GestureUtils.GestureEventDisposer;
+    private _holdDisposer?: InteractionUtils.MultiTouchEventDisposer;
+    protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
 
-    protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
-    private holdDisposer?: InteractionUtils.MultiTouchEventDisposer;
-
-    public get title() { return this.props.Document.title; }
     public get displayName() { return "DocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive
     public get ContentDiv() { return this._mainCont.current; }
-    get active() { return SelectionManager.IsSelected(this, true) || this.props.parentActive(true); }
+    private get active() { return SelectionManager.IsSelected(this, true) || this.props.parentActive(true); }
     @computed get topMost() { return this.props.renderDepth === 0; }
     @computed get freezeDimensions() { return this.props.FreezeDimensions; }
     @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
@@ -136,9 +130,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     onClickFunc = () => this.onClickHandler;
     onDoubleClickFunc = () => this.onDoubleClickHandler;
 
-    private _firstX: number = -1;
-    private _firstY: number = -1;
-
     handle1PointerHoldStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): any => {
         this.removeMoveListeners();
         this.removeEndListeners();
@@ -152,11 +143,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             this._firstX = pt.pageX;
             this._firstY = pt.pageY;
         }
-
     }
 
     handle1PointerHoldMove = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => {
-
         const pt = me.touchEvent.touches[me.touchEvent.touches.length - 1];
 
         if (this._firstX === -1 || this._firstY === -1) {
@@ -200,7 +189,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     componentDidMount() {
         this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.props.Document));
         this._mainCont.current && (this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this)));
-        this._mainCont.current && (this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this)));
+        this._mainCont.current && (this._multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this)));
         // this._mainCont.current && (this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this)));
 
         if (!this.props.dontRegisterView) {
@@ -212,13 +201,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     componentDidUpdate() {
         this._dropDisposer?.();
         this._gestureEventDisposer?.();
-        this.multiTouchDisposer?.();
-        this.holdDisposer?.();
+        this._multiTouchDisposer?.();
+        this._holdDisposer?.();
         if (this._mainCont.current) {
             this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.props.Document);
             this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this));
-            this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this));
-            this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this));
+            this._multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this));
+            this._holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this));
         }
     }
 
@@ -226,8 +215,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     componentWillUnmount() {
         this._dropDisposer?.();
         this._gestureEventDisposer?.();
-        this.multiTouchDisposer?.();
-        this.holdDisposer?.();
+        this._multiTouchDisposer?.();
+        this._holdDisposer?.();
         Doc.UnBrushDoc(this.props.Document);
         if (!this.props.dontRegisterView) {
             const index = DocumentManager.Instance.DocumentViews.indexOf(this);
@@ -242,7 +231,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             dragData.offset = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).transformDirection(x - left, y - top);
             dragData.dropAction = dropAction;
             dragData.removeDocument = this.props.removeDocument;
-            dragData.moveDocument = this.props.moveDocument;//  this.layoutDoc.onDragStart ? undefined : this.props.moveDocument;
+            dragData.moveDocument = this.props.moveDocument;
             dragData.dragDivName = this.props.dragDivName;
             dragData.treeViewDoc = this.props.treeViewDoc;
             DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: !dropAction && !this.layoutDoc.onDragStart });
@@ -254,7 +243,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const de = new DragManager.DocumentDragData([topDoc]);
         de.dragDivName = topDocView.props.dragDivName;
         de.moveDocument = topDocView.props.moveDocument;
-        undoBatch(action(() => topDoc.z = topDoc.z ? 0 : 1))();
         setTimeout(() => {
             const newDocView = DocumentManager.Instance.getDocumentView(topDoc);
             if (newDocView) {
@@ -263,6 +251,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 DragManager.StartDocumentDrag([contentDiv], de, x, y, { offsetX: x - xf.left, offsetY: y - xf.top, hideSource: true });
             }
         }, 0);
+        UndoManager.RunInBatch(action(() => topDoc.z = topDoc.z ? 0 : 1), "float");
     }
 
     onKeyDown = (e: React.KeyboardEvent) => {
@@ -301,41 +290,39 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                         const func = () => this.onDoubleClickHandler.script.run({
                             this: this.layoutDoc,
                             self: this.rootDoc,
-                            thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey
+                            thisContainer: this.props.ContainingCollectionDoc,
+                            shiftKey: e.shiftKey
                         }, console.log);
                         func();
                     } else {
                         UndoManager.RunInBatch(() => {
+                            let fullScreenDoc = this.props.Document;
                             if (StrCast(this.props.Document.layoutKey) !== "layout_fullScreen" && this.props.Document.layout_fullScreen) {
-                                const fullScreenAlias = Doc.MakeAlias(this.props.Document);
-                                fullScreenAlias.layoutKey = "layout_fullScreen";
-                                this.props.addDocTab(fullScreenAlias, "inTab");
-                            } else {
-                                this.props.addDocTab(this.props.Document, "inTab");
+                                fullScreenDoc = Doc.MakeAlias(this.props.Document);
+                                fullScreenDoc.layoutKey = "layout_fullScreen";
                             }
+                            this.props.addDocTab(fullScreenDoc, "inTab");
                         }, "double tap");
                         SelectionManager.DeselectAll();
                         Doc.UnBrushDoc(this.props.Document);
                     }
                 }
             } else if (this.onClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself
-                //SelectionManager.DeselectAll();
                 const func = () => this.onClickHandler.script.run({
                     this: this.layoutDoc,
                     self: this.rootDoc,
-                    thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey
+                    thisContainer: this.props.ContainingCollectionDoc,
+                    shiftKey: e.shiftKey
                 }, console.log);
                 if (this.props.Document !== Doc.UserDoc()["dockedBtn-undo"] && this.props.Document !== Doc.UserDoc()["dockedBtn-redo"]) {
                     UndoManager.RunInBatch(func, "on click");
                 } else func();
             } else if (this.Document["onClick-rawScript"] && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) {// bcz: hack? don't edit a script if you're clicking on a scripting box itself
-                const alias = Doc.MakeAlias(this.props.Document);
-                DocUtils.makeCustomViewClicked(alias, undefined, "onClick");
-                this.props.addDocTab(alias, "onRight");
+                this.props.addDocTab(DocUtils.makeCustomViewClicked(Doc.MakeAlias(this.props.Document), undefined, "onClick"), "onRight");
             } else if (this.allLinks && this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) {
                 this.allLinks.length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey);
             } else {
-                if ((this.layoutDoc.onDragStart || (this.props.Document.rootDocument)) && !(e.ctrlKey || e.button > 0)) {  // onDragStart implies a button doc that we don't want to select when clicking.   RootDocument & isTEmplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
+                if ((this.layoutDoc.onDragStart || this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0)) {  // onDragStart implies a button doc that we don't want to select when clicking.   RootDocument & isTemplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
                     stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template
                 } else {
                     SelectionManager.SelectDoc(this, e.ctrlKey || e.shiftKey);
@@ -407,7 +394,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             }
             e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document'  however it does mark the event as cancelBubble=true which we test for in the move event handlers
             e.preventDefault();
-
         }
     }
 
@@ -445,12 +431,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const oldPoint2 = this.prevPoints.get(pt2.identifier);
         const pinching = InteractionUtils.Pinning(pt1, pt2, oldPoint1!, oldPoint2!);
         if (pinching !== 0 && oldPoint1 && oldPoint2) {
-            // let dX = (Math.min(pt1.clientX, pt2.clientX) - Math.min(oldPoint1.clientX, oldPoint2.clientX));
-            // let dY = (Math.min(pt1.clientY, pt2.clientY) - Math.min(oldPoint1.clientY, oldPoint2.clientY));
-            // let dX = Math.sign(Math.abs(pt1.clientX - oldPoint1.clientX) - Math.abs(pt2.clientX - oldPoint2.clientX));
-            // let dY = Math.sign(Math.abs(pt1.clientY - oldPoint1.clientY) - Math.abs(pt2.clientY - oldPoint2.clientY));
-            // let dW = -dX;
-            // let dH = -dY;
             const dW = (Math.abs(pt1.clientX - pt2.clientX) - Math.abs(oldPoint1.clientX - oldPoint2.clientX));
             const dH = (Math.abs(pt1.clientY - pt2.clientY) - Math.abs(oldPoint1.clientY - oldPoint2.clientY));
             const dX = -1 * Math.sign(dW);
@@ -533,7 +513,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     onPointerMove = (e: PointerEvent): void => {
-
         if ((e as any).formattedHandled) { e.stopPropagation(); return; }
         if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || Doc.GetSelectedTool() === InkTool.Highlighter || Doc.GetSelectedTool() === InkTool.Pen)) return;
         if (e.cancelBubble && this.active) {
@@ -554,17 +533,15 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     onPointerUp = (e: PointerEvent): void => {
         this.cleanUpInteractions();
+        document.removeEventListener("pointermove", this.onPointerMove);
+        document.removeEventListener("pointerup", this.onPointerUp);
 
         if (this.onPointerUpHandler?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
             this.onPointerUpHandler.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log);
-            document.removeEventListener("pointerup", this.onPointerUp);
-            return;
+        } else {
+            this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2);
+            this._lastTap = Date.now();
         }
-
-        document.removeEventListener("pointermove", this.onPointerMove);
-        document.removeEventListener("pointerup", this.onPointerUp);
-        this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2);
-        this._lastTap = Date.now();
     }
 
     onGesture = (e: Event, ge: GestureUtils.GestureEvent) => {
@@ -586,54 +563,20 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
     }
 
-    @undoBatch
-    togglePushpin = () => {
+    @undoBatch @action
+    toggleFollowLink = (location: Opt<string>, zoom: boolean, setPushpin: boolean): void => {
         this.Document.ignoreClick = false;
-        if (this.Document.isLinkButton || this.Document.isPushpin || this.onClickHandler || this.Document.ignoreClick) {
-            this.Document.isPushpin = this.Document.isLinkButton = false;
-            this.Document.onClick = this.layoutDoc.onClick = undefined;
+        this.Document.isLinkButton = !this.Document.isLinkButton;
+        setPushpin && (this.Document.isPushpin = this.Document.isLinkButton);
+        if (this.Document.isLinkButton && !this.onClickHandler) {
+            this.Document.followLinkZoom = zoom;
+            this.Document.followLinkLocation = location;
         } else {
-            this.Document.isPushpin = this.Document.isLinkButton = true;
-            this.Document.followLinkZoom = false;
-            this.Document.followLinkLocation = undefined;
-        }
-    }
-
-    @undoBatch
-    toggleLinkButtonBehavior = (): void => {
-        this.Document.ignoreClick = false;
-        if (this.Document.isLinkButton || this.onClickHandler || this.Document.ignoreClick) {
-            this.Document.isLinkButton = false;
             this.Document.onClick = this.layoutDoc.onClick = undefined;
-        } else {
-            this.Document.isLinkButton = true;
-            this.Document.followLinkZoom = false;
-            this.Document.followLinkLocation = undefined;
-        }
-    }
-
-    @undoBatch
-    toggleFollowInPlace = (): void => {
-        this.Document.ignoreClick = false;
-        this.Document.isLinkButton = !this.Document.isLinkButton;
-        if (this.Document.isLinkButton) {
-            this.Document.followLinkZoom = true;
-            this.Document.followLinkLocation = "inPlace";
         }
     }
 
-    @undoBatch
-    toggleFollowOnRight = (): void => {
-        this.Document.ignoreClick = false;
-        this.Document.isLinkButton = !this.Document.isLinkButton;
-        if (this.Document.isLinkButton) {
-            this.Document.followLinkZoom = false;
-            this.Document.followLinkLocation = "onRight";
-        }
-    }
-
-    @undoBatch
-    @action
+    @undoBatch @action
     drop = async (e: Event, de: DragManager.DropEvent) => {
         if (this.props.Document === Doc.UserDoc().activeWorkspace) {
             alert("linking to document tabs not yet supported.  Drop link on document content.");
@@ -663,11 +606,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
         if (de.complete.linkDragData) {
             e.stopPropagation();
-            if (de.complete.linkDragData.linkSourceDocument !== this.props.Document) {
-                const linkDoc = DocUtils.MakeLink({ doc: de.complete.linkDragData.linkSourceDocument },
-                    { doc: this.props.Document }, `link`);
-                de.complete.linkDragData.linkSourceDocument !== this.props.Document &&
-                    (de.complete.linkDragData.linkDocument = linkDoc); // TODODO this is where in text links get passed
+            const linkSource = de.complete.linkDragData.linkSourceDocument;
+            if (linkSource !== this.props.Document) {
+                const linkDoc = DocUtils.MakeLink({ doc: linkSource }, { doc: this.props.Document }, `link`);
+                linkSource !== this.props.Document && (de.complete.linkDragData.linkDocument = linkDoc); // TODODO this is where in text links get passed
                 linkDoc && makeLink(linkDoc);
             }
 
@@ -680,6 +622,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.PanelWidth(), this.props.PanelHeight());
     }
 
+    @undoBatch
+    @action
+    toggleLockPosition = (): void => {
+        this.Document.lockedPosition = this.Document.lockedPosition ? undefined : true;
+    }
+
     @undoBatch
     @action
     makeIntoPortal = async () => {
@@ -694,9 +642,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     @undoBatch
     @action
-    toggleBackground = (temporary: boolean): void => {
-        this.Document._overflow = temporary ? "visible" : "hidden";
-        this.Document.isBackground = !temporary ? !this.Document.isBackground : (this.Document.isBackground ? undefined : true);
+    toggleBackground = () => {
+        this.Document.isBackground = (this.Document.isBackground ? undefined : true);
+        this.Document._overflow = this.Document.isBackground ? "visible" : undefined;
         if (this.Document.isBackground) {
             this.props.bringToFront(this.props.Document, true);
             this.props.Document[DataSym][Doc.LayoutFieldKey(this.Document) + "-nativeWidth"] = this.Document[WidthSym]();
@@ -704,41 +652,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
     }
 
-    @undoBatch
-    @action
-    toggleLockPosition = (): void => {
-        this.Document.lockedPosition = this.Document.lockedPosition ? undefined : true;
-    }
-
-    @undoBatch
-    @action
-    setAcl = (acl: SharingPermissions) => {
-        this.dataDoc.ACL = this.props.Document.ACL = acl;
-        DocListCast(this.dataDoc[Doc.LayoutFieldKey(this.dataDoc)]).map(d => {
-            if (d.author === Doc.CurrentUserEmail) d.ACL = acl;
-            const data = d[DataSym];
-            if (data && data.author === Doc.CurrentUserEmail) data.ACL = acl;
-        });
-    }
-
-    @undoBatch
-    @action
-    testAcl = (acl: SharingPermissions) => {
-        this.dataDoc.author = this.props.Document.author = "ADMIN";
-        this.dataDoc.ACL = this.props.Document.ACL = acl;
-        DocListCast(this.dataDoc[Doc.LayoutFieldKey(this.dataDoc)]).map(d => {
-            if (d.author === Doc.CurrentUserEmail) {
-                d.author = "ADMIN";
-                d.ACL = acl;
-            }
-            const data = d[DataSym];
-            if (data && data.author === Doc.CurrentUserEmail) {
-                data.author = "ADMIN";
-                data.ACL = acl;
-            }
-        });
-    }
-
     @action
     onContextMenu = async (e: React.MouseEvent | Touch): Promise<void> => {
         // the touch onContextMenu is button 0, the pointer onContextMenu is button 2
@@ -785,10 +698,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" });
         onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.Document.layoutKey}")`), icon: "window-restore" });
         onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" });
-        onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: this.toggleFollowInPlace, icon: "concierge-bell" });
-        onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link on Right", event: this.toggleFollowOnRight, icon: "concierge-bell" });
-        onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? "Remove Click Behavior" : "Follow Link", event: this.toggleLinkButtonBehavior, icon: "concierge-bell" });
-        onClicks.push({ description: (this.Document.isPushpin ? "Remove" : "Make") + " Pushpin", event: this.togglePushpin, icon: "snowflake" });
+        onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: () => this.toggleFollowLink("inPlace", true, false), icon: "concierge-bell" });
+        !this.Document.isLinkButton && onClicks.push({ description: "Follow Link on Right", event: () => this.toggleFollowLink("onRight", false, false), icon: "concierge-bell" });
+        onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? "Remove Click Behavior" : "Follow Link", event: () => this.toggleFollowLink(undefined, false, false), icon: "concierge-bell" });
+        onClicks.push({ description: (this.Document.isPushpin ? "Remove" : "Make") + " Pushpin", event: () => this.toggleFollowLink(undefined, false, true), icon: "snowflake" });
         onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "edit" });
         !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, addDivider: true, subitems: onClicks, icon: "hand-point-right" });
 
@@ -802,16 +715,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
         const more = cm.findByDescription("More...");
         const moreItems = more && "subitems" in more ? more.subitems : [];
-        moreItems.push({
-            description: "Download document", icon: "download", event: async () => {
-                Doc.Zip(this.props.Document);
-                // const a = document.createElement("a");
-                // const url = Utils.prepend(`/downloadId/${this.props.Document[Id]}`);
-                // a.href = url;
-                // a.download = `DocExport-${this.props.Document[Id]}.zip`;
-                // a.click();
-            }
-        });
+        moreItems.push({ description: "Download document", icon: "download", event: async () => Doc.Zip(this.props.Document) });
         if (!Doc.UserDoc().noviceMode) {
             moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" });
             moreItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" });
@@ -836,179 +740,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         helpItems.push({ description: "Print Document in Console", event: () => console.log(this.props.Document), icon: "hand-point-right" });
         cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" });
 
-        // const existingAcls = cm.findByDescription("Privacy...");
-        // const aclItems: ContextMenuProps[] = existingAcls && "subitems" in existingAcls ? existingAcls.subitems : [];
-        // aclItems.push({ description: "Make Add Only", event: () => this.setAcl(SharingPermissions.Add), icon: "concierge-bell" });
-        // aclItems.push({ description: "Make Read Only", event: () => this.setAcl(SharingPermissions.View), icon: "concierge-bell" });
-        // aclItems.push({ description: "Make Private", event: () => this.setAcl(SharingPermissions.None), icon: "concierge-bell" });
-        // aclItems.push({ description: "Make Editable", event: () => this.setAcl(SharingPermissions.Edit), icon: "concierge-bell" });
-        // aclItems.push({ description: "Test Private", event: () => this.testAcl(SharingPermissions.None), icon: "concierge-bell" });
-        // aclItems.push({ description: "Test Readonly", event: () => this.testAcl(SharingPermissions.View), icon: "concierge-bell" });
-        // !existingAcls && cm.addItem({ description: "Privacy...", subitems: aclItems, icon: "question" });
-
-        // cm.addItem({ description: `${getPlaygroundMode() ? "Disable" : "Enable"} playground mode`, event: togglePlaygroundMode, icon: "concierge-bell" });
-
-        // const recommender_subitems: ContextMenuProps[] = [];
-
-        // recommender_subitems.push({
-        //     description: "Internal recommendations",
-        //     event: () => this.recommender(),
-        //     icon: "brain"
-        // });
-
-        // const ext_recommender_subitems: ContextMenuProps[] = [];
-
-        // ext_recommender_subitems.push({
-        //     description: "arXiv",
-        //     event: () => this.externalRecommendation("arxiv"),
-        //     icon: "brain"
-        // });
-        // ext_recommender_subitems.push({
-        //     description: "Bing",
-        //     event: () => this.externalRecommendation("bing"),
-        //     icon: "brain"
-        // });
-
-        // recommender_subitems.push({
-        //     description: "External recommendations",
-        //     subitems: ext_recommender_subitems,
-        //     icon: "brain"
-        // });
-
-
-        //moreItems.push({ description: "Recommender System", subitems: recommender_subitems, icon: "brain" });
-        //moreItems.push({ description: "Publish", event: () => DocUtils.Publish(this.props.Document, this.Document.title || "", this.props.addDocument, this.props.removeDocument), icon: "file" });
-        //moreItems.push({ description: "Undo Debug Test", event: () => UndoManager.TraceOpenBatches(), icon: "exclamation" });
-
-        // runInAction(() => {
-        //     const setWriteMode = (mode: DocServer.WriteMode) => {
-        //         DocServer.AclsMode = mode;
-        //         const mode1 = mode;
-        //         const mode2 = mode === DocServer.WriteMode.Default ? mode : DocServer.WriteMode.Playground;
-        //         DocServer.setFieldWriteMode("x", mode1);
-        //         DocServer.setFieldWriteMode("y", mode1);
-        //         DocServer.setFieldWriteMode("_width", mode1);
-        //         DocServer.setFieldWriteMode("_height", mode1);
-
-        //         DocServer.setFieldWriteMode("_panX", mode2);
-        //         DocServer.setFieldWriteMode("_panY", mode2);
-        //         DocServer.setFieldWriteMode("scale", mode2);
-        //         DocServer.setFieldWriteMode("_viewType", mode2);
-        //     };
-        //     const aclsMenu: ContextMenuProps[] = [];
-        //     aclsMenu.push({ description: "Default (write/read all)", event: () => setWriteMode(DocServer.WriteMode.Default), icon: DocServer.AclsMode === DocServer.WriteMode.Default ? "check" : "exclamation" });
-        //     aclsMenu.push({ description: "Playground (write own/no read)", event: () => setWriteMode(DocServer.WriteMode.Playground), icon: DocServer.AclsMode === DocServer.WriteMode.Playground ? "check" : "exclamation" });
-        //     aclsMenu.push({ description: "Live Playground (write own/read others)", event: () => setWriteMode(DocServer.WriteMode.LivePlayground), icon: DocServer.AclsMode === DocServer.WriteMode.LivePlayground ? "check" : "exclamation" });
-        //     aclsMenu.push({ description: "Live Readonly (no write/read others)", event: () => setWriteMode(DocServer.WriteMode.LiveReadonly), icon: DocServer.AclsMode === DocServer.WriteMode.LiveReadonly ? "check" : "exclamation" });
-        //     cm.addItem({ description: "Collaboration ...", subitems: aclsMenu, icon: "share" });
-        // });
         runInAction(() => {
             if (!this.topMost && !(e instanceof Touch)) {
-                // DocumentViews should stop propagation of this event
-                e.stopPropagation();
+                e.stopPropagation(); // DocumentViews should stop propagation of this event
             }
             cm.displayMenu(e.pageX - 15, e.pageY - 15);
             !SelectionManager.IsSelected(this, true) && SelectionManager.SelectDoc(this, false);
         });
-        const path = this.props.LibraryPath.reduce((p: string, d: Doc) => p + "/" + (Doc.AreProtosEqual(d, (Doc.UserDoc()["tabs-button-library"] as Doc).sourcePanel as Doc) ? "" : d.title), "");
-        const item = ({
-            description: `path: ${path}`, event: () => {
-                if (this.props.LibraryPath !== emptyPath) {
-                    this.props.LibraryPath.map(lp => Doc.GetProto(lp).treeViewOpen = lp.treeViewOpen = true);
-                    Doc.linkFollowHighlight(this.props.Document);
-                } else {
-                    Doc.AddDocToList(Doc.GetProto(Doc.UserDoc().myCatalog as Doc), "data", this.props.Document[DataSym]);
-                }
-            }, icon: "check"
-        });
-        //cm.addItem(item);
-    }
-
-    recommender = async () => {
-        if (!ClientRecommender.Instance) new ClientRecommender({ title: "Client Recommender" });
-        const documents: Doc[] = [];
-        const allDocs = await SearchUtil.GetAllDocs();
-        // clears internal representation of documents as vectors
-        ClientRecommender.Instance.reset_docs();
-        //ClientRecommender.Instance.arxivrequest("electrons");
-        await Promise.all(allDocs.map((doc: Doc) => {
-            let isMainDoc: boolean = false;
-            const dataDoc = Doc.GetProto(doc);
-            if (doc.type === DocumentType.RTF) {
-                if (dataDoc === Doc.GetProto(this.props.Document)) {
-                    isMainDoc = true;
-                }
-                if (!documents.includes(dataDoc)) {
-                    documents.push(dataDoc);
-                    const extdoc = doc.data_ext as Doc;
-                    return ClientRecommender.Instance.extractText(doc, extdoc ? extdoc : doc, true, "", isMainDoc);
-                }
-            }
-            if (doc.type === DocumentType.IMG) {
-                if (dataDoc === Doc.GetProto(this.props.Document)) {
-                    isMainDoc = true;
-                }
-                if (!documents.includes(dataDoc)) {
-                    documents.push(dataDoc);
-                    const extdoc = doc.data_ext as Doc;
-                    return ClientRecommender.Instance.extractText(doc, extdoc ? extdoc : doc, true, "", isMainDoc, true);
-                }
-            }
-        }));
-        const doclist = ClientRecommender.Instance.computeSimilarities("cosine");
-        const recDocs: { preview: Doc, score: number }[] = [];
-        // tslint:disable-next-line: prefer-for-of
-        for (let i = 0; i < doclist.length; i++) {
-            recDocs.push({ preview: doclist[i].actualDoc, score: doclist[i].score });
-        }
-
-        const data = recDocs.map(unit => {
-            unit.preview.score = unit.score;
-            return unit.preview;
-        });
-
-        console.log(recDocs.map(doc => doc.score));
-
-        const title = `Showing ${data.length} recommendations for "${StrCast(this.props.Document.title)}"`;
-        const recommendations = Docs.Create.RecommendationsDocument(data, { title });
-        recommendations.documentIconHeight = 150;
-        recommendations.sourceDoc = this.props.Document;
-        recommendations.sourceDocContext = this.props.ContainingCollectionView!.props.Document;
-        this.props.addDocTab(recommendations, "onRight");
-
-        // RecommendationsBox.Instance.displayRecommendations(e.pageX + 100, e.pageY);
-    }
-
-    @action
-    externalRecommendation = async (api: string) => {
-        if (!ClientRecommender.Instance) new ClientRecommender({ title: "Client Recommender" });
-        ClientRecommender.Instance.reset_docs();
-        const doc = Doc.GetDataDoc(this.props.Document);
-        const extdoc = doc.data_ext as Doc;
-        const recs_and_kps = await ClientRecommender.Instance.extractText(doc, extdoc ? extdoc : doc, false, api);
-        let recs: any;
-        let kps: any;
-        if (recs_and_kps) {
-            recs = recs_and_kps.recs;
-            kps = recs_and_kps.keyterms;
-        }
-        else {
-            console.log("recommender system failed :(");
-            return;
-        }
-        console.log("ibm keyterms: ", kps.toString());
-        const headers = [new SchemaHeaderField("title"), new SchemaHeaderField("href")];
-        const bodies: Doc[] = [];
-        const titles = recs.title_vals;
-        const urls = recs.url_vals;
-        for (let i = 0; i < 5; i++) {
-            const body = Docs.Create.FreeformDocument([], { title: titles[i] });
-            body.href = urls[i];
-            bodies.push(body);
-        }
-        this.props.addDocTab(Docs.Create.SchemaDocument(headers, bodies, { title: `Showing External Recommendations for "${StrCast(doc.title)}"` }), "onRight");
-        this._showKPQuery = true;
-        this._queries = kps.toString();
     }
 
     // does Document set a layout prop
@@ -1088,7 +826,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     // used to decide whether a link anchor view should be created or not.
-    // if it's a tempoarl link (currently just for Audio), then the audioBox will display the anchor and we don't want to display it here.
+    // if it's a temporal link (currently just for Audio), then the audioBox will display the anchor and we don't want to display it here.
     // would be good to generalize this some way.
     isNonTemporalLink = (linkDoc: Doc) => {
         const anchor = Cast(Doc.AreProtosEqual(this.props.Document, Cast(linkDoc.anchor1, Doc) as Doc) ? linkDoc.anchor1 : linkDoc.anchor2, Doc) as Doc;
@@ -1096,7 +834,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         return anchor.type === DocumentType.AUDIO && NumCast(ept) ? false : true;
     }
 
-
     @observable _link: Opt<Doc>;  // see DocumentButtonBar for explanation of how this works
     makeLink = () => this._link; // pass the link placeholde to child views so they can react to make a specialized anchor.  This is essentially a function call to the descendants since the value of the _link variable will immediately get set back to undefined.
 
@@ -1186,7 +923,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             DocUtils.makeCustomViewClicked(this.props.Document, Docs.Create.StackingDocument, layout, undefined);
         }
     }
-    @observable _animateScalingTo = 0;
+
     switchViews = action((custom: boolean, view: string) => {
         this._animateScalingTo = 0.1;  // shrink doc
         setTimeout(action(() => {
@@ -1200,7 +937,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         return (this.Document.isBackground !== undefined || this.isSelected(false)) &&
             ((this.Document.type === DocumentType.COL && this.Document._viewType !== CollectionViewType.Pile) || this.Document.type === DocumentType.IMG) &&
             this.props.renderDepth > 0 && !this.props.treeViewDoc ?
-            <div className="documentView-lock" onClick={() => this.toggleBackground(true)}>
+            <div className="documentView-lock" onClick={this.toggleBackground}>
                 <FontAwesomeIcon icon={this.Document.isBackground ? "unlock" : "lock"} style={{ color: this.Document.isBackground ? "red" : undefined }} size="lg" />
             </div>
             : (null);
@@ -1224,7 +961,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const highlightStyles = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid"];
         let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc._viewType !== CollectionViewType.Linear && this.props.Document.type !== DocumentType.INK;
         highlighting = highlighting && this.props.focus !== emptyFunction;  // bcz: hack to turn off highlighting onsidebar panel documents.  need to flag a document as not highlightable in a more direct way
-        return <div className={`documentView-node${this.topMost ? "-topmost" : ""}`}
+        const topmost = this.topMost ? "-topmost" : "";
+        return <div className={`documentView-node${topmost}`}
             id={this.props.Document[Id]}
             ref={this._mainCont} onKeyDown={this.onKeyDown}
             onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick}
@@ -1266,7 +1004,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 this.innards}
             {this.renderLock()}
         </div>;
-        { this._showKPQuery ? <KeyphraseQueryView keyphrases={this._queries}></KeyphraseQueryView> : undefined; }
     }
 }
 
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 5f689624c..d668d332b 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -66,7 +66,7 @@ const uploadIcons = {
 
 @observer
 export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageDocument>(ImageDocument) {
-    protected multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined;
+    protected _multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined;
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); }
     private _imgRef: React.RefObject<HTMLImageElement> = React.createRef();
     private _dropDisposer?: DragManager.DragDropDisposer;
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
index bc43cd473..1a5edc1d9 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -32,7 +32,7 @@ const ScriptingDocument = makeInterface(ScriptingSchema, documentSchema);
 export class ScriptingBox extends ViewBoxAnnotatableComponent<FieldViewProps, ScriptingDocument>(ScriptingDocument) {
 
     private dropDisposer?: DragManager.DragDropDisposer;
-    protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer | undefined;
+    protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer | undefined;
     public static LayoutString(fieldStr: string) { return FieldView.LayoutString(ScriptingBox, fieldStr); }
     private _overlayDisposer?: () => void;
     private _caretPos = 0;
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 87acb2ea7..267defa4b 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -587,6 +587,11 @@ export namespace Doc {
     }
 
     export async function Zip(doc: Doc) {
+        // const a = document.createElement("a");
+        // const url = Utils.prepend(`/downloadId/${this.props.Document[Id]}`);
+        // a.href = url;
+        // a.download = `DocExport-${this.props.Document[Id]}.zip`;
+        // a.click();
         const { clone, map } = await Doc.MakeClone(doc, true);
         function replacer(key: any, value: any) {
             if (["cloneOf", "context", "cursors"].includes(key)) return undefined;
-- 
cgit v1.2.3-70-g09d2


From ba52b0373a3ce559114c7b6337149c769053c4dc Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 28 Jul 2020 12:00:23 -0400
Subject: fixed selectin collections to show up in CollectionMenu

---
 src/client/views/collections/CollectionView.tsx | 1 -
 1 file changed, 1 deletion(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index e7a504e61..5a3396b68 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -572,7 +572,6 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
             ChildLayoutTemplate: this.childLayoutTemplate,
             ChildLayoutString: this.childLayoutString,
         };
-        setTimeout(() => this.props.isSelected(true) && CollectionMenu.Instance.SetSelection(this, this.props.fieldKey), 0);
         const boxShadow = Doc.UserDoc().renderStyle === "comic" || this.props.Document.isBackground || this.collectionViewType === CollectionViewType.Linear ? undefined :
             `${Cast(Doc.UserDoc().activeWorkspace, Doc, null)?.darkScheme ? "rgb(30, 32, 31) " : "#9c9396 "} ${StrCast(this.props.Document.boxShadow, "0.2vw 0.2vw 0.8vw")}`;
         return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
-- 
cgit v1.2.3-70-g09d2


From 2fb042f575626cc6f938eec57c8e71e45ff6b1d5 Mon Sep 17 00:00:00 2001
From: usodhi <61431818+usodhi@users.noreply.github.com>
Date: Wed, 29 Jul 2020 23:30:20 +0530
Subject: anyone can share without setting acls + fixed some inheriting stuff +
 deleting stuff + some cleanup

---
 src/client/util/SharingManager.scss             |   2 +-
 src/client/util/SharingManager.tsx              |  63 ++++++++-------
 src/client/views/DocComponent.tsx               |  18 ++---
 src/client/views/DocumentDecorations.tsx        |  27 ++++---
 src/client/views/collections/CollectionView.tsx |  34 ++++----
 src/client/views/nodes/DocumentView.tsx         | 100 ------------------------
 src/client/views/nodes/TaskCompletedBox.tsx     |   2 -
 7 files changed, 76 insertions(+), 170 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/util/SharingManager.scss b/src/client/util/SharingManager.scss
index 2ce9f232c..8da80ef52 100644
--- a/src/client/util/SharingManager.scss
+++ b/src/client/util/SharingManager.scss
@@ -50,7 +50,7 @@
                 .share-button {
                     height: 105%;
                     margin-left: 2%;
-                    background-color: #979797;
+                    background-color: black;
                 }
             }
 
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index ec04bdd81..83524f062 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -1,7 +1,7 @@
 import { observable, runInAction, action } from "mobx";
 import * as React from "react";
 import MainViewModal from "../views/MainViewModal";
-import { Doc, Opt, DocListCastAsync } from "../../fields/Doc";
+import { Doc, Opt, DocListCastAsync, AclAdmin, DataSym } from "../../fields/Doc";
 import { DocServer } from "../DocServer";
 import { Cast, StrCast } from "../../fields/Types";
 import * as RequestPromise from "request-promise";
@@ -82,6 +82,7 @@ export default class SharingManager extends React.Component<{}> {
     // }
 
     public open = (target: DocumentView) => {
+        runInAction(() => this.users = []);
         SelectionManager.DeselectAll();
         this.populateUsers().then(action(() => {
             this.targetDocView = target;
@@ -145,7 +146,7 @@ export default class SharingManager extends React.Component<{}> {
         const target = this.targetDoc!;
         const ACL = `ACL-${StrCast(group.groupName)}`;
 
-        distributeAcls(ACL, permission as SharingPermissions, target);
+        target.author === Doc.CurrentUserEmail && distributeAcls(ACL, permission as SharingPermissions, target);
 
         // if documents have been shared, add the target to that list if it doesn't already exist, otherwise create a new list with the target
         group.docsShared ? DocListCastAsync(group.docsShared).then(resolved => Doc.IndexOf(target, resolved!) === -1 && (group.docsShared as List<Doc>).push(target)) : group.docsShared = new List<Doc>([target]);
@@ -220,7 +221,7 @@ export default class SharingManager extends React.Component<{}> {
         const key = user.email.replace('.', '_');
         const ACL = `ACL-${key}`;
 
-        distributeAcls(ACL, permission as SharingPermissions, this.targetDoc!);
+        target.author === Doc.CurrentUserEmail && distributeAcls(ACL, permission as SharingPermissions, target);
 
         if (permission !== SharingPermissions.None) {
             DocListCastAsync(notificationDoc[storage]).then(resolved => {
@@ -385,7 +386,7 @@ export default class SharingManager extends React.Component<{}> {
             const userKey = user.email.replace('.', '_');
             const permissions = StrCast(this.targetDoc?.[`ACL-${userKey}`], SharingPermissions.None);
 
-            return permissions === SharingPermissions.None || user.email === this.targetDoc?.author ? null : (
+            return user.email === this.targetDoc?.author ? null : (
                 <div
                     key={userKey}
                     className={"container"}
@@ -490,36 +491,34 @@ export default class SharingManager extends React.Component<{}> {
                     <div className={"close-button"} onClick={this.close}>
                         <FontAwesomeIcon icon={fa.faTimes} color={"black"} size={"lg"} />
                     </div>
-                    {this.targetDoc?.author !== Doc.CurrentUserEmail ? null
-                        :
-                        <div className="share-container">
-                            <div className="share-setup">
-                                <Select
-                                    className={"user-search"}
-                                    placeholder={"Enter user or group name..."}
-                                    isMulti
-                                    closeMenuOnSelect={false}
-                                    options={options}
-                                    onChange={this.handleUsersChange}
-                                    value={this.selectedUsers}
-                                    styles={{
-                                        indicatorSeparator: () => ({
-                                            visibility: "hidden"
-                                        })
-                                    }}
-                                />
-                                <select className="permissions-select" onChange={this.handlePermissionsChange}>
-                                    {this.sharingOptions}
-                                </select>
-                                <button ref={this.shareDocumentButtonRef} className="share-button" onClick={this.share}>
-                                    Share
+                    {<div className="share-container">
+                        <div className="share-setup">
+                            <Select
+                                className={"user-search"}
+                                placeholder={"Enter user or group name..."}
+                                isMulti
+                                closeMenuOnSelect={false}
+                                options={options}
+                                onChange={this.handleUsersChange}
+                                value={this.selectedUsers}
+                                styles={{
+                                    indicatorSeparator: () => ({
+                                        visibility: "hidden"
+                                    })
+                                }}
+                            />
+                            <select className="permissions-select" onChange={this.handlePermissionsChange}>
+                                {this.sharingOptions}
+                            </select>
+                            <button ref={this.shareDocumentButtonRef} className="share-button" onClick={this.share}>
+                                Share
                             </button>
-                            </div>
-                            <div className="sort-checkboxes">
-                                <input type="checkbox" onChange={action(() => this.showUserOptions = !this.showUserOptions)} /> <label style={{ marginRight: 10 }}>Individuals</label>
-                                <input type="checkbox" onChange={action(() => this.showGroupOptions = !this.showGroupOptions)} /> <label>Groups</label>
-                            </div>
                         </div>
+                        <div className="sort-checkboxes">
+                            <input type="checkbox" onChange={action(() => this.showUserOptions = !this.showUserOptions)} /> <label style={{ marginRight: 10 }}>Individuals</label>
+                            <input type="checkbox" onChange={action(() => this.showGroupOptions = !this.showGroupOptions)} /> <label>Groups</label>
+                        </div>
+                    </div>
                     }
                     <div className="main-container">
                         <div className={"individual-container"}>
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 9fd406407..ae180a78b 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -154,15 +154,15 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
                     return false;
                 }
                 else {
-                    if (this.props.Document[AclSym]) {
-                        added.forEach(d => {
-                            const dataDoc = d[DataSym];
-                            dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym];
-                            for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
-                                dataDoc[key] = d[key] = this.AclMap.get(value);
-                            }
-                        });
-                    }
+                    // if (this.props.Document[AclSym]) {
+                    //     added.forEach(d => {
+                    //         const dataDoc = d[DataSym];
+                    //         dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym];
+                    //         for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
+                    //             dataDoc[key] = d[key] = this.AclMap.get(value);
+                    //         }
+                    //     });
+                    // }
                     if (effectiveAcl === AclAddonly) {
                         added.map(doc => Doc.AddDocToList(targetDataDoc, this.annotationKey, doc));
                     }
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 8d63537e7..655f330e3 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,9 +1,9 @@
 import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
 import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faTextHeight, faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faShare, faStopCircle, faSyncAlt, faTag, faTimes, faAngleLeft, faAngleRight, faAngleDoubleLeft, faAngleDoubleRight, faPause } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, observable, reaction, runInAction } from "mobx";
+import { action, computed, observable, reaction, runInAction, get } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, DataSym, Field, WidthSym, HeightSym } from "../../fields/Doc";
+import { Doc, DataSym, Field, WidthSym, HeightSym, AclEdit, AclAdmin } from "../../fields/Doc";
 import { Document } from '../../fields/documentSchemas';
 import { ScriptField } from '../../fields/ScriptField';
 import { Cast, StrCast, NumCast } from "../../fields/Types";
@@ -23,6 +23,9 @@ import { SnappingManager } from '../util/SnappingManager';
 import { HtmlField } from '../../fields/HtmlField';
 import { InkData, InkField, InkTool } from "../../fields/InkField";
 import { Tooltip } from '@material-ui/core';
+import { GetEffectiveAcl } from '../../fields/util';
+import { DocumentIcon } from './nodes/DocumentIcon';
+import { render } from 'react-dom';
 
 library.add(faCaretUp);
 library.add(faObjectGroup);
@@ -193,8 +196,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
             SelectionManager.DeselectAll();
 
             selected.map(dv => {
-                recent && Doc.AddDocToList(recent, "data", dv.props.Document, undefined, true, true);
-                dv.props.removeDocument?.(dv.props.Document);
+                const effectiveAcl = GetEffectiveAcl(dv.props.Document);
+                if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) { // deletes whatever you have the right to delete
+                    recent && Doc.AddDocToList(recent, "data", dv.props.Document, undefined, true, true);
+                    dv.props.removeDocument?.(dv.props.Document);
+                }
             });
         }
     }
@@ -545,17 +551,18 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         if (SnappingManager.GetIsDragging() || bounds.r - bounds.x < 2 || bounds.x === Number.MAX_VALUE || !seldoc || this._hidden || isNaN(bounds.r) || isNaN(bounds.b) || isNaN(bounds.x) || isNaN(bounds.y)) {
             return (null);
         }
+        const canDelete = SelectionManager.SelectedDocuments().map(docView => GetEffectiveAcl(docView.props.Document)).some(permission => permission === AclAdmin || permission === AclEdit);
         const minimal = bounds.r - bounds.x < 100 ? true : false;
         const maximizeIcon = minimal ? (
             <Tooltip title={<><div className="dash-tooltip">Show context menu</div></>} placement="top">
                 <div className="documentDecorations-contextMenu" onPointerDown={this.onSettingsDown}>
                     <FontAwesomeIcon size="lg" icon="cog" />
-                </div></Tooltip>) : (
-                <Tooltip title={<><div className="dash-tooltip">Delete</div></>} placement="top">
-                    <div className="documentDecorations-closeButton" onClick={this.onCloseClick}>
-                        {/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/}
-                        <FontAwesomeIcon className="documentdecorations-times" icon={faTimes} size="lg" />
-                    </div></Tooltip>);
+                </div></Tooltip>) : canDelete ? (
+                    <Tooltip title={<><div className="dash-tooltip">Delete</div></>} placement="top">
+                        <div className="documentDecorations-closeButton" onClick={this.onCloseClick}>
+                            {/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/}
+                            <FontAwesomeIcon className="documentdecorations-times" icon={faTimes} size="lg" />
+                        </div></Tooltip>) : null;
 
         const titleArea = this._edtingTitle ?
             <>
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index a82c91383..3bb1022e0 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -17,7 +17,7 @@ import { listSpec } from '../../../fields/Schema';
 import { ComputedField, ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
-import { TraceMobx, GetEffectiveAcl, getPlaygroundMode, distributeAcls, SharingPermissions } from '../../../fields/util';
+import { TraceMobx, GetEffectiveAcl, getPlaygroundMode, SharingPermissions } from '../../../fields/util';
 import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
@@ -149,16 +149,16 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 return false;
             }
             else {
-                if (this.props.Document[AclSym]) {
-                    // change so it only adds if more restrictive
-                    added.forEach(d => {
-                        // const dataDoc = d[DataSym];
-                        for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
-                            distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true);
-                        }
-                        // dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym];
-                    });
-                }
+                // if (this.props.Document[AclSym]) {
+                //     // change so it only adds if more restrictive
+                //     added.forEach(d => {
+                //         // const dataDoc = d[DataSym];
+                //         for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
+                //             // key.substring(4).replace("_", ".") !== Doc.CurrentUserEmail && distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true);
+                //             distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true);
+                //         }
+                //     });
+                // }
 
                 if (effectiveAcl === AclAddonly) {
                     added.map(doc => Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc));
@@ -192,14 +192,16 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
 
     @action.bound
     removeDocument = (doc: any): boolean => {
-        const effectiveAcl = GetEffectiveAcl(this.props.Document);
-        if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin || getPlaygroundMode()) {
+        const collectionEffectiveAcl = GetEffectiveAcl(this.props.Document);
+        const docEffectiveAcl = GetEffectiveAcl(doc);
+        // you can remove the document if you either have Admin/Edit access to the collection or to the specific document
+        if (collectionEffectiveAcl === AclEdit || collectionEffectiveAcl === AclAdmin || docEffectiveAcl === AclAdmin || docEffectiveAcl === AclEdit || getPlaygroundMode()) {
             const docs = doc instanceof Doc ? [doc] : doc as Doc[];
             const targetDataDoc = this.props.Document[DataSym];
             const value = DocListCast(targetDataDoc[this.props.fieldKey]);
-            const result = value.filter(v => !docs.includes(v));
-            if (result.length !== value.length) {
-                targetDataDoc[this.props.fieldKey] = new List<Doc>(result);
+            const toRemove = value.filter(v => docs.includes(v));
+            if (toRemove.length !== 0) {
+                toRemove.forEach(doc => Doc.RemoveDocFromList(targetDataDoc, this.props.fieldKey, doc));
                 return true;
             }
         }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b59875a7e..1d89f3d24 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -697,35 +697,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         this.Document.lockedPosition = this.Document.lockedPosition ? undefined : true;
     }
 
-    @undoBatch
-    @action
-    setAcl = (acl: SharingPermissions) => {
-        this.dataDoc.ACL = this.props.Document.ACL = acl;
-        DocListCast(this.dataDoc[Doc.LayoutFieldKey(this.dataDoc)]).map(d => {
-            if (d.author === Doc.CurrentUserEmail) d.ACL = acl;
-            const data = d[DataSym];
-            if (data && data.author === Doc.CurrentUserEmail) data.ACL = acl;
-        });
-    }
-
-    @undoBatch
-    @action
-    testAcl = (acl: SharingPermissions) => {
-        this.dataDoc.author = this.props.Document.author = "ADMIN";
-        this.dataDoc.ACL = this.props.Document.ACL = acl;
-        DocListCast(this.dataDoc[Doc.LayoutFieldKey(this.dataDoc)]).map(d => {
-            if (d.author === Doc.CurrentUserEmail) {
-                d.author = "ADMIN";
-                d.ACL = acl;
-            }
-            const data = d[DataSym];
-            if (data && data.author === Doc.CurrentUserEmail) {
-                data.author = "ADMIN";
-                data.ACL = acl;
-            }
-        });
-    }
-
     @action
     onContextMenu = async (e: React.MouseEvent | Touch): Promise<void> => {
         // the touch onContextMenu is button 0, the pointer onContextMenu is button 2
@@ -791,11 +762,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         moreItems.push({
             description: "Download document", icon: "download", event: async () => {
                 Doc.Zip(this.props.Document);
-                // const a = document.createElement("a");
-                // const url = Utils.prepend(`/downloadId/${this.props.Document[Id]}`);
-                // a.href = url;
-                // a.download = `DocExport-${this.props.Document[Id]}.zip`;
-                // a.click();
             }
         });
         if (!Doc.UserDoc().noviceMode) {
@@ -822,72 +788,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         helpItems.push({ description: "Print Document in Console", event: () => console.log(this.props.Document), icon: "hand-point-right" });
         cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" });
 
-        // const existingAcls = cm.findByDescription("Privacy...");
-        // const aclItems: ContextMenuProps[] = existingAcls && "subitems" in existingAcls ? existingAcls.subitems : [];
-        // aclItems.push({ description: "Make Add Only", event: () => this.setAcl(SharingPermissions.Add), icon: "concierge-bell" });
-        // aclItems.push({ description: "Make Read Only", event: () => this.setAcl(SharingPermissions.View), icon: "concierge-bell" });
-        // aclItems.push({ description: "Make Private", event: () => this.setAcl(SharingPermissions.None), icon: "concierge-bell" });
-        // aclItems.push({ description: "Make Editable", event: () => this.setAcl(SharingPermissions.Edit), icon: "concierge-bell" });
-        // aclItems.push({ description: "Test Private", event: () => this.testAcl(SharingPermissions.None), icon: "concierge-bell" });
-        // aclItems.push({ description: "Test Readonly", event: () => this.testAcl(SharingPermissions.View), icon: "concierge-bell" });
-        // !existingAcls && cm.addItem({ description: "Privacy...", subitems: aclItems, icon: "question" });
-
-        // cm.addItem({ description: `${getPlaygroundMode() ? "Disable" : "Enable"} playground mode`, event: togglePlaygroundMode, icon: "concierge-bell" });
-
-        // const recommender_subitems: ContextMenuProps[] = [];
-
-        // recommender_subitems.push({
-        //     description: "Internal recommendations",
-        //     event: () => this.recommender(),
-        //     icon: "brain"
-        // });
-
-        // const ext_recommender_subitems: ContextMenuProps[] = [];
-
-        // ext_recommender_subitems.push({
-        //     description: "arXiv",
-        //     event: () => this.externalRecommendation("arxiv"),
-        //     icon: "brain"
-        // });
-        // ext_recommender_subitems.push({
-        //     description: "Bing",
-        //     event: () => this.externalRecommendation("bing"),
-        //     icon: "brain"
-        // });
-
-        // recommender_subitems.push({
-        //     description: "External recommendations",
-        //     subitems: ext_recommender_subitems,
-        //     icon: "brain"
-        // });
-
-
-        //moreItems.push({ description: "Recommender System", subitems: recommender_subitems, icon: "brain" });
-        //moreItems.push({ description: "Publish", event: () => DocUtils.Publish(this.props.Document, this.Document.title || "", this.props.addDocument, this.props.removeDocument), icon: "file" });
-        //moreItems.push({ description: "Undo Debug Test", event: () => UndoManager.TraceOpenBatches(), icon: "exclamation" });
-
-        // runInAction(() => {
-        //     const setWriteMode = (mode: DocServer.WriteMode) => {
-        //         DocServer.AclsMode = mode;
-        //         const mode1 = mode;
-        //         const mode2 = mode === DocServer.WriteMode.Default ? mode : DocServer.WriteMode.Playground;
-        //         DocServer.setFieldWriteMode("x", mode1);
-        //         DocServer.setFieldWriteMode("y", mode1);
-        //         DocServer.setFieldWriteMode("_width", mode1);
-        //         DocServer.setFieldWriteMode("_height", mode1);
-
-        //         DocServer.setFieldWriteMode("_panX", mode2);
-        //         DocServer.setFieldWriteMode("_panY", mode2);
-        //         DocServer.setFieldWriteMode("scale", mode2);
-        //         DocServer.setFieldWriteMode("_viewType", mode2);
-        //     };
-        //     const aclsMenu: ContextMenuProps[] = [];
-        //     aclsMenu.push({ description: "Default (write/read all)", event: () => setWriteMode(DocServer.WriteMode.Default), icon: DocServer.AclsMode === DocServer.WriteMode.Default ? "check" : "exclamation" });
-        //     aclsMenu.push({ description: "Playground (write own/no read)", event: () => setWriteMode(DocServer.WriteMode.Playground), icon: DocServer.AclsMode === DocServer.WriteMode.Playground ? "check" : "exclamation" });
-        //     aclsMenu.push({ description: "Live Playground (write own/read others)", event: () => setWriteMode(DocServer.WriteMode.LivePlayground), icon: DocServer.AclsMode === DocServer.WriteMode.LivePlayground ? "check" : "exclamation" });
-        //     aclsMenu.push({ description: "Live Readonly (no write/read others)", event: () => setWriteMode(DocServer.WriteMode.LiveReadonly), icon: DocServer.AclsMode === DocServer.WriteMode.LiveReadonly ? "check" : "exclamation" });
-        //     cm.addItem({ description: "Collaboration ...", subitems: aclsMenu, icon: "share" });
-        // });
         runInAction(() => {
             if (!this.topMost && !(e instanceof Touch)) {
                 // DocumentViews should stop propagation of this event
diff --git a/src/client/views/nodes/TaskCompletedBox.tsx b/src/client/views/nodes/TaskCompletedBox.tsx
index 89602f219..2a3dd8d2d 100644
--- a/src/client/views/nodes/TaskCompletedBox.tsx
+++ b/src/client/views/nodes/TaskCompletedBox.tsx
@@ -1,7 +1,5 @@
 import React = require("react");
 import { observer } from "mobx-react";
-import { documentSchema } from "../../../fields/documentSchemas";
-import { makeInterface } from "../../../fields/Schema";
 import "./TaskCompletedBox.scss";
 import { observable, action } from "mobx";
 import { Fade } from "@material-ui/core";
-- 
cgit v1.2.3-70-g09d2


From c40feda5e8799831e77639b24db2789d5ff8cdc3 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 29 Jul 2020 22:09:07 -0400
Subject: fixed Pileup interactions - no double tap. shift to dra out items.

---
 src/client/documents/Documents.ts                  |  2 +-
 .../views/collections/CollectionPileView.tsx       | 28 ++++++++++------------
 src/client/views/collections/CollectionSubView.tsx |  8 +++++--
 src/client/views/collections/CollectionView.tsx    |  3 +--
 .../collectionFreeForm/FormatShapePane.tsx         | 12 +++++-----
 5 files changed, 26 insertions(+), 27 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index ad19ea7b2..7e094089f 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -726,7 +726,7 @@ export namespace Docs {
         }
 
         export function PileDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
-            return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", backgroundColor: "black", ...options, _viewType: CollectionViewType.Pile }, id);
+            return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", backgroundColor: "black", hideFilterView: true, forceActive: true, ...options, _viewType: CollectionViewType.Pile }, id);
         }
 
         export function LinearDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index 22a3877ab..2e4055256 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -39,7 +39,15 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
 
     @computed get contents() {
         return <div className="collectionPileView-innards" style={{ pointerEvents: this.layoutEngine() === "starburst" ? undefined : "none" }} >
-            <CollectionFreeFormView {...this.props} layoutEngine={this.layoutEngine} />
+            <CollectionFreeFormView {...this.props} layoutEngine={this.layoutEngine}
+                addDocument={(doc: Doc | Doc[]) => {
+                    (doc instanceof Doc ? [doc] : doc).map((d) => DocUtils.iconify(d));
+                    return this.props.addDocument(doc);
+                }}
+                moveDocument={(doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => {
+                    (doc instanceof Doc ? [doc] : doc).map((d) => Doc.deiconifyView(d));
+                    return this.props.moveDocument(doc, targetCollection, addDoc);
+                }} />
         </div>;
     }
     toggleStarburst = action(() => {
@@ -72,24 +80,13 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
         }
     });
 
-    @undoBatch
-    @action
-    onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
-        if (super.onInternalDrop(e, de)) {
-            if (de.complete.docDragData) {
-                DocUtils.pileup(this.childDocs);
-            }
-        }
-        return true;
-    }
-
     _undoBatch: UndoManager.Batch | undefined;
     pointerDown = (e: React.PointerEvent) => {
         let dist = 0;
         SnappingManager.SetIsDragging(true);
         // this._lastTap should be set to 0, and this._doubleTap should be set to false in the class header
         setupMoveUpEvents(this, e, (e: PointerEvent, down: number[], delta: number[]) => {
-            if (this.layoutEngine() === "pass" && this.childDocs.length && this.props.isSelected(true)) {
+            if (this.layoutEngine() === "pass" && this.childDocs.length && e.shiftKey) {
                 dist += Math.sqrt(delta[0] * delta[0] + delta[1] * delta[1]);
                 if (dist > 100) {
                     if (!this._undoBatch) {
@@ -110,11 +107,11 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
             if (!this.childDocs.length) {
                 this.props.ContainingCollectionView?.removeDocument(this.props.Document);
             }
-        }, emptyFunction, false, this.layoutEngine() === "pass" && this.props.isSelected(true)); // this sets _doubleTap
+        }, emptyFunction, e.shiftKey && this.layoutEngine() === "pass", this.layoutEngine() === "pass" && e.shiftKey); // this sets _doubleTap
     }
 
     onClick = (e: React.MouseEvent) => {
-        if (e.button === 0 && this._doubleTap) {
+        if (e.button === 0) {//} && this._doubleTap) {
             SelectionManager.DeselectAll();
             this.toggleStarburst();
             e.stopPropagation();
@@ -124,7 +121,6 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
     render() {
 
         return <div className={"collectionPileView"} onClick={this.onClick} onPointerDown={this.pointerDown}
-            ref={this.createDashEventsTarget}
             style={{ width: this.props.PanelWidth(), height: `calc(100%  - ${this.props.Document._chromeStatus === "enabled" ? 51 : 0}px)` }}>
             {this.contents}
         </div>;
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 99acfdcc2..a89fcc703 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -195,7 +195,11 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                     const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d);
                     const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d);
                     const res = addedDocs.length ? this.addDocument(addedDocs) : true;
-                    added = movedDocs.length ? docDragData.moveDocument(movedDocs, this.props.Document, Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.props.Document) || de.embedKey || !this.props.isAnnotationOverlay ? this.addDocument : returnFalse) : res;
+                    if (movedDocs.length) {
+                        const canAdd = this.props.Document._viewType === CollectionViewType.Pile || de.embedKey || !this.props.isAnnotationOverlay ||
+                            Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.props.Document);
+                        added = docDragData.moveDocument(movedDocs, this.props.Document, canAdd ? this.addDocument : returnFalse);
+                    } else added = res;
                 } else {
                     added = this.addDocument(docDragData.droppedDocuments);
                 }
@@ -430,7 +434,7 @@ import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents";
 import { CurrentUserUtils } from "../../util/CurrentUserUtils";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { FormattedTextBox, GoogleRef } from "../nodes/formattedText/FormattedTextBox";
-import { CollectionView } from "./CollectionView";
+import { CollectionView, CollectionViewType } from "./CollectionView";
 import { SelectionManager } from "../../util/SelectionManager";
 import { OverlayView } from "../OverlayView";
 import { setTimeout } from "timers";
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 5a3396b68..42d320308 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -45,7 +45,6 @@ import { SubCollectionViewProps } from './CollectionSubView';
 import { CollectionTimeView } from './CollectionTimeView';
 import { CollectionTreeView } from "./CollectionTreeView";
 import './CollectionView.scss';
-import CollectionMenu from './CollectionMenu';
 import { ContextMenuProps } from '../ContextMenuItem';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
@@ -586,7 +585,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                         Utils.CorsProxy(Cast(d.data, ImageField)!.url.href) : Cast(d.data, ImageField)!.url.href
                     :
                     ""))}
-            {(!this.props.isSelected() || this.props.Document.hideFilterView) && !this.props.Document.forceActive ? (null) :
+            {(!this.props.isSelected() && !this.props.Document.forceActive) || this.props.Document.hideFilterView ? (null) :
                 <div className="collectionView-filterDragger" title="library View Dragger" onPointerDown={this.onPointerDown}
                     style={{ right: this.facetWidth() - 1, top: this.props.Document._viewType === CollectionViewType.Docking ? "25%" : "55%" }} />
             }
diff --git a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
index cd5ca7fd4..ddc282e57 100644
--- a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
+++ b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
@@ -338,7 +338,7 @@ export default class FormatShapePane extends AntimodeMenu {
 
     colorButton(value: string, setter: () => {}) {
         return <>
-            <button className="antimodeMenu-button" key="fill" onPointerDown={undoBatch(action(e => setter()))} style={{ position: "relative", marginTop: -5 }}>
+            <button className="antimodeMenu-button" key="color" onPointerDown={undoBatch(action(e => setter()))} style={{ position: "relative", marginTop: -5 }}>
                 <div className="color-previewII" style={{ backgroundColor: value ?? "121212" }} />
                 {value === "" || value === "transparent" ? <p style={{ fontSize: 25, color: "red", marginTop: -23, position: "fixed" }}>☒</p> : ""}
             </button>
@@ -347,14 +347,14 @@ export default class FormatShapePane extends AntimodeMenu {
 
     controlPointsButton() {
         return <>
-            <button className="antimodeMenu-button" title="Edit points" key="fill" onPointerDown={action(() => this._controlBtn = this._controlBtn ? false : true)} style={{ position: "relative", marginTop: 10, backgroundColor: this._controlBtn ? "black" : "" }}>
+            <button className="antimodeMenu-button" title="Edit points" key="bezier" onPointerDown={action(() => this._controlBtn = this._controlBtn ? false : true)} style={{ position: "relative", marginTop: 10, backgroundColor: this._controlBtn ? "black" : "" }}>
                 <FontAwesomeIcon icon="bezier-curve" size="lg" />
             </button>
-            <button className="antimodeMenu-button" title="Lock ratio" key="fill" onPointerDown={action(() => this._lock = this._lock ? false : true)} style={{ position: "relative", marginTop: 10, backgroundColor: this._lock ? "black" : "" }}>
+            <button className="antimodeMenu-button" title="Lock ratio" key="ratio" onPointerDown={action(() => this._lock = this._lock ? false : true)} style={{ position: "relative", marginTop: 10, backgroundColor: this._lock ? "black" : "" }}>
                 <FontAwesomeIcon icon="lock" size="lg" />
 
             </button>
-            <button className="antimodeMenu-button" key="fill" title="Rotate 90˚" onPointerDown={action(() => this.rotate(Math.PI / 2))} style={{ position: "relative", marginTop: 10, fontSize: 15 }}>
+            <button className="antimodeMenu-button" key="rotate" title="Rotate 90˚" onPointerDown={action(() => this.rotate(Math.PI / 2))} style={{ position: "relative", marginTop: 10, fontSize: 15 }}>
                 ⟲
             </button>
             <br /> <br />
@@ -363,7 +363,7 @@ export default class FormatShapePane extends AntimodeMenu {
 
     lockRatioButton() {
         return <>
-            <button className="antimodeMenu-button" key="fill" onPointerDown={action(() => this._lock = this._lock ? false : true)} style={{ position: "absolute", right: 80, backgroundColor: this._lock ? "black" : "" }}>
+            <button className="antimodeMenu-button" key="lock" onPointerDown={action(() => this._lock = this._lock ? false : true)} style={{ position: "absolute", right: 80, backgroundColor: this._lock ? "black" : "" }}>
                 {/* <FontAwesomeIcon icon="bezier-curve" size="lg" /> */}
                 <FontAwesomeIcon icon="lock" size="lg" />
 
@@ -374,7 +374,7 @@ export default class FormatShapePane extends AntimodeMenu {
 
     rotate90Button() {
         return <>
-            <button className="antimodeMenu-button" key="fill" onPointerDown={action(() => this.rotate(Math.PI / 2))} style={{ position: "absolute", right: 80, }}>
+            <button className="antimodeMenu-button" key="rot" onPointerDown={action(() => this.rotate(Math.PI / 2))} style={{ position: "absolute", right: 80, }}>
                 {/* <FontAwesomeIcon icon="bezier-curve" size="lg" /> */}
                 ⟲
 
-- 
cgit v1.2.3-70-g09d2


From 4224ebd13aec9e01f1fe73c935c40adb089dbc69 Mon Sep 17 00:00:00 2001
From: anika-ahluwalia <anika.ahluwalia@gmail.com>
Date: Wed, 29 Jul 2020 23:11:35 -0500
Subject: sally UI changes

---
 src/client/views/ContextMenuItem.tsx               |   4 +-
 src/client/views/DocumentDecorations.tsx           |   4 +-
 src/client/views/MainView.scss                     |   9 +
 src/client/views/MainView.tsx                      | 251 +++++++++++----------
 src/client/views/PropertiesButtons.tsx             |  25 +-
 .../views/collections/CollectionSchemaView.tsx     |   2 +-
 src/client/views/collections/CollectionView.tsx    |   2 +-
 src/client/views/collections/SchemaTable.tsx       |   6 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   8 +-
 src/client/views/linking/LinkMenuItem.tsx          |   1 +
 src/client/views/nodes/DocumentView.tsx            |  17 +-
 11 files changed, 189 insertions(+), 140 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index 81432968d..7e233ec04 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -80,7 +80,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
     render() {
         if ("event" in this.props) {
             return (
-                <div className={"contextMenu-item" + (this.props.selected ? " contextMenu-itemSelected" : "")} onClick={this.handleEvent}>
+                <div className={"contextMenu-item" + (this.props.selected ? " contextMenu-itemSelected" : "")} onPointerDown={this.handleEvent}>
                     {this.props.icon ? (
                         <span className="icon-background">
                             <FontAwesomeIcon icon={this.props.icon} size="sm" />
@@ -95,7 +95,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
             const where = !this.overItem ? "" : this._overPosY < window.innerHeight / 3 ? "flex-start" : this._overPosY > window.innerHeight * 2 / 3 ? "flex-end" : "center";
             const marginTop = !this.overItem ? "" : this._overPosY < window.innerHeight / 3 ? "20px" : this._overPosY > window.innerHeight * 2 / 3 ? "-20px" : "";
             const submenu = !this.overItem ? (null) :
-                <div className="contextMenu-subMenu-cont" style={{ marginLeft: "25%", left: "0px", marginTop }}>
+                <div className="contextMenu-subMenu-cont" style={{ marginLeft: "90%", left: "0px", marginTop }}>
                     {this._items.map(prop => <ContextMenuItem {...prop} key={prop.description} closeMenu={this.props.closeMenu} />)}
                 </div>;
             if (!("noexpand" in this.props)) {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index ff91e401f..85dd40173 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -577,9 +577,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 </div>}
             </> :
             <>
-                {minimal ? (null) : <Tooltip title={<><div className="dash-tooltip">Show context menu</div></>} placement="top"><div className="documentDecorations-contextMenu" key="menu" onPointerDown={this.onSettingsDown}>
+                {/* {minimal ? (null) : <Tooltip title={<><div className="dash-tooltip">Show context menu</div></>} placement="top"><div className="documentDecorations-contextMenu" key="menu" onPointerDown={this.onSettingsDown}>
                     <FontAwesomeIcon size="lg" icon="bars" />
-                </div></Tooltip>}
+                </div></Tooltip>} */}
                 <div className="documentDecorations-title" key="title" onPointerDown={this.onTitleDown} >
                     <span style={{ width: "100%", display: "inline-block", cursor: "move" }}>{`${this.selectionTitle}`}</span>
                 </div>
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index 8bf38ebe9..fe01c27a3 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -314,6 +314,15 @@
     display: flex;
     flex-direction: column;
     z-index: 2;
+
+    .mainView-libraryFlyout-close {
+        right: 6;
+        top: 5;
+        position: absolute;
+        margin-right: 6px;
+        z-index: 10;
+        margin-bottom: 10;
+    }
 }
 
 .mainView-expandFlyoutButton {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 5f7f7ca03..326082927 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -63,6 +63,8 @@ import { SelectionManager } from '../util/SelectionManager';
 import { PrefetchProxy } from '../../fields/Proxy';
 import { DragManager } from '../util/DragManager';
 import { discovery_v1, dialogflow_v2beta1 } from 'googleapis';
+import { undo } from 'prosemirror-history';
+import { undoBatch } from '../util/UndoManager';
 
 @observer
 export class MainView extends React.Component {
@@ -426,12 +428,18 @@ export class MainView extends React.Component {
     //sidebarScreenToLocal = () => new Transform(0, (RichTextMenu.Instance.Pinned ? -35 : 0) + (CollectionMenu.Instance.Pinned ? -35 : 0), 1);
     mainContainerXf = () => this.sidebarScreenToLocal().translate(0, -this._buttonBarHeight);
 
+    @computed get closePosition() { return 55 + this.flyoutWidth }
     @computed get flyout() {
         if (!(this.sidebarContent instanceof Doc)) {
             return (null);
         }
         return <div className="mainView-libraryFlyout">
             <div className="mainView-contentArea" style={{ position: "relative", height: `100%`, width: "100%", overflow: "visible" }}>
+                {this.flyoutWidth > 0 ? <div className="mainView-libraryFlyout-close"
+                    onPointerDown={this.closeFlyout}>
+                    <FontAwesomeIcon icon="times" color="black" size="sm" />
+                </div> : null}
+
                 <DocumentView
                     Document={this.sidebarContent}
                     DataDoc={undefined}
@@ -463,130 +471,129 @@ export class MainView extends React.Component {
             {this.docButtons}</div>;
     }
 
-    @computed get menuPanel() {
-
-        return <div className="mainView-menuPanel">
-            <DocumentView
-                Document={Doc.UserDoc().menuStack as Doc}
-                DataDoc={undefined}
-                LibraryPath={emptyPath}
-                addDocument={undefined}
-                addDocTab={this.addDocTabFunc}
-                pinToPres={emptyFunction}
-                NativeHeight={returnZero}
-                NativeWidth={returnZero}
-                rootSelected={returnTrue}
-                removeDocument={returnFalse}
-                onClick={undefined}
-                ScreenToLocalTransform={this.mainContainerXf}
-                ContentScaling={returnOne}
-                PanelWidth={() => 80}
-                PanelHeight={this.getContentsHeight}
-                renderDepth={0}
-                focus={emptyFunction}
-                backgroundColor={this.defaultBackgroundColors}
-                parentActive={returnTrue}
-                whenActiveChanged={emptyFunction}
-                bringToFront={emptyFunction}
-                docFilters={returnEmptyFilter}
-                ContainingCollectionView={undefined}
-                ContainingCollectionDoc={undefined}
-                relative={true}
-                scriptContext={this}
-            />
-        </div>;
-    }
-
     // @computed get menuPanel() {
+
     //     return <div className="mainView-menuPanel">
-    //         <div className="mainView-menuPanel-button" style={{ backgroundColor: this.panelContent === "workspace" ? "lightgrey" : "" }}>
-    //             <div className="mainView-menuPanel-button-wrap"
-    //                 style={{ backgroundColor: this.panelContent === "workspace" ? "lightgrey" : "" }}
-    //                 onPointerDown={e => this.selectPanel("workspace")}>
-    //                 <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="desktop"
-    //                     color={this.panelContent === "workspace" ? "black" : "white"} size="lg" />
-    //                 <div className="mainView-menuPanel-button-label"
-    //                     style={{ color: this.panelContent === "workspace" ? "black" : "white" }}> Workspace </div>
-    //             </div>
-    //         </div>
-
-    //         <div className="mainView-menuPanel-button" style={{ backgroundColor: this.panelContent === "catalog" ? "lightgrey" : "" }}>
-    //             <div className="mainView-menuPanel-button-wrap"
-    //                 style={{ backgroundColor: this.panelContent === "catalog" ? "lightgrey" : "" }}
-    //                 onPointerDown={e => this.selectPanel("catalog")}>
-    //                 <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="file"
-    //                     color={this.panelContent === "catalog" ? "black" : "white"} size="lg" />
-    //                 <div className="mainView-menuPanel-button-label"
-    //                     style={{ color: this.panelContent === "catalog" ? "black" : "white" }}> Catalog </div>
-    //             </div>
-    //         </div>
-
-    //         <div className="mainView-menuPanel-button" style={{ backgroundColor: this.panelContent === "deleted" ? "lightgrey" : "" }}>
-    //             <div className="mainView-menuPanel-button-wrap"
-    //                 style={{ backgroundColor: this.panelContent === "deleted" ? "lightgrey" : "" }}
-    //                 onPointerDown={e => this.selectPanel("deleted")}>
-    //                 <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="archive"
-    //                     color={this.panelContent === "deleted" ? "black" : "white"} size="lg" />
-    //                 <div className="mainView-menuPanel-button-label"
-    //                     style={{ color: this.panelContent === "deleted" ? "black" : "white" }}> Recently Used </div>
-    //             </div>
-    //         </div>
-
-    //         <div className="mainView-menuPanel-button">
-    //             <div className="mainView-menuPanel-button-wrap"
-    //                 onPointerDown={e => this.selectPanel("upload")}>
-    //                 <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="upload" color="white" size="lg" />
-    //                 <div className="mainView-menuPanel-button-label"> Import </div>
-    //             </div>
-    //         </div>
-
-    //         <div className="mainView-menuPanel-button">
-    //             <div className="mainView-menuPanel-button-wrap"
-    //                 //onPointerDown={e => this.selectPanel("sharing")}
-    //                 onClick={() => GroupManager.Instance.open()}>
-    //                 <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="users" color="white" size="lg" />
-    //                 <div className="mainView-menuPanel-button-label"> Sharing </div>
-    //             </div>
-    //         </div>
-
-    //         <div className="mainView-menuPanel-button" style={{ marginBottom: "110px", backgroundColor: this.panelContent === "tools" ? "lightgrey" : "", }}>
-    //             <div className="mainView-menuPanel-button-wrap"
-    //                 onPointerDown={e => this.selectPanel("tools")}
-    //                 style={{
-    //                     backgroundColor: this.panelContent === "tools" ? "lightgrey" : "",
-    //                 }}>
-    //                 <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="wrench"
-    //                     color={this.panelContent === "tools" ? "black" : "white"} size="lg" />
-    //                 <div className="mainView-menuPanel-button-label"
-    //                     style={{ color: this.panelContent === "tools" ? "black" : "white" }}> Tools </div>
-    //             </div>
-    //         </div>
-
-    //         <div className="mainView-menuPanel-button">
-    //             <div className="mainView-menuPanel-button-wrap"
-    //                 // style={{backgroundColor: this.panelContent= "help" ? "lightgrey" : "black"}}
-    //                 onPointerDown={e => this.selectPanel("help")} >
-    //                 <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="question-circle" color="white" size="lg" />
-    //                 <div className="mainView-menuPanel-button-label"> Help </div>
-    //             </div>
-    //         </div>
-
-    //         <div className="mainView-menuPanel-button">
-    //             <div className="mainView-menuPanel-button-wrap"
-    //                 // onPointerDown={e => this.selectPanel("settings")}
-    //                 onClick={() => SettingsManager.Instance.open()}>
-    //                 <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="cog" color="white" size="lg" />
-    //                 <div className="mainView-menuPanel-button-label"> Settings </div>
-    //             </div>
-    //         </div>
+    //         <DocumentView
+    //             Document={Doc.UserDoc().menuStack as Doc}
+    //             DataDoc={undefined}
+    //             LibraryPath={emptyPath}
+    //             addDocument={undefined}
+    //             addDocTab={this.addDocTabFunc}
+    //             pinToPres={emptyFunction}
+    //             NativeHeight={returnZero}
+    //             NativeWidth={returnZero}
+    //             rootSelected={returnTrue}
+    //             removeDocument={returnFalse}
+    //             onClick={undefined}
+    //             ScreenToLocalTransform={this.mainContainerXf}
+    //             ContentScaling={returnOne}
+    //             PanelWidth={() => 80}
+    //             PanelHeight={this.getContentsHeight}
+    //             renderDepth={0}
+    //             focus={emptyFunction}
+    //             backgroundColor={this.defaultBackgroundColors}
+    //             parentActive={returnTrue}
+    //             whenActiveChanged={emptyFunction}
+    //             bringToFront={emptyFunction}
+    //             docFilters={returnEmptyFilter}
+    //             ContainingCollectionView={undefined}
+    //             ContainingCollectionDoc={undefined}
+    //             relative={true}
+    //             scriptContext={this}
+    //         />
     //     </div>;
     // }
 
-    @action
+    @computed get menuPanel() {
+        return <div className="mainView-menuPanel">
+            <div className="mainView-menuPanel-button" style={{ backgroundColor: this.panelContent === "workspace" ? "lightgrey" : "" }}>
+                <div className="mainView-menuPanel-button-wrap"
+                    style={{ backgroundColor: this.panelContent === "workspace" ? "lightgrey" : "" }}
+                    onPointerDown={e => this.selectPanel("workspace")}>
+                    <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="desktop"
+                        color={this.panelContent === "workspace" ? "black" : "white"} size="lg" />
+                    <div className="mainView-menuPanel-button-label"
+                        style={{ color: this.panelContent === "workspace" ? "black" : "white" }}> Workspace </div>
+                </div>
+            </div>
+
+            <div className="mainView-menuPanel-button" style={{ backgroundColor: this.panelContent === "catalog" ? "lightgrey" : "" }}>
+                <div className="mainView-menuPanel-button-wrap"
+                    style={{ backgroundColor: this.panelContent === "catalog" ? "lightgrey" : "" }}
+                    onPointerDown={e => this.selectPanel("catalog")}>
+                    <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="file"
+                        color={this.panelContent === "catalog" ? "black" : "white"} size="lg" />
+                    <div className="mainView-menuPanel-button-label"
+                        style={{ color: this.panelContent === "catalog" ? "black" : "white" }}> Catalog </div>
+                </div>
+            </div>
+
+            <div className="mainView-menuPanel-button" style={{ backgroundColor: this.panelContent === "deleted" ? "lightgrey" : "" }}>
+                <div className="mainView-menuPanel-button-wrap"
+                    style={{ backgroundColor: this.panelContent === "deleted" ? "lightgrey" : "" }}
+                    onPointerDown={e => this.selectPanel("deleted")}>
+                    <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="archive"
+                        color={this.panelContent === "deleted" ? "black" : "white"} size="lg" />
+                    <div className="mainView-menuPanel-button-label"
+                        style={{ color: this.panelContent === "deleted" ? "black" : "white" }}> Recently Used </div>
+                </div>
+            </div>
+
+            <div className="mainView-menuPanel-button">
+                <div className="mainView-menuPanel-button-wrap"
+                    onPointerDown={e => this.selectPanel("upload")}>
+                    <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="upload" color="white" size="lg" />
+                    <div className="mainView-menuPanel-button-label"> Import </div>
+                </div>
+            </div>
+
+            <div className="mainView-menuPanel-button">
+                <div className="mainView-menuPanel-button-wrap"
+                    //onPointerDown={e => this.selectPanel("sharing")}
+                    onClick={() => GroupManager.Instance.open()}>
+                    <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="users" color="white" size="lg" />
+                    <div className="mainView-menuPanel-button-label"> Sharing </div>
+                </div>
+            </div>
+
+            <div className="mainView-menuPanel-button" style={{ marginBottom: "110px", backgroundColor: this.panelContent === "tools" ? "lightgrey" : "", }}>
+                <div className="mainView-menuPanel-button-wrap"
+                    onPointerDown={e => this.selectPanel("tools")}
+                    style={{
+                        backgroundColor: this.panelContent === "tools" ? "lightgrey" : "",
+                    }}>
+                    <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="wrench"
+                        color={this.panelContent === "tools" ? "black" : "white"} size="lg" />
+                    <div className="mainView-menuPanel-button-label"
+                        style={{ color: this.panelContent === "tools" ? "black" : "white" }}> Tools </div>
+                </div>
+            </div>
+
+            <div className="mainView-menuPanel-button">
+                <div className="mainView-menuPanel-button-wrap"
+                    // style={{backgroundColor: this.panelContent= "help" ? "lightgrey" : "black"}}
+                    onPointerDown={e => this.selectPanel("help")} >
+                    <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="question-circle" color="white" size="lg" />
+                    <div className="mainView-menuPanel-button-label"> Help </div>
+                </div>
+            </div>
+
+            <div className="mainView-menuPanel-button">
+                <div className="mainView-menuPanel-button-wrap"
+                    // onPointerDown={e => this.selectPanel("settings")}
+                    onClick={() => SettingsManager.Instance.open()}>
+                    <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="cog" color="white" size="lg" />
+                    <div className="mainView-menuPanel-button-label"> Settings </div>
+                </div>
+            </div>
+        </div>;
+    }
+
+    @action @undoBatch
     selectPanel = (str: string) => {
         if (this.panelContent === str && this.flyoutWidth !== 0) {
-            this.panelContent = "none";
-            this.flyoutWidth = 0;
+            this.closeFlyout();
         } else {
             this.panelContent = str;
             MainView.expandFlyout();
@@ -606,7 +613,13 @@ export class MainView extends React.Component {
         return true;
     }
 
-    @action
+    @action @undoBatch
+    closeFlyout = () => {
+        this.panelContent = "none";
+        this.flyoutWidth = 0;
+    }
+
+    @action @undoBatch
     selectMenu = (str: string) => {
         if (CurrentUserUtils.panelContent === str && this.flyoutWidth !== 0) {
             CurrentUserUtils.panelContent = "none";
@@ -630,7 +643,7 @@ export class MainView extends React.Component {
         return true;
     }
 
-    @action
+    @action @undoBatch
     onDown = (e: React.PointerEvent) => {
         setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
             this._propertiesWidth = this._panelWidth - Math.max(Transform.Identity().transformPoint(e.clientX, 0)[0], 0);
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 3113d8cb4..cc15a8195 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -6,7 +6,7 @@ import { observer } from "mobx-react";
 import { Doc, DocListCast } from "../../fields/Doc";
 import { RichTextField } from '../../fields/RichTextField';
 import { Cast, NumCast, BoolCast } from "../../fields/Types";
-import { emptyFunction, setupMoveUpEvents } from "../../Utils";
+import { emptyFunction, setupMoveUpEvents, Utils } from "../../Utils";
 import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
 import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils';
 import { Docs, DocUtils } from '../documents/Documents';
@@ -27,6 +27,8 @@ import SharingManager from '../util/SharingManager';
 import { GooglePhotos } from '../apis/google_docs/GooglePhotosClientUtils';
 import { ImageField } from '../../fields/URLField';
 import { undoBatch, UndoManager } from '../util/UndoManager';
+import { DocumentType } from '../documents/DocumentTypes';
+import { CollectionFreeFormView } from './collections/collectionFreeForm/CollectionFreeFormView';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -471,6 +473,22 @@ export class PropertiesButtons extends React.Component<{}, {}> {
         </Tooltip>;
     }
 
+    // @computed
+    // get importButton() {
+    //     const targetDoc = this.selectedDoc;
+    //     return !targetDoc ? (null) : <Tooltip
+    //         title={<><div className="dash-tooltip">{"Import a Document"}</div></>}>
+    //         <div className={"propertiesButtons-linkButton-empty"}
+    //             onPointerDown={() => {
+    //                 if (this.selectedDocumentView) {
+    //                     CollectionFreeFormView.importDocument(100, 100);
+    //                 }
+    //             }}>
+    //             {<FontAwesomeIcon className="documentdecorations-icon"
+    //                 icon="upload" size="sm" />}
+    //         </div>
+    //     </Tooltip>;
+    // }
 
     render() {
         if (!this.selectedDoc) return (null);
@@ -479,6 +497,8 @@ export class PropertiesButtons extends React.Component<{}, {}> {
         const considerPull = isText && this.considerGoogleDocsPull;
         const considerPush = isText && this.considerGoogleDocsPush;
         const isImage = this.selectedDoc[Doc.LayoutFieldKey(this.selectedDoc)] instanceof ImageField;
+        const isCollection = this.selectedDoc.type === DocumentType.COL ? true : false;
+
         return <div><div className="propertiesButtons" style={{ paddingBottom: "5.5px" }}>
             <div className="propertiesButtons-button">
                 {this.templateButton}
@@ -518,6 +538,9 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                 <div className="propertiesButtons-button" style={{ display: !isImage ? "none" : "" }}>
                     {this.googlePhotosButton}
                 </div>
+                {/* <div className="propertiesButtons-button" style={{ display: !isCollection ? "none" : "" }}>
+                    {this.importButton}
+                </div> */}
             </div>
         </div>;
     }
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 5553bbbb7..f67e049fd 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -253,7 +253,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
             <div className="collectionSchema-headerMenu-group">
                 <div onClick={() => this.typesDropdownChange(!this._openTypes)}>
                     <label>Column type:</label>
-                    <FontAwesomeIcon icon={"caret-down"} size="sm" style={{ float: "right" }} />
+                    <FontAwesomeIcon icon={"caret-down"} size="lg" style={{ float: "right" }} />
                 </div>
                 {this._openTypes ? allColumnTypes : justColType}
             </div >
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index ae53f5ba0..5834e5542 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -308,7 +308,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
 
             const options = cm.findByDescription("Options...");
             const optionItems = options && "subitems" in options ? options.subitems : [];
-            optionItems.splice(0, 0, { description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" });
+            !Doc.UserDoc().noviceMode ? optionItems.splice(0, 0, { description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" }) : null;
             if (this.props.Document.childLayout instanceof Doc) {
                 optionItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, "onRight"), icon: "project-diagram" });
             }
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index cde795098..75e693f96 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -208,7 +208,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                 }}>
                 {col.heading}</div>;
 
-            const sortIcon = col.desc === undefined ? "circle" : col.desc === true ? "caret-down" : "caret-up";
+            const sortIcon = col.desc === undefined ? "caret-right" : col.desc === true ? "caret-down" : "caret-up";
 
             const header =
                 <div //className="collectionSchemaView-header"
@@ -224,12 +224,12 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                         {keysDropdown}
                     </div>
                     <div onClick={e => this.changeSorting(col)}
-                        style={{ paddingRight: "6px", display: "inline" }}>
+                        style={{ paddingRight: "6px", marginLeft: "4px", display: "inline" }}>
                         <FontAwesomeIcon icon={sortIcon} size="sm" />
                     </div>
                     <div onClick={e => this.props.openHeader(col, e.clientX, e.clientY)}
                         style={{ float: "right", paddingRight: "6px" }}>
-                        <FontAwesomeIcon icon={"compass"} size="sm" />
+                        <FontAwesomeIcon icon={"cog"} size="sm" />
                     </div>
                 </div>;
 
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 57336131a..e0981d797 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1239,13 +1239,15 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         const appearanceItems = appearance && "subitems" in appearance ? appearance.subitems : [];
         appearanceItems.push({ description: "Reset View", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: "compress-arrows-alt" });
         appearanceItems.push({ description: `${this.fitToContent ? "Make Zoomable" : "Scale to Window"}`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" });
-        appearanceItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" });
+        !Doc.UserDoc().noviceMode ? appearanceItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }) : null;
         !appearance && ContextMenu.Instance.addItem({ description: "Appearance...", subitems: appearanceItems, icon: "eye" });
 
         const viewctrls = ContextMenu.Instance.findByDescription("UI Controls...");
         const viewCtrlItems = viewctrls && "subitems" in viewctrls ? viewctrls.subitems : [];
-        viewCtrlItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " Snap Lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" });
-        viewCtrlItems.push({ description: (this.Document.useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" });
+
+
+        !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " Snap Lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }) : null;
+        !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (this.Document.useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }) : null;
         !viewctrls && ContextMenu.Instance.addItem({ description: "UI Controls...", subitems: viewCtrlItems, icon: "eye" });
 
         const options = ContextMenu.Instance.findByDescription("Options...");
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 8084d96ae..0aabf5319 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -196,6 +196,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
             case DocumentType.DOCHOLDER: destinationIcon = "expand"; break;
             case DocumentType.VID: destinationIcon = "video"; break;
             case DocumentType.INK: destinationIcon = "pen-nib"; break;
+            case DocumentType.PDF: destinationIcon = "file"; break;
             default: destinationIcon = "question"; break;
         }
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 856eb7246..f5ae9349a 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -712,21 +712,21 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
         const options = cm.findByDescription("Options...");
         const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : [];
-        optionItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
+        //optionItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
         !options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "compass" });
 
 
         const existingOnClick = cm.findByDescription("OnClick...");
         const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
         onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" });
-        onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.Document.layoutKey}")`), icon: "window-restore" });
+        onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.Document.layoutKey}")`), icon: "concierge-bell" });
         onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" });
-        onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: () => this.toggleFollowLink("inPlace", true, false), icon: "concierge-bell" });
-        !this.Document.isLinkButton && onClicks.push({ description: "Follow Link on Right", event: () => this.toggleFollowLink("onRight", false, false), icon: "concierge-bell" });
-        onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? "Remove Click Behavior" : "Follow Link", event: () => this.toggleFollowLink(undefined, false, false), icon: "concierge-bell" });
-        onClicks.push({ description: (this.Document.isPushpin ? "Remove" : "Make") + " Pushpin", event: () => this.toggleFollowLink(undefined, false, true), icon: "snowflake" });
-        onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "edit" });
-        !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, addDivider: true, subitems: onClicks, icon: "hand-point-right" });
+        onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: () => this.toggleFollowLink("inPlace", true, false), icon: "link" });
+        !this.Document.isLinkButton && onClicks.push({ description: "Follow Link on Right", event: () => this.toggleFollowLink("onRight", false, false), icon: "link" });
+        onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? "Remove Click Behavior" : "Follow Link", event: () => this.toggleFollowLink(undefined, false, false), icon: "link" });
+        onClicks.push({ description: (this.Document.isPushpin ? "Remove" : "Make") + " Pushpin", event: () => this.toggleFollowLink(undefined, false, true), icon: "map-pin" });
+        onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "terminal" });
+        !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, addDivider: true, subitems: onClicks, icon: "mouse-pointer" });
 
         const funcs: ContextMenuProps[] = [];
         if (this.layoutDoc.onDragStart) {
@@ -739,6 +739,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const more = cm.findByDescription("More...");
         const moreItems = more && "subitems" in more ? more.subitems : [];
         moreItems.push({ description: "Share", event: () => SharingManager.Instance.open(this), icon: "users" });
+        moreItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
         moreItems.push({ description: "Create an Alias", event: () => this.onCopy(), icon: "copy" });
         moreItems.push({ description: "Download document", icon: "download", event: async () => Doc.Zip(this.props.Document) });
         if (!Doc.UserDoc().noviceMode) {
-- 
cgit v1.2.3-70-g09d2


From 626c7b04dcfff293a2a30ed059e661100143199b Mon Sep 17 00:00:00 2001
From: usodhi <61431818+usodhi@users.noreply.github.com>
Date: Thu, 30 Jul 2020 22:11:39 +0530
Subject: some playground mode stuff + minor sharingmanager changes

---
 src/client/util/GroupManager.tsx                |  2 +-
 src/client/util/SharingManager.tsx              | 41 ++++++++++++++++---------
 src/client/views/DocComponent.tsx               |  6 ++--
 src/client/views/collections/CollectionView.tsx |  7 +++--
 4 files changed, 35 insertions(+), 21 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index 551216fa4..a0db9a421 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -102,7 +102,7 @@ export default class GroupManager extends React.Component<{}> {
      */
     @action
     open = () => {
-        SelectionManager.DeselectAll();
+        // SelectionManager.DeselectAll();
         this.isOpen = true;
         this.populateUsers();
         this.populateGroups();
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 00d0691f2..7ede584c2 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -1,7 +1,7 @@
 import { observable, runInAction, action } from "mobx";
 import * as React from "react";
 import MainViewModal from "../views/MainViewModal";
-import { Doc, Opt, DocListCastAsync, AclAdmin, DataSym } from "../../fields/Doc";
+import { Doc, Opt, DocListCastAsync, AclAdmin, DataSym, AclPrivate } from "../../fields/Doc";
 import { DocServer } from "../DocServer";
 import { Cast, StrCast } from "../../fields/Types";
 import * as RequestPromise from "request-promise";
@@ -19,7 +19,7 @@ import GroupMemberView from "./GroupMemberView";
 import Select from "react-select";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { List } from "../../fields/List";
-import { distributeAcls, SharingPermissions } from "../../fields/util";
+import { distributeAcls, SharingPermissions, GetEffectiveAcl } from "../../fields/util";
 import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox";
 
 export interface User {
@@ -80,7 +80,7 @@ export default class SharingManager extends React.Component<{}> {
 
     public open = (target: DocumentView) => {
         runInAction(() => this.users = []);
-        SelectionManager.DeselectAll();
+        // SelectionManager.DeselectAll();
         this.populateUsers().then(action(() => {
             this.targetDocView = target;
             this.targetDoc = target.props.Document;
@@ -93,8 +93,8 @@ export default class SharingManager extends React.Component<{}> {
 
     public close = action(() => {
         this.isOpen = false;
-        this.users = []; // resets the list of users and seleected users (in the react-select component)
-        this.selectedUsers = null;
+        this.users = [];
+        this.selectedUsers = null; // resets the list of users and seleected users (in the react-select component)
 
         setTimeout(action(() => {
             // this.copied = false;
@@ -108,10 +108,15 @@ export default class SharingManager extends React.Component<{}> {
         SharingManager.Instance = this;
     }
 
+    componentDidMount() {
+        this.populateUsers();
+    }
+
     /**
      * Populates the list of validated users (this.users) by adding registered users which have a rightSidebarCollection.
      */
     populateUsers = async () => {
+        runInAction(() => this.users = []);
         const userList = await RequestPromise.get(Utils.prepend("/getUsers"));
         const raw = JSON.parse(userList) as User[];
         const evaluating = raw.map(async user => {
@@ -379,24 +384,32 @@ export default class SharingManager extends React.Component<{}> {
         const users = this.individualSort === "ascending" ? this.users.sort(this.sortUsers) : this.individualSort === "descending" ? this.users.sort(this.sortUsers).reverse() : this.users;
         const groups = this.groupSort === "ascending" ? groupList.sort(this.sortGroups) : this.groupSort === "descending" ? groupList.sort(this.sortGroups).reverse() : groupList;
 
+        const effectiveAcl = this.targetDoc ? GetEffectiveAcl(this.targetDoc) : AclPrivate;
+
         const userListContents: (JSX.Element | null)[] = users.map(({ user, notificationDoc }) => {
             const userKey = user.email.replace('.', '_');
-            const permissions = StrCast(this.targetDoc?.[`ACL-${userKey}`], SharingPermissions.None);
+            const permissions = StrCast(this.targetDoc?.[`ACL-${userKey}`]);
 
-            return user.email === this.targetDoc?.author ? null : (
+            return !permissions || user.email === this.targetDoc?.author ? null : (
                 <div
                     key={userKey}
                     className={"container"}
                 >
                     <span className={"padding"}>{user.email}</span>
                     <div className="edit-actions">
-                        <select
-                            className={"permissions-dropdown"}
-                            value={permissions}
-                            onChange={e => this.setInternalSharing({ user, notificationDoc }, e.currentTarget.value)}
-                        >
-                            {this.sharingOptions}
-                        </select>
+                        {effectiveAcl === AclAdmin ? (
+                            <select
+                                className={"permissions-dropdown"}
+                                value={permissions}
+                                onChange={e => this.setInternalSharing({ user, notificationDoc }, e.currentTarget.value)}
+                            >
+                                {this.sharingOptions}
+                            </select>
+                        ) : (
+                                <div className={"permissions-dropdown"}>
+                                    {this.sharingOptions}
+                                </div>
+                            )}
                     </div>
                 </div>
             );
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 777fb5323..3bcf4b922 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -163,13 +163,13 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
                     //         }
                     //     });
                     // }
-                    if (effectiveAcl === AclAddonly) {
+                    if (effectiveAcl === AclAddonly && !getPlaygroundMode()) {
                         added.map(doc => Doc.AddDocToList(targetDataDoc, this.annotationKey, doc));
                     }
                     else {
                         added.map(doc => doc.context = this.props.Document);
-                        targetDataDoc[this.annotationKey] = new List<Doc>([...docList, ...added]);
-                        targetDataDoc[this.annotationKey + "-lastModified"] = new DateField(new Date(Date.now()));
+                        (targetDataDoc[this.annotationKey] as List<Doc>).push(...added);
+                        if (!getPlaygroundMode()) targetDataDoc[this.annotationKey + "-lastModified"] = new DateField(new Date(Date.now()));
                     }
                 }
             }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 25a832994..5262c8b46 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -157,7 +157,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 //     });
                 // }
 
-                if (effectiveAcl === AclAddonly) {
+                if (effectiveAcl === AclAddonly && !getPlaygroundMode()) {
                     added.map(doc => Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc));
                 }
                 else {
@@ -179,8 +179,9 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                         doc.context = this.props.Document;
                     });
                     added.map(add => Doc.AddDocToList(Cast(Doc.UserDoc().myCatalog, Doc, null), "data", add));
-                    targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]);
-                    targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+                    // targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]);
+                    (targetDataDoc[this.props.fieldKey] as List<Doc>).push(...added);
+                    if (!getPlaygroundMode()) targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
                 }
             }
         }
-- 
cgit v1.2.3-70-g09d2


From 19c0ca86ed6ff8d8644125fa119270fc79e0afc9 Mon Sep 17 00:00:00 2001
From: usodhi <61431818+usodhi@users.noreply.github.com>
Date: Fri, 31 Jul 2020 13:59:04 +0530
Subject: integrated playgroundmode into geteffectiveacl, still some issues
 with deleting docs

---
 src/client/views/DocComponent.tsx                              |  8 ++++----
 src/client/views/collections/CollectionView.tsx                | 10 +++++-----
 .../views/collections/collectionFreeForm/MarqueeView.tsx       |  4 ++--
 src/client/views/nodes/WebBox.tsx                              |  4 ++--
 src/client/views/pdf/PDFViewer.tsx                             |  4 ++--
 src/fields/util.ts                                             |  6 +-----
 6 files changed, 16 insertions(+), 20 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 3bcf4b922..804c7a8d4 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -7,7 +7,7 @@ import { InteractionUtils } from '../util/InteractionUtils';
 import { List } from '../../fields/List';
 import { DateField } from '../../fields/DateField';
 import { ScriptField } from '../../fields/ScriptField';
-import { GetEffectiveAcl, getPlaygroundMode, SharingPermissions } from '../../fields/util';
+import { GetEffectiveAcl, SharingPermissions } from '../../fields/util';
 
 
 ///  DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView)
@@ -150,7 +150,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
             const effectiveAcl = GetEffectiveAcl(this.dataDoc);
 
             if (added.length) {
-                if (effectiveAcl === AclPrivate || (effectiveAcl === AclReadonly && !getPlaygroundMode())) {
+                if (effectiveAcl === AclPrivate || effectiveAcl === AclReadonly) {
                     return false;
                 }
                 else {
@@ -163,13 +163,13 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
                     //         }
                     //     });
                     // }
-                    if (effectiveAcl === AclAddonly && !getPlaygroundMode()) {
+                    if (effectiveAcl === AclAddonly) {
                         added.map(doc => Doc.AddDocToList(targetDataDoc, this.annotationKey, doc));
                     }
                     else {
                         added.map(doc => doc.context = this.props.Document);
                         (targetDataDoc[this.annotationKey] as List<Doc>).push(...added);
-                        if (!getPlaygroundMode()) targetDataDoc[this.annotationKey + "-lastModified"] = new DateField(new Date(Date.now()));
+                        targetDataDoc[this.annotationKey + "-lastModified"] = new DateField(new Date(Date.now()));
                     }
                 }
             }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 5262c8b46..7e7ea6786 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -17,7 +17,7 @@ import { listSpec } from '../../../fields/Schema';
 import { ComputedField, ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
-import { TraceMobx, GetEffectiveAcl, getPlaygroundMode, SharingPermissions } from '../../../fields/util';
+import { TraceMobx, GetEffectiveAcl, SharingPermissions } from '../../../fields/util';
 import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
@@ -142,7 +142,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
         const effectiveAcl = GetEffectiveAcl(this.props.Document);
 
         if (added.length) {
-            if (effectiveAcl === AclPrivate || (effectiveAcl === AclReadonly && !getPlaygroundMode())) {
+            if (effectiveAcl === AclPrivate || effectiveAcl === AclReadonly) {
                 return false;
             }
             else {
@@ -157,7 +157,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 //     });
                 // }
 
-                if (effectiveAcl === AclAddonly && !getPlaygroundMode()) {
+                if (effectiveAcl === AclAddonly) {
                     added.map(doc => Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc));
                 }
                 else {
@@ -181,7 +181,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                     added.map(add => Doc.AddDocToList(Cast(Doc.UserDoc().myCatalog, Doc, null), "data", add));
                     // targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]);
                     (targetDataDoc[this.props.fieldKey] as List<Doc>).push(...added);
-                    if (!getPlaygroundMode()) targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+                    targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
                 }
             }
         }
@@ -193,7 +193,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
         const collectionEffectiveAcl = GetEffectiveAcl(this.props.Document);
         const docEffectiveAcl = GetEffectiveAcl(doc);
         // you can remove the document if you either have Admin/Edit access to the collection or to the specific document
-        if (collectionEffectiveAcl === AclEdit || collectionEffectiveAcl === AclAdmin || docEffectiveAcl === AclAdmin || docEffectiveAcl === AclEdit || getPlaygroundMode()) {
+        if (collectionEffectiveAcl === AclEdit || collectionEffectiveAcl === AclAdmin || docEffectiveAcl === AclAdmin || docEffectiveAcl === AclEdit) {
             const docs = doc instanceof Doc ? [doc] : doc as Doc[];
             const targetDataDoc = this.props.Document[DataSym];
             const value = DocListCast(targetDataDoc[this.props.fieldKey]);
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 764758eee..a32c8b363 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,7 +1,7 @@
 import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
 import { Doc, Opt, DocListCast, DataSym, AclEdit, AclAddonly, AclAdmin } from "../../../../fields/Doc";
-import { GetEffectiveAcl, getPlaygroundMode } from "../../../../fields/util";
+import { GetEffectiveAcl } from "../../../../fields/util";
 import { InkData, InkField, InkTool } from "../../../../fields/InkField";
 import { List } from "../../../../fields/List";
 import { RichTextField } from "../../../../fields/RichTextField";
@@ -281,7 +281,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             this._downX = x;
             this._downY = y;
             const effectiveAcl = GetEffectiveAcl(this.props.Document);
-            if ([AclAdmin, AclEdit, AclAddonly].includes(effectiveAcl) || getPlaygroundMode()) PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument, this.props.nudge);
+            if ([AclAdmin, AclEdit, AclAddonly].includes(effectiveAcl)) PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument, this.props.nudge);
             this.clearSelection();
         }
     });
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index cb82a76f1..3fbebe3e6 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -13,7 +13,7 @@ import { List } from "../../../fields/List";
 import { listSpec, makeInterface } from "../../../fields/Schema";
 import { Cast, NumCast, StrCast } from "../../../fields/Types";
 import { WebField } from "../../../fields/URLField";
-import { TraceMobx, GetEffectiveAcl, getPlaygroundMode } from "../../../fields/util";
+import { TraceMobx, GetEffectiveAcl } from "../../../fields/util";
 import { addStyleSheet, clearStyleSheetRules, emptyFunction, returnOne, returnZero, Utils, returnTrue } from "../../../Utils";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
@@ -536,7 +536,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
     highlight = (color: string) => {
         // creates annotation documents for current highlights
         const effectiveAcl = GetEffectiveAcl(this.props.Document);
-        if ([AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl) || getPlaygroundMode()) {
+        if ([AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl)) {
             const annotationDoc = this.makeAnnotationDocument(color);
             annotationDoc && Doc.AddDocToList(this.props.Document, this.annotationKey, annotationDoc);
             return annotationDoc;
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 954b62332..59fa6b08c 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -13,7 +13,7 @@ import { createSchema, makeInterface } from "../../../fields/Schema";
 import { ScriptField } from "../../../fields/ScriptField";
 import { Cast, NumCast } from "../../../fields/Types";
 import { PdfField } from "../../../fields/URLField";
-import { TraceMobx, GetEffectiveAcl, getPlaygroundMode } from "../../../fields/util";
+import { TraceMobx, GetEffectiveAcl } from "../../../fields/util";
 import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, emptyPath, intersectRect, returnZero, smoothScroll, Utils } from "../../../Utils";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { DocumentType } from "../../documents/DocumentTypes";
@@ -566,7 +566,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
     highlight = (color: string) => {
         // creates annotation documents for current highlights
         const effectiveAcl = GetEffectiveAcl(this.props.Document);
-        if ([AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl) || getPlaygroundMode()) {
+        if ([AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl)) {
             const annotationDoc = this.makeAnnotationDocument(color);
             annotationDoc && Doc.AddDocToList(this.props.Document, this.annotationKey, annotationDoc);
             return annotationDoc;
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 048b66b53..500daf0c7 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -122,10 +122,6 @@ export function togglePlaygroundMode() {
     playgroundMode = !playgroundMode;
 }
 
-export function getPlaygroundMode() {
-    return playgroundMode;
-}
-
 // the list of groups that the current user is a member of 
 let currentUserGroups: string[] = [];
 
@@ -188,7 +184,7 @@ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number)
                 }
             }
         }
-        return effectiveAcl;
+        return playgroundMode && HierarchyMapping.get(effectiveAcl)! < 3 ? AclEdit : effectiveAcl;
     }
     return AclAdmin;
 }
-- 
cgit v1.2.3-70-g09d2


From a1950ec49c56f5f9e2612da7e60a1e2615209386 Mon Sep 17 00:00:00 2001
From: Andy Rickert <andrew_rickert@brown.edu>
Date: Fri, 31 Jul 2020 18:25:39 -0400
Subject: bugfix

---
 src/client/views/DocComponent.tsx                  |  2 +
 src/client/views/GlobalKeyHandler.ts               |  2 +
 src/client/views/collections/CollectionView.tsx    |  4 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx | 28 ++++-----
 src/client/views/search/SearchBox.tsx              | 69 ++++++++++++++++------
 5 files changed, 71 insertions(+), 34 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 9b9a28f0f..106250af4 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -146,6 +146,8 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
                     added.map(doc => doc.context = this.props.Document);
                     targetDataDoc[this.annotationKey] = new List<Doc>([...docList, ...added]);
                     targetDataDoc[this.annotationKey + "-lastModified"] = new DateField(new Date(Date.now()));
+                    targetDataDoc["lastModified"] = new DateField(new Date(Date.now()));
+
                 }
             }
             return true;
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index c85849adb..2e5c018ba 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -307,6 +307,8 @@ export default class KeyManager {
                             undoBatch(() => {
                                 targetDataDoc[fieldKey] = new List<Doc>([...docList, ...added]);
                                 targetDataDoc[fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+                                targetDataDoc["lastModified"] = new DateField(new Date(Date.now()));
+
                             })();
                         }
                     }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 0178cc2e9..f9dc666d6 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -159,6 +159,8 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 added.map(add => Doc.AddDocToList(Cast(Doc.UserDoc().myCatalog, Doc, null), "data", add));
                 targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]);
                 targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+                targetDataDoc["lastModified"] = new DateField(new Date(Date.now()));
+
             }
         }
         return true;
@@ -554,7 +556,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
         return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
             style={{ pointerEvents: this.props.Document.isBackground ? "none" : undefined, boxShadow }}>
             {this.showIsTagged()}
-            <div className="collectionView-facetCont" style={{ display: this.props.PanelPosition==="absolute"? "flex" : "", justifyContent: this.props.PanelPosition==="absolute"? "center" : "", width: `calc(100% - ${this.facetWidth()}px)` }}>
+            <div className="collectionView-facetCont" style={{ display: this.props.PanelPosition === "absolute" ? "flex" : "", justifyContent: this.props.PanelPosition === "absolute" ? "center" : "", width: `calc(100% - ${this.facetWidth()}px)` }}>
                 {this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
             </div>
             {this.lightbox(DocListCast(this.props.Document[this.props.fieldKey]).filter(d => d.type === DocumentType.IMG).map(d =>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 11f25a208..71ba51039 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -228,7 +228,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             if (!this.dataDoc[AclSym]) {
                 if (!this._applyingChange && json.replace(/"selection":.*/, "") !== curProto?.Data.replace(/"selection":.*/, "")) {
                     this._applyingChange = true;
-                    (curText !== Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text) && (this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())));
+                    (curText !== Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text) && (this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()))) && (this.dataDoc["lastModified"] = new DateField(new Date(Date.now())));
                     if ((!curTemp && !curProto) || curText || curLayout?.Data.includes("dash")) { // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
                         if (json !== curLayout?.Data) {
                             !curText && tx.storedMarks?.map(m => m.type.name === "pFontSize" && (Doc.UserDoc().fontSize = this.layoutDoc._fontSize = m.attrs.fontSize));
@@ -280,7 +280,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             this._editorView.dispatch(tr.addMark(flattened[lastSel].from, flattened[lastSel].to, link));
         }
     }
-    public highlightSearchTerms = (terms: string[])=> {
+    public highlightSearchTerms = (terms: string[]) => {
         if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
 
             const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
@@ -291,30 +291,30 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             const flattened: TextSelection[] = [];
             res.map(r => r.map(h => flattened.push(h)));
 
-            
+
             const lastSel = Math.min(flattened.length - 1, this._searchIndex);
             flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark));
             this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
             this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
-            
+
             console.log(this._searchIndex, length);
-            if (this._searchIndex>1){
-                this._searchIndex+=-2;
+            if (this._searchIndex > 1) {
+                this._searchIndex += -2;
             }
-            else if (this._searchIndex===1){
-                this._searchIndex=length-1;
+            else if (this._searchIndex === 1) {
+                this._searchIndex = length - 1;
             }
-            else if (this._searchIndex===0 && length!==1){
-                this._searchIndex=length-2;
+            else if (this._searchIndex === 0 && length !== 1) {
+                this._searchIndex = length - 2;
             }
             let index = this._searchIndex;
 
             Doc.GetProto(this.dataDoc).searchIndex = index;
-            Doc.GetProto(this.dataDoc).length=length;
+            Doc.GetProto(this.dataDoc).length = length;
         }
     }
 
-    public highlightSearchTerms2 = (terms: string[])=> {
+    public highlightSearchTerms2 = (terms: string[]) => {
         if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
 
             const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
@@ -323,7 +323,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             let length = res[0].length;
             let tr = this._editorView.state.tr;
             const flattened: TextSelection[] = [];
-            res.map(r => r.map(h => flattened.push(h)));       
+            res.map(r => r.map(h => flattened.push(h)));
             const lastSel = Math.min(flattened.length - 1, this._searchIndex);
             flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark));
             this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
@@ -331,7 +331,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             let index = this._searchIndex;
 
             Doc.GetProto(this.dataDoc).searchIndex = index;
-            Doc.GetProto(this.dataDoc).length=length;
+            Doc.GetProto(this.dataDoc).length = length;
         }
     }
 
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index b17751d44..005f7d1af 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -40,6 +40,7 @@ import * as _ from "lodash";
 import { checkIfStateModificationsAreAllowed } from 'mobx/lib/internal';
 import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
 import { indexOf } from 'lodash';
+import { protocol } from 'socket.io-client';
 
 
 library.add(faTimes);
@@ -379,22 +380,42 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             let docs = DocListCast(selectedCollection.dataDoc[Doc.LayoutFieldKey(selectedCollection.dataDoc)]);
             let found: [Doc, string[], string[]][] = [];
             let docsforFilter: Doc[] = []
-            docs.forEach((d) => {
-                let hlights: string[] = [];
-                const protos = Doc.GetAllPrototypes(d);
-                let proto = protos[protos.length - 2];
-                Object.keys(proto).forEach(key => {
-                    if (StrCast(d[key]).includes(query)) {
-                        console.log(key, d[key]);
-                        hlights.push(key);
+            let newarray: Doc[] = [];
+
+            while (docs.length > 0) {
+                console.log("iteration");
+                newarray = [];
+                docs.forEach((d) => {
+                    console.log(d);
+                    if (d.data != undefined) {
+                        let newdocs = DocListCast(d.data);
+                        newdocs.forEach((newdoc) => {
+                            console.log(newdoc);
+                            newarray.push(newdoc);
+
+                        });
                     }
+
+
+                    let hlights: string[] = [];
+
+                    const protos = Doc.GetAllPrototypes(d);
+                    let proto = protos[protos.length - 1];
+                    protos.forEach(proto => {
+                        Object.keys(proto).forEach(key => {
+                            // console.log(key, d[key]);
+                            if (StrCast(d[key]).includes(query) && !hlights.includes(key)) {
+                                hlights.push(key);
+                            }
+                        })
+                    });
+                    if (hlights.length > 0) {
+                        found.push([d, hlights, []]);
+                        docsforFilter.push(d);
+                    };
                 });
-                if (hlights.length > 0) {
-                    found.push([d, hlights, []]);
-                    docsforFilter.push(d);
-                };
-            });
-            console.log(found);
+                docs = newarray;
+            }
             this._results = found;
             this.docsforfilter = docsforFilter;
             if (this.filter === true) {
@@ -408,6 +429,20 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
 
     }
 
+
+    documentKeys(doc: Doc) {
+        const keys: { [key: string]: boolean } = {};
+        // bcz: ugh.  this is untracked since otherwise a large collection of documents will blast the server for all their fields.
+        //  then as each document's fields come back, we update the documents _proxies.  Each time we do this, the whole schema will be
+        //  invalidated and re-rendered.   This workaround will inquire all of the document fields before the options button is clicked.
+        //  then by the time the options button is clicked, all of the fields should be in place.  If a new field is added while this menu
+        //  is displayed (unlikely) it won't show up until something else changes.
+        //TODO Types
+        Doc.GetAllPrototypes(doc).map
+            (proto => Object.keys(proto).forEach(key => keys[key] = false));
+        return Array.from(Object.keys(keys));
+    }
+
     applyBasicFieldFilters(query: string) {
         let finalQuery = "";
 
@@ -669,7 +704,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
         const endIndex = 30;
         this._endIndex = endIndex === -1 ? 12 : endIndex;
         this._endIndex = 30;
-        let headers = new Set<string>(["title", "author", "creationDate"]);
+        let headers = new Set<string>(["title", "author", "lastModified"]);
         if ((this._numTotalResults === 0 || this._results.length === 0) && this._openNoResults) {
             if (this.noresults === "") {
                 this.noresults = "No search results :(";
@@ -734,12 +769,8 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
                             if (i < this._visibleDocuments.length) {
                                 this._visibleDocuments[i] = result[0];
                                 this._isSearch[i] = "search";
-                                console.log("WHYYYY");
-                                console.log(result[0]);
-
                                 Doc.AddDocToList(this.dataDoc, this.props.fieldKey, result[0]);
                                 this.children++;
-
                             }
                         }
                     }
-- 
cgit v1.2.3-70-g09d2


From a10db866ff80961e22bc794d51db95e8cb6d0f16 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 2 Aug 2020 14:50:10 -0400
Subject: keep filter view as a feature for expert users

---
 src/client/views/collections/CollectionMenu.tsx | 4 ++--
 src/client/views/collections/CollectionView.tsx | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index fdd1b4e81..59e6ac7ff 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -332,11 +332,11 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
                         {this.props.type === CollectionViewType.Invalid ||
                             this.props.type === CollectionViewType.Docking || this.isText ? (null) : this.viewModes}
                         {this.props.type === CollectionViewType.Docking || this.isText ? (null) : this.templateChrome}
-                        {/* <div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: "grid" }}>
+                        {Doc.UserDoc().noviceMode ? (null) : <div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: "grid" }}>
                             <button className={"antimodeMenu-button"} onClick={this.toggleViewSpecs} >
                                 <FontAwesomeIcon icon="filter" size="lg" />
                             </button>
-                        </div> */}
+                        </div>}
 
                         {this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? (null) : <button className={"antimodeMenu-button"} key="float"
                             style={{ backgroundColor: !this.props.docView.layoutDoc.isAnnotating ? "121212" : undefined, borderRight: "1px solid gray" }}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 62e8dc26a..c2b55d38e 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -591,11 +591,11 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                         Utils.CorsProxy(Cast(d.data, ImageField)!.url.href) : Cast(d.data, ImageField)!.url.href
                     :
                     ""))}
-            {/* {(!this.props.isSelected() && !this.props.Document.forceActive) || this.props.Document.hideFilterView ? (null) :
+            {(Doc.UserDoc()?.noviceMode || !this.props.isSelected() && !this.props.Document.forceActive) || this.props.Document.hideFilterView ? (null) :
                 <div className="collectionView-filterDragger" title="library View Dragger" onPointerDown={this.onPointerDown}
                     style={{ right: this.facetWidth() - 1, top: this.props.Document._viewType === CollectionViewType.Docking ? "25%" : "55%" }} />
             }
-            {this.facetWidth() < 10 ? (null) : this.filterView}  */}
+            {Doc.UserDoc()?.noviceMode || this.facetWidth() < 10 ? (null) : this.filterView}
         </div>);
     }
 }
-- 
cgit v1.2.3-70-g09d2


From ac177d7b9a01075fbf1ad1c327c7625d95569afb Mon Sep 17 00:00:00 2001
From: anika-ahluwalia <anika.ahluwalia@gmail.com>
Date: Sun, 2 Aug 2020 18:20:59 -0500
Subject: bug fixes found with sally

---
 src/client/views/PropertiesButtons.scss            | 13 +++++++--
 src/client/views/PropertiesButtons.tsx             | 29 +++++++++++++------
 src/client/views/collections/CollectionMenu.scss   | 19 ++++++++-----
 .../views/collections/CollectionTreeView.tsx       |  2 +-
 src/client/views/collections/CollectionView.tsx    |  2 +-
 .../collectionFreeForm/PropertiesView.scss         | 24 ++++++++++++++++
 .../collectionFreeForm/PropertiesView.tsx          | 33 ++++++++++------------
 src/client/views/nodes/DocumentView.tsx            |  8 +++---
 src/client/views/nodes/FontIconBox.scss            |  2 +-
 src/client/views/nodes/FontIconBox.tsx             | 23 ++++++++-------
 src/client/views/nodes/LabelBox.tsx                |  2 +-
 11 files changed, 103 insertions(+), 54 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/PropertiesButtons.scss b/src/client/views/PropertiesButtons.scss
index e099122c4..b3a317a6b 100644
--- a/src/client/views/PropertiesButtons.scss
+++ b/src/client/views/PropertiesButtons.scss
@@ -77,10 +77,19 @@ $linkGap : 3px;
     text-align: center;
     border-radius: 5px;
     pointer-events: auto;
-    color: $dark-color;
-    border: $dark-color 1px solid;
+    // color: $dark-color;
+    // border: $dark-color 1px solid;
+    background-color: #252b33;
+    color: #fcfbf7;
     transition: 0.2s ease all;
     margin-right: 5px;
+    padding-top: 5px;
+
+    &:hover {
+        background: $main-accent;
+        transform: scale(1.05);
+        cursor: pointer;
+    }
 }
 
 .propertiesButtons-linker:hover {
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 59e7cc7c8..d3f056a34 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -208,7 +208,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
         const isPinned = targetDoc && Doc.isDocPinned(targetDoc);
         return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div></>}>
             <div className="propertiesButtons-linker"
-                style={{ backgroundColor: isPinned ? "white" : "rgb(37, 43, 51)", color: isPinned ? "black" : "white" }}
+                style={{ backgroundColor: isPinned ? "white" : "", color: isPinned ? "black" : "white" }}
                 onClick={e => DockedFrameRenderer.PinDoc(targetDoc, isPinned)}>
                 <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin"
                 />
@@ -238,6 +238,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
     onAliasButtonDown = (e: React.PointerEvent): void => {
         setupMoveUpEvents(this, e, this.onAliasButtonMoved, emptyFunction, emptyFunction);
     }
+    @undoBatch
     onAliasButtonMoved = () => {
         if (this._dragRef.current) {
             const dragDocView = this.selectedDocumentView!;
@@ -273,12 +274,17 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                 </div></Tooltip>;
     }
 
+    @undoBatch
     onCopy = () => {
         if (this.selectedDoc && this.selectedDocumentView) {
-            const copy = Doc.MakeCopy(this.selectedDocumentView.props.Document, true);
-            copy.x = NumCast(this.selectedDoc.x) + NumCast(this.selectedDoc._width);
-            copy.y = NumCast(this.selectedDoc.y) + 30;
-            this.selectedDocumentView.props.addDocument?.(copy);
+            // const copy = Doc.MakeCopy(this.selectedDocumentView.props.Document, true);
+            // copy.x = NumCast(this.selectedDoc.x) + NumCast(this.selectedDoc._width);
+            // copy.y = NumCast(this.selectedDoc.y) + 30;
+            // this.selectedDocumentView.props.addDocument?.(copy);
+            const alias = Doc.MakeAlias(this.selectedDoc);
+            alias.x = NumCast(this.selectedDoc.x) + NumCast(this.selectedDoc._width);
+            alias.y = NumCast(this.selectedDoc.y) + 30;
+            this.selectedDocumentView.props.addDocument?.(alias);
         }
     }
 
@@ -295,7 +301,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
         </Tooltip>;
     }
 
-    @action
+    @action @undoBatch
     onLock = () => {
         this.selectedDocumentView?.toggleLockPosition();
     }
@@ -337,15 +343,19 @@ export class PropertiesButtons extends React.Component<{}, {}> {
         return !targetDoc ? (null) : <Tooltip
             title={<><div className="dash-tooltip">{"Delete Document"}</div></>}>
             <div className={"propertiesButtons-linkButton-empty"}
-                onPointerDown={() => {
-                    this.selectedDocumentView?.props.ContainingCollectionView?.removeDocument(this.selectedDocumentView?.props.Document);
-                }}>
+                onPointerDown={this.deleteDocument}>
                 {<FontAwesomeIcon className="propertiesButtons-icon"
                     icon="trash-alt" size="sm" />}
             </div>
         </Tooltip>;
     }
 
+    @undoBatch
+    @action
+    deleteDocument = () => {
+        this.selectedDocumentView?.props.ContainingCollectionView?.removeDocument(this.selectedDocumentView?.props.Document);
+    }
+
     @computed
     get sharingButton() {
         const targetDoc = this.selectedDoc;
@@ -380,6 +390,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
         }
     }
 
+    @undoBatch
     @action
     handleOptionChange = (e: any) => {
         const value = e.target.value;
diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss
index 9da204787..0a316317f 100644
--- a/src/client/views/collections/CollectionMenu.scss
+++ b/src/client/views/collections/CollectionMenu.scss
@@ -2,8 +2,8 @@
 
 
 .collectionMenu-cont {
-    position:relative;
-    display:inline-flex;
+    position: relative;
+    display: inline-flex;
     width: 100%;
     opacity: 0.9;
     z-index: 9001;
@@ -12,14 +12,15 @@
     color: white;
     transform-origin: top left;
     top: 0;
-    width:100%;
+    width: 100%;
 
     .antimodeMenu-button {
         padding: 0;
         width: 30px;
         display: flex;
+
         svg {
-            margin:auto;
+            margin: auto;
         }
     }
 
@@ -108,6 +109,7 @@
                 margin-top: auto;
                 margin-bottom: auto;
             }
+
             .collectionViewBaseChrome-viewSpecs {
                 margin-left: 5px;
                 display: grid;
@@ -318,12 +320,14 @@
         text-align: center;
         display: block;
     }
+
     .color-previewI {
         width: 80%;
         height: 20%;
         bottom: 0;
         position: absolute;
     }
+
     .color-previewII {
         width: 80%;
         height: 80%;
@@ -336,7 +340,7 @@
         margin: auto;
         /* Make the buttons appear below each other */
     }
-    
+
     .btn-draw {
         display: inline-flex;
         margin: auto;
@@ -374,6 +378,7 @@
             display: block;
             margin: auto;
         }
+
         border-right: solid gray 1px;
     }
 }
@@ -398,14 +403,14 @@
 
     .collectionSchemaViewChrome-toggler {
         width: 100px;
-        height: 41px;
+        height: 35px;
         background-color: black;
         position: relative;
     }
 
     .collectionSchemaViewChrome-togglerButton {
         width: 47px;
-        height: 35px;
+        height: 30px;
         background-color: $light-color-secondary;
         // position: absolute;
         transition: all 0.5s ease;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 7787a8b38..3c7471d7c 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -785,7 +785,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
         onClicks.push({
             description: "Edit onChecked Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.doc, undefined, "onCheckedClick"), "edit onCheckedClick"), icon: "edit"
         });
-        !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "hand-point-right" });
+        !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "mouse-pointer" });
     }
     outerXf = () => Utils.GetScreenTransform(this._mainEle!);
     onTreeDrop = (e: React.DragEvent) => this.onExternalDrop(e, {});
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index c2b55d38e..89034a0c0 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -339,7 +339,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                     icon: "edit",
                     event: () => Doc.GetProto(this.props.Document)[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)),
                 }));
-            !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "hand-point-right" });
+            !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "mouse-pointer" });
 
             if (!Doc.UserDoc().noviceMode) {
                 const more = cm.findByDescription("More...");
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.scss b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
index a96716659..7df56115f 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.scss
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
@@ -60,6 +60,10 @@
             padding-left: 8px;
             background-color: rgb(51, 51, 51);
 
+            &:hover {
+                cursor: pointer;
+            }
+
             .propertiesView-settings-title-icon {
                 float: right;
                 right: 0;
@@ -94,6 +98,10 @@
             padding-left: 8px;
             background-color: rgb(51, 51, 51);
 
+            &:hover {
+                cursor: pointer;
+            }
+
             .propertiesView-sharing-title-icon {
                 float: right;
                 right: 0;
@@ -127,6 +135,10 @@
             padding-left: 8px;
             background-color: rgb(51, 51, 51);
 
+            &:hover {
+                cursor: pointer;
+            }
+
             .propertiesView-appearance-title-icon {
                 float: right;
                 right: 0;
@@ -160,6 +172,10 @@
             padding-left: 8px;
             background-color: rgb(51, 51, 51);
 
+            &:hover {
+                cursor: pointer;
+            }
+
             .propertiesView-transform-title-icon {
                 float: right;
                 right: 0;
@@ -287,6 +303,10 @@
             padding-left: 8px;
             background-color: rgb(51, 51, 51);
 
+            &:hover {
+                cursor: pointer;
+            }
+
             .propertiesView-fields-title-name {
                 font-size: 12.5px;
                 font-weight: bold;
@@ -362,6 +382,10 @@
             padding-left: 8px;
             background-color: rgb(51, 51, 51);
 
+            &:hover {
+                cursor: pointer;
+            }
+
             .propertiesView-layout-title-icon {
                 float: right;
                 right: 0;
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index 73f0f1bdd..0168c825f 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -205,7 +205,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         }
     }
 
-
+    @undoBatch
     setKeyValue = (value: string) => {
         if (this.selectedDoc && this.dataDoc) {
             const doc = this.layoutFields ? Doc.Layout(this.selectedDoc) : this.dataDoc;
@@ -266,9 +266,14 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         }
     }
 
+    @undoBatch
+    changePermissions = (e: any, user: string) => {
+        SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, this.selectedDoc!);
+    }
+
     getPermissionsSelect(user: string) {
         return <select className="permissions-select"
-            onChange={e => SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, this.selectedDoc!)}>
+            onChange={e => this.changePermissions(e, user)}>
             {Object.values(SharingPermissions).map(permission => {
                 return (
                     <option key={permission} value={permission} selected={this.selectedDoc![`ACL-${user.replace(".", "_")}`] === permission}>
@@ -344,6 +349,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         />;
     }
 
+    @undoBatch
     @action
     toggleCheckbox = () => {
         this.layoutFields = !this.layoutFields;
@@ -359,6 +365,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             SetValue={this.setTitle} />;
     }
 
+    @undoBatch
     @action
     setTitle = (value: string) => {
         if (this.dataDoc) {
@@ -370,13 +377,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
 
-
-
-
-
-
-
-
     @undoBatch
     @action
     rotate = (angle: number) => {
@@ -739,9 +739,13 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
         if (!this.selectedDoc) {
             return <div className="propertiesView" style={{ width: this.props.width }}>
-                <div className="propertiesView-title" style={{ width: this.props.width, paddingLeft: 6 }}>
+                <div className="propertiesView-title" style={{ width: this.props.width }}>
                     No Document Selected
-            </div> </div>;
+                <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}>
+                        <FontAwesomeIcon icon="times" color="black" size="xs" />
+                    </div>
+                </div>
+            </div>;
         }
 
         const novice = Doc.UserDoc().noviceMode;
@@ -783,9 +787,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 </div> : null}
             </div>
 
-
-
-
             {this.isInk ? <div className="propertiesView-appearance">
                 <div className="propertiesView-appearance-title"
                     onPointerDown={() => runInAction(() => { this.openAppearance = !this.openAppearance; })}
@@ -814,10 +815,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 </div> : null}
             </div> : null}
 
-
-
-
-
             <div className="propertiesView-fields">
                 <div className="propertiesView-fields-title"
                     onPointerDown={() => runInAction(() => { this.openFields = !this.openFields; })}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 30382a4ef..ec0a5f3ac 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -677,10 +677,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     @action
     onCopy = () => {
-        const copy = Doc.MakeCopy(this.props.Document, true);
-        copy.x = NumCast(this.props.Document.x) + NumCast(this.props.Document._width);
-        copy.y = NumCast(this.props.Document.y) + 30;
-        this.props.addDocument?.(copy);
+        const alias = Doc.MakeAlias(this.props.Document);
+        alias.x = NumCast(this.props.Document.x) + NumCast(this.props.Document._width);
+        alias.y = NumCast(this.props.Document.y) + 30;
+        this.props.addDocument?.(alias);
     }
 
     @action
diff --git a/src/client/views/nodes/FontIconBox.scss b/src/client/views/nodes/FontIconBox.scss
index 13af511a6..a142d873a 100644
--- a/src/client/views/nodes/FontIconBox.scss
+++ b/src/client/views/nodes/FontIconBox.scss
@@ -33,7 +33,7 @@
     padding-left: 5px;
     width: 100%;
     width: 60px;
-    height: 70px;
+    height: 60px;
     padding-top: 3px;
     padding-bottom: 3px;
 
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index 720d6a15d..7c538df92 100644
--- a/src/client/views/nodes/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox.tsx
@@ -66,18 +66,21 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
 
         if (this.layoutDoc.menuIcon) {
 
-            let backgroundColor = "black";
-            if (this.dataDoc.title === "Sharing" || this.dataDoc.title === "Help" || this.dataDoc.title === "Settings" || this.dataDoc.title === "Import") {
-                backgroundColor = "black";
-            } else {
-                backgroundColor = CurrentUserUtils.selectedPanel === this.dataDoc.title ? "lightgrey" : "black";
-            }
+            // let backgroundColor = "black";
+            // if (this.dataDoc.title === "Sharing" || this.dataDoc.title === "Help" || this.dataDoc.title === "Settings" || this.dataDoc.title === "Import") {
+            //     backgroundColor = "black";
+            // } else {
+            //     backgroundColor = CurrentUserUtils.selectedPanel === this.dataDoc.title ? "lightgrey" : "";
+            // }
 
-            const color = backgroundColor === "lightgrey" ? "black" : "white";
-            const menuBTN = <div className="menuButton" style={{ backgroundColor: backgroundColor }}>
+            const color = CurrentUserUtils.selectedPanel === this.dataDoc.title ? "black" : "white";
+            const menuBTN = <div className="menuButton"
+                style={{ backgroundColor: CurrentUserUtils.selectedPanel === this.dataDoc.title ? "lightgrey" : "" }}>
 
-                <div className="menuButton-wrap" style={{ backgroundColor: backgroundColor }}>
-                    <FontAwesomeIcon className="menuButton-icon" icon={StrCast(this.dataDoc.icon, "user") as any} color={color} size="lg" />
+                <div className="menuButton-wrap"
+                    style={{ backgroundColor: CurrentUserUtils.selectedPanel === this.dataDoc.title ? "lightgrey" : "" }}>
+                    <FontAwesomeIcon className="menuButton-icon"
+                        icon={StrCast(this.dataDoc.icon, "user") as any} color={color} size="lg" />
                     <div className="menuButton-label" style={{ color: color }}> {this.dataDoc.title} </div>
                 </div>
             </div>;
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 0dfbdc5cf..05ba6628c 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -41,7 +41,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps, LabelDocument
             }, icon: "trash"
         });
 
-        ContextMenu.Instance.addItem({ description: "OnClick...", noexpand: true, subitems: funcs, icon: "asterisk" });
+        ContextMenu.Instance.addItem({ description: "OnClick...", noexpand: true, subitems: funcs, icon: "mouse-pointer" });
     }
 
     @undoBatch
-- 
cgit v1.2.3-70-g09d2


From 2a5ed028c356e122acade2b695cdb56f727c681f Mon Sep 17 00:00:00 2001
From: usodhi <61431818+usodhi@users.noreply.github.com>
Date: Tue, 4 Aug 2020 01:38:55 +0530
Subject: reinstated collection acl inheritance

---
 src/client/views/DocComponent.tsx               | 19 ++++++++++---------
 src/client/views/collections/CollectionView.tsx | 19 ++++++++-----------
 2 files changed, 18 insertions(+), 20 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 804c7a8d4..34144d3eb 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -154,15 +154,16 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
                     return false;
                 }
                 else {
-                    // if (this.props.Document[AclSym]) {
-                    //     added.forEach(d => {
-                    //         const dataDoc = d[DataSym];
-                    //         dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym];
-                    //         for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
-                    //             dataDoc[key] = d[key] = this.AclMap.get(value);
-                    //         }
-                    //     });
-                    // }
+                    if (this.props.Document[AclSym]) {
+                        added.forEach(d => {
+                            const dataDoc = d[DataSym];
+                            dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym];
+                            for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
+                                dataDoc[key] = d[key] = this.AclMap.get(value);
+                            }
+                        });
+                    }
+
                     if (effectiveAcl === AclAddonly) {
                         added.map(doc => Doc.AddDocToList(targetDataDoc, this.annotationKey, doc));
                     }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 89034a0c0..44875ac1e 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -17,7 +17,7 @@ import { listSpec } from '../../../fields/Schema';
 import { ComputedField, ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
-import { TraceMobx, GetEffectiveAcl, SharingPermissions } from '../../../fields/util';
+import { TraceMobx, GetEffectiveAcl, SharingPermissions, distributeAcls } from '../../../fields/util';
 import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
@@ -147,16 +147,13 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 return false;
             }
             else {
-                // if (this.props.Document[AclSym]) {
-                //     // change so it only adds if more restrictive
-                //     added.forEach(d => {
-                //         // const dataDoc = d[DataSym];
-                //         for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
-                //             // key.substring(4).replace("_", ".") !== Doc.CurrentUserEmail && distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true);
-                //             distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true);
-                //         }
-                //     });
-                // }
+                if (this.props.Document[AclSym]) {
+                    added.forEach(d => {
+                        for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
+                            distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true);
+                        }
+                    });
+                }
 
                 if (effectiveAcl === AclAddonly) {
                     added.map(doc => Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc));
-- 
cgit v1.2.3-70-g09d2


From 9811044a5731fb949b2a59962308cfc4d9df09fb Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 4 Aug 2020 15:27:48 -0400
Subject: more search cleanup

---
 src/client/views/collections/CollectionSchemaCells.tsx |  1 -
 src/client/views/collections/CollectionSchemaView.scss |  2 +-
 src/client/views/collections/CollectionSubView.tsx     | 15 +++++----------
 src/client/views/collections/CollectionView.tsx        |  2 --
 src/client/views/nodes/LabelBox.tsx                    |  8 ++------
 src/client/views/search/SearchBox.scss                 |  5 +----
 6 files changed, 9 insertions(+), 24 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index ecd20eb06..6b0d726f2 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -241,7 +241,6 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
         //         <FontAwesomeIcon icon="expand" size="sm" />
         //     </div>
         // );   
-        trace();
         let positions = [];
         if (StrCast(this.props.Document._searchString) !== "") {
             const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
index 93878d799..e572e8f5f 100644
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ b/src/client/views/collections/CollectionSchemaView.scss
@@ -165,7 +165,7 @@
     .collectionSchema-apper {
         &.col-before {
             border-left: 2px solid red;
-        }
+    }
 
         &.col-after {
             border-right: 2px solid red;
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 88241f519..6f075be92 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -112,9 +112,10 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                 [...this.props.docFilters(), ...Cast(this.props.Document._docFilters, listSpec("string"), [])];
         }
         @computed get childDocs() {
+            let rawdocs: (Doc | Promise<Doc>)[] = DocListCast(this.props.Document._searchDocs);
 
-            let rawdocs: (Doc | Promise<Doc>)[] = [];
-            if (this.dataField instanceof Doc) { // if collection data is just a document, then promote it to a singleton list;
+            if (rawdocs.length !== 0) {
+            } else if (this.dataField instanceof Doc) { // if collection data is just a document, then promote it to a singleton list;
                 rawdocs = [this.dataField];
             } else if (Cast(this.dataField, listSpec(Doc), null)) { // otherwise, if the collection data is a list, then use it.  
                 rawdocs = Cast(this.dataField, listSpec(Doc), null);
@@ -127,16 +128,9 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
 
             const docs = rawdocs.filter(d => !(d instanceof Promise)).map(d => d as Doc);
             const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
-            let childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
-
-            const searchDocs = DocListCast(this.props.Document._searchDocs);
-            if (searchDocs !== undefined && searchDocs.length > 0) {
-                childDocs = searchDocs;
-            }
-            const docFilters = this.docFilters();
             const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
 
-            return this.props.Document.dontRegisterView ? childDocs : DocUtils.FilterDocs(childDocs, docFilters, docRangeFilters, viewSpecScript);
+            return this.props.Document.dontRegisterView ? docs : DocUtils.FilterDocs(docs, this.docFilters(), docRangeFilters, viewSpecScript);
         }
 
         @action
@@ -442,4 +436,5 @@ import { CollectionView, CollectionViewType } from "./CollectionView";
 import { SelectionManager } from "../../util/SelectionManager";
 import { OverlayView } from "../OverlayView";
 import { setTimeout } from "timers";
+import { raw } from "serializr";
 
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 123519b08..6e15cb887 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -184,8 +184,6 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                     // targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]);
                     (targetDataDoc[this.props.fieldKey] as List<Doc>).push(...added);
                     targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
-                    targetDataDoc["lastModified"] = new DateField(new Date(Date.now()));
-
                 }
             }
         }
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 302d66cc5..ccdd088d3 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -1,5 +1,3 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faEdit } from '@fortawesome/free-regular-svg-icons';
 import { action, computed, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
@@ -59,8 +57,6 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps, LabelDocument
         }
     }
 
-
-
     @observable backColor = "unset";
 
     @observable clicked = false;
@@ -75,9 +71,9 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps, LabelDocument
                 style={{ boxShadow: this.layoutDoc.opacity ? StrCast(this.layoutDoc.boxShadow) : "" }}>
                 <div className="labelBox-mainButton" style={{
                     background: StrCast(this.layoutDoc.backgroundColor),
-                    color: StrCast(this.layoutDoc.color),
                     backgroundColor: this.backColor,
-                    fontSize: NumCast(this.layoutDoc.fontSize) || "inherit",
+                    color: StrCast(this.layoutDoc.color, "inherit"),
+                    fontSize: StrCast(this.layoutDoc._fontSize) || "inherit",
                     fontFamily: StrCast(this.layoutDoc._fontFamily) || "inherit",
                     letterSpacing: StrCast(this.layoutDoc.letterSpacing),
                     textTransform: StrCast(this.layoutDoc.textTransform) as any,
diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss
index 8cd2f00b4..3f06ba7d3 100644
--- a/src/client/views/search/SearchBox.scss
+++ b/src/client/views/search/SearchBox.scss
@@ -147,10 +147,7 @@
         overflow:hidden;
         transition:height 0.3s ease-out;
         height:0px;
-
-        .labelBox-mainButton:hover{
-            color:"White";
-        }
+        
         // .filter-keybar {
         //     display: flex;
         //     flex-wrap: wrap;
-- 
cgit v1.2.3-70-g09d2


From 3e4329b81d96f139f38eeb182afcbd8359dcd171 Mon Sep 17 00:00:00 2001
From: usodhi <61431818+usodhi@users.noreply.github.com>
Date: Thu, 6 Aug 2020 19:51:25 +0530
Subject: alias and acl related fixes

---
 src/client/documents/Documents.ts                    |  1 +
 src/client/views/collections/CollectionView.tsx      |  3 ++-
 .../collectionFreeForm/PropertiesView.tsx            | 20 +++++++++++---------
 src/fields/Doc.ts                                    |  4 ++--
 src/fields/util.ts                                   |  2 +-
 5 files changed, 17 insertions(+), 13 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 7719b3eef..61a44a39d 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -565,6 +565,7 @@ export namespace Docs {
             // without this, if a doc has no annotations but the user has AddOnly privileges, they won't be able to add an annotation because they would have needed to create the field's list which they don't have permissions to do.
 
             dataDoc[fieldKey + "-annotations"] = new List<Doc>();
+            dataDoc.aliases = new List<Doc>();
 
             proto.links = ComputedField.MakeFunction("links(self)");
 
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index dcd5a31f6..4d1cb670c 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -151,7 +151,8 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 if (this.props.Document[AclSym]) {
                     added.forEach(d => {
                         for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
-                            distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true);
+                            if (d.author === Doc.CurrentUserEmail && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d, true);
+                            else distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true);
                         }
                     });
                 }
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index d22c00b1f..5634a438a 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -25,6 +25,7 @@ import "./FormatShapePane.scss";
 import { discovery_v1 } from "googleapis";
 import { PresBox } from "../../nodes/PresBox";
 import { DocumentManager } from "../../../util/DocumentManager";
+import FormatShapePane from "./FormatShapePane";
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -51,8 +52,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     @computed get selectedDocumentView() {
         if (SelectionManager.SelectedDocuments().length) {
             return SelectionManager.SelectedDocuments()[0];
-        } else if (PresBox.Instance._selectedArray.length >= 1) {
-            return DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc);
+        } else if (PresBox.Instance?._selectedArray.length >= 1) {
+            return DocumentManager.Instance.getDocumentView(PresBox.Instance?.rootDoc);
         } else { return undefined; }
     }
     @computed get isPres(): boolean {
@@ -72,6 +73,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     @observable openTransform: boolean = true;
     // @observable selectedUser: string = "";
     // @observable addButtonPressed: boolean = false;
+
     //Pres Trails booleans:
     @observable openAddSlide: boolean = true;
     @observable openPresentationTools: boolean = true;
@@ -957,9 +959,9 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     <div className="propertiesView-name">
                         {this.editableTitle}
                         <div className="propertiesView-presSelected">
-                            {PresBox.Instance._selectedArray.length} selected
+                            {PresBox.Instance?._selectedArray.length} selected
                             <div className="propertiesView-selectedList">
-                                {PresBox.Instance.listOfSelected}
+                                {PresBox.Instance?.listOfSelected}
                             </div>
                         </div>
                     </div>
@@ -973,7 +975,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             </div>
                         </div>
                         {this.openAddSlide ? <div className="propertiesView-settings-content">
-                            {PresBox.Instance.newDocumentDropdown}
+                            {PresBox.Instance?.newDocumentDropdown}
                         </div> : null}
                     </div>
                     <div className="propertiesView-sharing">
@@ -986,7 +988,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             </div>
                         </div>
                         {this.openPresTransitions ? <div className="propertiesView-sharing-content">
-                            {PresBox.Instance.transitionDropdown}
+                            {PresBox.Instance?.transitionDropdown}
                         </div> : null}
                     </div>
                     <div className="propertiesView-sharing">
@@ -999,20 +1001,20 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             </div>
                         </div>
                         {this.openPresProgressivize ? <div className="propertiesView-sharing-content">
-                            {PresBox.Instance.progressivizeDropdown}
+                            {PresBox.Instance?.progressivizeDropdown}
                         </div> : null}
                     </div>
                     <div className="propertiesView-sharing">
                         <div className="propertiesView-sharing-title"
                             onPointerDown={() => runInAction(() => { this.openSlideOptions = !this.openSlideOptions; })}
                             style={{ backgroundColor: this.openSlideOptions ? "black" : "" }}>
-                            &nbsp; <FontAwesomeIcon icon={"cog"} /> &nbsp; {PresBox.Instance.stringType} options
+                            &nbsp; <FontAwesomeIcon icon={"cog"} /> &nbsp; {PresBox.Instance?.stringType} options
                         <div className="propertiesView-sharing-title-icon">
                                 <FontAwesomeIcon icon={this.openSlideOptions ? "caret-down" : "caret-right"} size="lg" color="white" />
                             </div>
                         </div>
                         {this.openSlideOptions ? <div className="propertiesView-sharing-content">
-                            {PresBox.Instance.optionsDropdown}
+                            {PresBox.Instance?.optionsDropdown}
                         </div> : null}
                     </div>
                     <div className="propertiesView-sharing">
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 6163fedbb..6bfe91378 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -508,9 +508,9 @@ export namespace Doc {
         alias.aliasOf = doc;
         alias.title = ComputedField.MakeFunction(`renameAlias(this, ${Doc.GetProto(doc).aliasNumber = NumCast(Doc.GetProto(doc).aliasNumber) + 1})`);
         alias.author = Doc.CurrentUserEmail;
+        alias[AclSym] = doc[AclSym];
 
-        if (!doc.aliases) doc.aliases = new List<Doc>([alias]);
-        else Doc.AddDocToList(doc, "aliases", alias);
+        Doc.AddDocToList(doc[DataSym], "aliases", alias);
 
         return alias;
     }
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 44a3317db..4c71572db 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -220,7 +220,7 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
         // maps over the aliases of the document
         if (target.aliases) {
             DocListCast(target.aliases).map(alias => {
-                distributeAcls(key, acl, alias);
+                distributeAcls(key, acl, alias, inheritingFromCollection);
             });
         }
 
-- 
cgit v1.2.3-70-g09d2

