From 3c6e77b7d2bcf4782d981b19bc32e402e07863ad Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 28 Sep 2020 10:11:12 -0400
Subject: fixed docRangeFilters to be propagated everywhere and evaluated like
 docFilters (if the field isn't there, it fails)

---
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx      | 1 +
 1 file changed, 1 insertion(+)

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

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 8af048d67..75ad8e5b0 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -964,6 +964,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             ContainingCollectionView: this.props.CollectionView,
             ContainingCollectionDoc: this.props.Document,
             docFilters: this.docFilters,
+            docRangeFilters: this.docRangeFilters,
             searchFilterDocs: this.searchFilterDocs,
             focus: this.focusDocument,
             backgroundColor: this.getClusterColor,
-- 
cgit v1.2.3-70-g09d2


From 9ad43c9e2a068fdf6308339f6f82e29cf94d2c14 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 29 Sep 2020 02:46:28 -0400
Subject: changed sidebar functionality for textboxes to open outward and make
 handle blue when there are contents.  added a fitToBox capability for
 contents of sidebar.

---
 src/client/views/DocumentButtonBar.tsx             |  4 +--
 src/client/views/PropertiesButtons.tsx             |  2 +-
 .../views/collections/CollectionStackingView.tsx   |  2 +-
 src/client/views/collections/TreeView.tsx          |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 36 ++++++++++++----------
 src/client/views/nodes/WebBox.tsx                  |  2 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx | 13 +++++---
 src/client/views/pdf/Annotation.tsx                |  8 ++---
 src/client/views/pdf/PDFViewer.tsx                 |  4 +--
 9 files changed, 40 insertions(+), 33 deletions(-)

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

diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index c5fd3c777..5ec43319b 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -363,9 +363,9 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
             {![DocumentType.VID, DocumentType.WEB].includes(StrCast(this.view0.props.Document.type) as DocumentType) ? (null) : <div className="documentButtonBar-button">
                 {this.annotateButton}
             </div>}
-            <div className="documentButtonBar-button" style={{ display: !considerPush ? "none" : "" }}>
+            {!Doc.UserDoc()["documentLinksButton-fullMenu"] ? (null) : <div className="documentButtonBar-button" style={{ display: !considerPush ? "none" : "" }}>
                 {this.considerGoogleDocsPush}
-            </div>
+            </div>}
             <div className="documentButtonBar-button" style={{ display: !considerPull ? "none" : "" }}>
                 {this.considerGoogleDocsPull}
             </div>
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 462091f63..9de4f9c67 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -529,7 +529,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
             <div className="propertiesButtons-button" style={{ display: !isFreeForm ? "none" : "" }}>
                 {this.clustersButton}
             </div>
-            <div className="propertiesButtons-button" style={{ display: !isFreeForm ? "none" : "" }}>
+            <div className="propertiesButtons-button" style={{ display: !isFreeForm && !isText ? "none" : "" }}>
                 {this.fitContentButton}
             </div>
             <div className="propertiesButtons-button" style={{ display: !isInk ? "none" : "" }}>
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 4ee00e0f4..423d39951 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -176,7 +176,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
             const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
             smoothScroll(doc.presTransition || doc.presTransition === 0 ? NumCast(doc.presTransition) : 500, this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
         }
-        afterFocus && setTimeout(() => afterFocus?.(), 500);
+        afterFocus && setTimeout(afterFocus, 500);
     }
 
     getDisplayDoc(doc: Doc, dxf: () => Transform, width: () => number) {
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 072cd23db..06c35de03 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -664,7 +664,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         ignoreFields: string[] | undefined,
         firstLevel: boolean,
         whenActiveChanged: (isActive: boolean) => void,
-        dontRegisterView: boolean | undeifned) {
+        dontRegisterView: boolean | undefined) {
         const viewSpecScript = Cast(containingCollection.viewSpecScript, ScriptField);
         if (viewSpecScript) {
             childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 75ad8e5b0..967055638 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -104,28 +104,32 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
     @observable canPanY: boolean = true;
 
     @computed get fitToContentScaling() { return this.fitToContent ? NumCast(this.layoutDoc.fitToContentScaling, 1) : 1; }
-    @computed get fitToContent() { return (this.props.fitToBox || this.Document._fitToBox) && !this.isAnnotationOverlay; }
-    @computed get parentScaling() { return this.props.ContentScaling && this.fitToContent && !this.isAnnotationOverlay ? this.props.ContentScaling() : 1; }
+    @computed get fitToContent() { return this.props.fitToBox || (this.Document._fitToBox && !this.isAnnotationOverlay); }
+    @computed get parentScaling() { return this.props.ContentScaling && this.fitToContent ? this.props.ContentScaling() : 1; }
     @computed get contentBounds() { return aggregateBounds(this._layoutElements.filter(e => e.bounds && !e.bounds.z).map(e => e.bounds!), NumCast(this.layoutDoc._xPadding, 10), NumCast(this.layoutDoc._yPadding, 10)); }
     @computed get nativeWidth() { return this.fitToContent ? 0 : returnVal(this.props.NativeWidth?.(), NumCast(this.Document._nativeWidth)); }
     @computed get nativeHeight() { return this.fitToContent ? 0 : returnVal(this.props.NativeHeight?.(), NumCast(this.Document._nativeHeight)); }
     private get isAnnotationOverlay() { return this.props.isAnnotationOverlay; }
     private get scaleFieldKey() { return this.props.scaleField || "_viewScale"; }
     private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; }
-    private panX = () => this.fitToContent ? (this.contentBounds.x + this.contentBounds.r) / 2 : this.Document._panX || 0;
-    private panY = () => this.fitToContent ? (this.contentBounds.y + this.contentBounds.b) / 2 : this.Document._panY || 0;
-    private zoomScaling = () => (this.fitToContentScaling / this.parentScaling) * (this.fitToContent ?
-        Math.min(this.props.PanelHeight() / (this.contentBounds.b - this.contentBounds.y),
-            this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x)) :
-        NumCast(this.Document[this.scaleFieldKey], 1))
-
+    private panX = () => this.fitToContent && !this.props.isAnnotationOverlay ? (this.contentBounds.x + this.contentBounds.r) / 2 : this.Document._panX || 0;
+    private panY = () => this.fitToContent && !this.props.isAnnotationOverlay ? (this.contentBounds.y + this.contentBounds.b) / 2 : this.Document._panY || 0;
+    private zoomScaling = () => {
+        const mult = this.fitToContentScaling / this.parentScaling;
+        if (this.fitToContent) {
+            const zs = !this.childDocs.length ? 1 :
+                Math.min(this.props.PanelHeight() / (this.contentBounds.b - this.contentBounds.y), this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x));
+            return mult * (this.props.isAnnotationOverlay ? Math.min(zs, 1) : zs);
+        }
+        return mult * NumCast(this.Document[this.scaleFieldKey], 1);
+    }
     @computed get cachedCenteringShiftX(): number {
         const scaling = this.fitToContent || !this.contentScaling ? 1 : this.contentScaling;
-        return !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling / scaling : 0;  // shift so pan position is at center of window for non-overlay collections
+        return !this.props.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling / scaling : 0;  // shift so pan position is at center of window for non-overlay collections
     }
     @computed get cachedCenteringShiftY(): number {
         const scaling = this.fitToContent || !this.contentScaling ? 1 : this.contentScaling;
-        return !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling / scaling : 0;// shift so pan position is at center of window for non-overlay collections
+        return !this.props.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling / scaling : 0;// shift so pan position is at center of window for non-overlay collections
     }
     @computed get cachedGetLocalTransform(): Transform {
         return Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY());
@@ -776,9 +780,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
     @action
     zoom = (pointX: number, pointY: number, deltaY: number): void => {
         let deltaScale = deltaY > 0 ? (1 / 1.05) : 1.05;
-        if (deltaScale * this.zoomScaling() < 1 && this.isAnnotationOverlay) {
-            deltaScale = 1 / this.zoomScaling();
-        }
         if (deltaScale < 0) deltaScale = -deltaScale;
         const [x, y] = this.getTransform().transformPoint(pointX, pointY);
         const localTransform = this.getLocalTransform().inverse().scaleAbout(deltaScale, x, y);
@@ -1106,7 +1107,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         });
         this._cachedPool.clear();
         Array.from(newPool.entries()).forEach(k => this._cachedPool.set(k[0], k[1]));
-        const elements: ViewDefResult[] = computedElementData.slice();
+        const elements = computedElementData.slice();
         const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine);
         Array.from(newPool.entries()).filter(entry => this.isCurrent(entry[1].pair.layout)).forEach(entry =>
             elements.push({
@@ -1127,8 +1128,9 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
                 bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica)
             }));
 
-        if (this.props.isAnnotationOverlay) {
-            this.props.Document[this.scaleFieldKey] = Math.max(1, NumCast(this.props.Document[this.scaleFieldKey]));
+        if (this.props.isAnnotationOverlay) {   // don't zoom out farther than 1-1 if it's a bounded item (image, video, pdf), otherwise don't allow zooming in closer than 1-1 if it's a text sidebar
+            if (this.props.scaleField) this.props.Document[this.scaleFieldKey] = Math.min(1, NumCast(this.props.Document[this.scaleFieldKey], 1));
+            else this.props.Document[this.scaleFieldKey] = Math.max(1, NumCast(this.props.Document[this.scaleFieldKey]));
         }
 
         this.Document._useClusters && !this._clusterSets.length && this.childDocs.length && this.updateClusters(true);
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 61f01cc95..a7b534956 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -458,7 +458,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
         TraceMobx();
         return <div className="webBox-annotationLayer" style={{ height: NumCast(this.Document._nativeHeight) }} ref={this._annotationLayer}>
             {this.nonDocAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno =>
-                <Annotation {...this.props} focus={this.props.focus} dataDoc={this.dataDoc} fieldKey={this.props.fieldKey} anno={anno} key={`${anno[Id]}-annotation`} />)
+                <Annotation {...this.props} showInfo={emptyFunction} focus={this.props.focus} dataDoc={this.dataDoc} fieldKey={this.props.fieldKey} anno={anno} key={`${anno[Id]}-annotation`} />)
             }
         </div>;
     }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index e7b4b72f4..a0af8d60f 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -557,7 +557,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
 
     sidebarDown = (e: React.PointerEvent) => {
         setupMoveUpEvents(this, e, this.sidebarMove, emptyFunction,
-            () => this.layoutDoc._showSidebar = ((this.layoutDoc._sidebarWidthPercent = StrCast(this.layoutDoc._sidebarWidthPercent, "0%") === "0%" ? "25%" : "0%")) !== "0%");
+            action(() => {
+                const prevWidth = this.sidebarWidth();
+                this.layoutDoc._showSidebar = ((this.layoutDoc._sidebarWidthPercent = StrCast(this.layoutDoc._sidebarWidthPercent, "0%") === "0%" ? "50%" : "0%")) !== "0%";
+                this.layoutDoc._width = this.layoutDoc._showSidebar ? NumCast(this.layoutDoc._width) * 2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth);
+            }));
     }
     sidebarMove = (e: PointerEvent, down: number[], delta: number[]) => {
         const bounds = this.CurrentDiv.getBoundingClientRect();
@@ -1518,16 +1522,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         }
     }
 
-    return1000 = () => 1000;
     @computed get sidebarCollection() {
+        const fitToBox = this.props.Document._fitToBox;
         return !this.layoutDoc._showSidebar || this.sidebarWidthPercent === "0%" ? (null) :
             <div className={"formattedTextBox-sidebar" + (Doc.GetSelectedTool() !== InkTool.None ? "-inking" : "")} style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
                 <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
-                    PanelHeight={this.active() ? this.return1000 : this.props.PanelHeight}
+                    PanelHeight={this.props.PanelHeight}
                     PanelWidth={this.sidebarWidth}
                     scaleField={this.annotationKey + "-scale"}
                     annotationsKey={this.annotationKey}
                     isAnnotationOverlay={true}
+                    fitToBox={fitToBox}
                     focus={this.props.focus}
                     isSelected={this.props.isSelected}
                     select={emptyFunction}
@@ -1614,7 +1619,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                         />
                     </div>
                     {this.sidebarCollection}
-                    {selected ? <div className="formattedTextBox-sidebar-handle" style={{ left: `max(0px, calc(100% - ${this.sidebarWidthPercent} - 5px))` }} onPointerDown={this.sidebarDown} /> : (null)}
+                    {selected ? <div className="formattedTextBox-sidebar-handle" style={{ left: `max(0px, calc(100% - ${this.sidebarWidthPercent} - 5px))`, background: DocListCast(this.dataDoc[this.annotationKey]).length ? "lightBlue" : undefined }} onPointerDown={this.sidebarDown} /> : (null)}
                     {!this.layoutDoc._showAudio ? (null) :
                         <div className="formattedTextBox-dictation" onClick={action(e => this._recording = !this._recording)} >
                             <FontAwesomeIcon className="formattedTextBox-audioFont" style={{ color: this._recording ? "red" : "blue", transitionDelay: "0.6s", opacity: this._recording ? 1 : 0.25, }} icon={"microphone"} size="sm" />
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index b7c7dae38..84b14cd61 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -1,7 +1,7 @@
 import React = require("react");
 import { action, IReactionDisposer, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, DocListCast, HeightSym, WidthSym, Field } from "../../../fields/Doc";
+import { Doc, DocListCast, HeightSym, WidthSym, Field, Opt } from "../../../fields/Doc";
 import { Id } from "../../../fields/FieldSymbols";
 import { List } from "../../../fields/List";
 import { Cast, FieldValue, BoolCast, NumCast, StrCast, PromiseValue } from "../../../fields/Types";
@@ -17,7 +17,7 @@ interface IAnnotationProps {
     focus: (doc: Doc) => void;
     dataDoc: Doc;
     fieldKey: string;
-    showInfo: (anno: Doc) => void;
+    showInfo: (anno: Opt<Doc>) => void;
 }
 
 @observer
@@ -25,7 +25,7 @@ export
     class Annotation extends React.Component<IAnnotationProps> {
     render() {
         return DocListCast(this.props.anno.annotations).map(a =>
-            <RegionAnnotation {...this.props} pinToPres={this.props.pinToPres} document={a} x={NumCast(a.x)} y={NumCast(a.y)} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />);
+            <RegionAnnotation {...this.props} showInfo={this.props.showInfo} pinToPres={this.props.pinToPres} document={a} x={NumCast(a.x)} y={NumCast(a.y)} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />);
     }
 }
 
@@ -40,7 +40,7 @@ interface IRegionAnnotationProps {
     document: Doc;
     dataDoc: Doc;
     fieldKey: string;
-    showInfo: (anno: Doc) => void;
+    showInfo: (anno: Opt<Doc>) => void;
 }
 
 @observer
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index e54464b77..fb87da744 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -703,10 +703,10 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
                 <div className="pdfViewerDash-overlayAnno" style={{ right: -50, background: SharingManager.Instance.users.find(users => users.user.email === this._overlayAnnoInfo!.author)?.userColor }}>
                     {this._overlayAnnoInfo.author + " " + Field.toString(this._overlayAnnoInfo.creationDate as Field)}
                 </div>
-            </div>
+            </div>;
     }
 
-    showInfo = action((anno: Doc) => this._overlayAnnoInfo = anno);
+    showInfo = action((anno: Opt<Doc>) => this._overlayAnnoInfo = anno);
     overlayTransform = () => this.scrollXf().scale(1 / this._zoomed);
     panelWidth = () => (this.Document.scrollHeight || this.Document._nativeHeight || 0);
     panelHeight = () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : (this.Document._nativeWidth || 0);
-- 
cgit v1.2.3-70-g09d2


From 1cb5ac5e07ad90589670a788e3144d9d9581a393 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 29 Sep 2020 15:03:16 -0400
Subject: made pdf/web anchors pushpins by default. can now remove docs you own
 from sidebars you don't.   made formatted text boxes alway show sidebar
 handle when there's content.  sidebar text has no padding by default. sidebar
 collection doesn't scroll when text overflows. added more playground fields

---
 src/client/documents/Documents.ts                  | 21 ++++++++++++
 src/client/util/CurrentUserUtils.ts                |  3 +-
 src/client/views/DocComponent.tsx                  |  3 +-
 src/client/views/MainView.tsx                      |  2 +-
 src/client/views/collections/CollectionSubView.tsx |  1 +
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  6 ++++
 .../collections/collectionFreeForm/MarqueeView.tsx |  2 +-
 src/client/views/nodes/FilterBox.tsx               |  2 +-
 src/client/views/nodes/WebBox.tsx                  |  1 +
 .../nodes/formattedText/FormattedTextBox.scss      | 18 +++++-----
 .../views/nodes/formattedText/FormattedTextBox.tsx | 40 ++++++++++++++++------
 src/client/views/pdf/PDFViewer.tsx                 |  3 +-
 12 files changed, 76 insertions(+), 26 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 19f719c43..ad30e7d33 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -889,6 +889,27 @@ export namespace Docs {
 }
 
 export namespace DocUtils {
+    export function Excluded(d: Doc, docFilters: string[]) {
+        const filterFacets: { [key: string]: { [value: string]: string } } = {};  // maps each filter key to an object with value=>modifier fields
+        for (let i = 0; i < docFilters.length; i += 3) {
+            const [key, value, modifiers] = docFilters.slice(i, i + 3);
+            if (!filterFacets[key]) {
+                filterFacets[key] = {};
+            }
+            filterFacets[key][value] = modifiers;
+        }
+
+        if (d.z) return false;
+        for (const facetKey of Object.keys(filterFacets)) {
+            const facet = filterFacets[facetKey];
+            const xs = Object.keys(facet).filter(value => facet[value] === "x");
+            const failsNotEqualFacets = xs?.some(value => Doc.matchFieldValue(d, facetKey, value));
+            if (failsNotEqualFacets) {
+                return true;
+            }
+        }
+        return false;
+    }
     export function FilterDocs(docs: Doc[], docFilters: string[], docRangeFilters: string[], viewSpecScript?: ScriptField) {
         const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
 
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 342954a4e..3e76b189a 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1127,8 +1127,9 @@ export class CurrentUserUtils {
         CurrentUserUtils.openDashboard(userDoc, dashboardDoc);
     }
 
-    public static GetNewTextDoc(title: string, x: number, y: number, width?: number, height?: number) {
+    public static GetNewTextDoc(title: string, x: number, y: number, width?: number, height?: number, noMargins?: boolean) {
         const tbox = Docs.Create.TextDocument("", {
+            _xMargin: noMargins ? 0 : undefined, _yMargin: noMargins ? 0 : undefined,
             _width: width || 200, _height: height || 100, x: x, y: y, _autoHeight: true, _fontSize: StrCast(Doc.UserDoc().fontSize),
             _fontFamily: StrCast(Doc.UserDoc().fontFamily), title
         });
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index b3c90a68f..893b74d75 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -123,7 +123,8 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
         @action.bound
         removeDocument(doc: Doc | Doc[]): boolean {
             const effectiveAcl = GetEffectiveAcl(this.dataDoc);
-            if (effectiveAcl === AclAdmin || effectiveAcl === AclEdit) {
+            const docAcl = GetEffectiveAcl(doc);
+            if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin || docAcl === AclAdmin) {
                 const docs = doc instanceof Doc ? [doc] : doc;
                 docs.map(doc => doc.isPushpin = doc.annotationOn = undefined);
                 const targetDataDoc = this.dataDoc;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 4299dba86..5469c2358 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -86,7 +86,7 @@ export class MainView extends React.Component {
         document.getElementById("root")?.addEventListener("scroll", e => ((ele) => ele.scrollLeft = ele.scrollTop = 0)(document.getElementById("root")!));
         new InkStrokeProperties();
         this._sidebarContent.proto = undefined;
-        DocServer.setPlaygroundFields(["dataTransition", "_viewTransition", "_panX", "_panY", "_viewScale", "_scrollY", "_scrollTop", "hidden", "_curPage", "_viewType", "_chromeStatus"]); // can play with these fields on someone else's
+        DocServer.setPlaygroundFields(["dataTransition", "_delayAutoHeight", "_autoHeight", "_showSidebar", "_sidebarWidthPercent", "_width", "_height", "_viewTransition", "_panX", "_panY", "_viewScale", "_scrollY", "_scrollTop", "hidden", "_curPage", "_viewType", "_chromeStatus"]); // can play with these fields on someone else's
 
         DocServer.GetRefField("rtfProto").then(proto => (proto instanceof Doc) && reaction(() => StrCast(proto.BROADCAST_MESSAGE), msg => msg && alert(msg)));
 
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 26fe00657..649b8c175 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -142,6 +142,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
 
             const docsforFilter: Doc[] = [];
             childDocs.forEach((d) => {
+                if (DocUtils.Excluded(d, docFilters)) return;
                 let notFiltered = d.z || ((!searchDocs.length || searchDocs.includes(d)) && ((!docFilters.length && !docRangeFilters.length) || DocUtils.FilterDocs([d], docFilters, docRangeFilters, viewSpecScript).length > 0));
                 const fieldKey = Doc.LayoutFieldKey(d);
                 const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView");
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 967055638..a3f76839d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1625,6 +1625,12 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
         const pany = -this.props.panY();
         const zoom = this.props.zoomScaling();
         return <div className={freeformclass}
+            onScroll={e => {
+                const target = e.target as any;
+                if (getComputedStyle(target.parentElement)?.overflow === "visible") {  // if collection is visible, then scrolling will mess things up since there are no scroll bars
+                    target.scrollTop = target.scrollLeft = 0;
+                }
+            }}
             style={{
                 transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}) translate(${panx}px, ${pany}px)`,
                 transition: this.props.transition,
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index e1ebb4eee..7c64fd429 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -141,7 +141,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             } else if (!e.ctrlKey && !e.metaKey) {
                 FormattedTextBox.SelectOnLoadChar = FormattedTextBox.DefaultLayout && !this.props.ChildLayoutString ? e.key : "";
                 FormattedTextBox.LiveTextUndo = UndoManager.StartBatch("live text batch");
-                this.props.addLiveTextDocument(CurrentUserUtils.GetNewTextDoc("-typed text-", x, y, 200, 100));
+                this.props.addLiveTextDocument(CurrentUserUtils.GetNewTextDoc("-typed text-", x, y, 200, 100, this.props.xMargin === 0));
                 e.stopPropagation();
             }
     }
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index c1978e331..d5b50122b 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -48,7 +48,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
 
         const keys = new Set<string>(noviceFields);
         this.allDocs.forEach(doc => SearchBox.documentKeys(doc).filter(key => keys.add(key)));
-        return Array.from(keys.keys()).filter(key => key[0] === "#" || key.indexOf("lastModified") !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith("_") && !key.startsWith("acl")) || noviceFields.includes(key)).sort();
+        return Array.from(keys.keys()).filter(key => key[0] === "#" || key.indexOf("lastModified") !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith("_")) || noviceFields.includes(key) || !Doc.UserDoc().noviceMode).sort();
     }
 
     gatherFieldValues(dashboard: Doc, facetKey: string) {
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index a7b534956..421aac69f 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -508,6 +508,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
                     if (!e.aborted && e.annoDragData && !e.annoDragData.linkDocument) {
                         e.annoDragData.linkDocument = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation");
                         annotationDoc.isLinkButton = true;
+                        annotationDoc.isPushpin = e.annoDragData?.dropDocument.annotationOn === this.props.Document;
                     }
                 }
             });
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss
index d1109b388..dbf98a5e9 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.scss
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss
@@ -106,6 +106,15 @@
         border-width: 1px;
     }
 }
+.formattedTextBox-inner-rounded-selected,
+.formattedTextBox-inner-selected {
+    .ProseMirror {
+        padding:10px;
+    }
+    .ProseMirror:hover {
+        background: unset;
+    }
+}
 
 // .menuicon {
 //     display: inline-block;
@@ -332,15 +341,6 @@ footnote::after {
     .multi4:before { transition: 0.5s;counter-increment: multi4; display: inline-block; vertical-align: top; margin-left: -4.2em;  width: 4.2em;    content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) "."counter(multi4, lower-roman) ". "; }
 }
 
-.formattedTextBox-inner-rounded-selected,
-.formattedTextBox-inner-selected {
-    .ProseMirror {
-        padding:10px;
-    }
-    .ProseMirror:hover {
-        background: unset;
-    }
-}
 
 @media only screen and (max-width: 1000px) {
     @import "../../globalCssVariables";
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 12fc690c8..1148087c6 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -557,11 +557,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
 
     sidebarDown = (e: React.PointerEvent) => {
         setupMoveUpEvents(this, e, this.sidebarMove, emptyFunction,
-            action(() => {
+            () => setTimeout(action(() => {
                 const prevWidth = this.sidebarWidth();
                 this.layoutDoc._showSidebar = ((this.layoutDoc._sidebarWidthPercent = StrCast(this.layoutDoc._sidebarWidthPercent, "0%") === "0%" ? "50%" : "0%")) !== "0%";
                 this.layoutDoc._width = this.layoutDoc._showSidebar ? NumCast(this.layoutDoc._width) * 2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth);
-            }));
+            })), false);
     }
     sidebarMove = (e: PointerEvent, down: number[], delta: number[]) => {
         const bounds = this.CurrentDiv.getBoundingClientRect();
@@ -1524,6 +1524,25 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         }
     }
 
+    @computed get audioHandle() {
+        return !this.layoutDoc._showAudio ? (null) :
+            <div className="formattedTextBox-dictation" onClick={action(e => this._recording = !this._recording)} >
+                <FontAwesomeIcon className="formattedTextBox-audioFont" style={{ color: this._recording ? "red" : "blue", transitionDelay: "0.6s", opacity: this._recording ? 1 : 0.25, }} icon={"microphone"} size="sm" />
+            </div>;
+    }
+
+    @computed get sidebarHandle() {
+        const annotated = DocListCast(this.dataDoc[this.annotationKey]).length;
+        return !this.props.isSelected() && !(annotated && !this.sidebarWidth()) ? (null) :
+            <div className="formattedTextBox-sidebar-handle"
+                style={{ left: `max(0px, calc(100% - ${this.sidebarWidthPercent} ${this.sidebarWidth() ? "- 5px" : "- 10px"}))`, background: annotated ? "lightBlue" : undefined }}
+                onPointerDown={this.sidebarDown}
+                onClick={e => {
+                    console.log(e);
+                }}
+            />;
+    }
+
     @computed get sidebarCollection() {
         const fitToBox = this.props.Document._fitToBox;
         return !this.layoutDoc._showSidebar || this.sidebarWidthPercent === "0%" ? (null) :
@@ -1531,6 +1550,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
                     PanelHeight={this.props.PanelHeight}
                     PanelWidth={this.sidebarWidth}
+                    xMargin={0}
                     scaleField={this.annotationKey + "-scale"}
                     annotationsKey={this.annotationKey}
                     isAnnotationOverlay={true}
@@ -1565,8 +1585,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         selected && setTimeout(() => this._editorView && RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this.props)); // need to make sure that we update a text box that is selected after updating the one that was deselected
         if (!selected && FormattedTextBoxComment.textBox === this) { FormattedTextBoxComment.Hide(); }
         const minimal = this.props.ignoreAutoHeight;
-        const selPad = (selected && !this.layoutDoc._singleLine) || minimal ? -10 : 0;
-        const selclass = selected && !this.layoutDoc._singleLine ? "-selected" : "";
+        const margins = NumCast(this.layoutDoc._yMargin, this.props.yMargin || 0);
+        const selPad = Math.min(margins, 10);
+        const padding = Math.max(margins + ((selected && !this.layoutDoc._singleLine) || minimal ? -selPad : 0), 0);
+        const selclass = selected && !this.layoutDoc._singleLine && margins >= 10 ? "-selected" : "";
         return (
             <div className={"formattedTextBox-cont"} ref={this._boxRef}
                 style={{
@@ -1614,18 +1636,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                         <div className={minimal ? "formattedTextBox-minimal" : `formattedTextBox-inner${rounded}${selclass}`} ref={this.createDropTarget}
                             style={{
                                 overflow: this.layoutDoc._singleLine ? "hidden" : undefined,
-                                padding: this.layoutDoc._textBoxPadding ? StrCast(this.layoutDoc._textBoxPadding) :
-                                    `${Math.max(0, NumCast(this.layoutDoc._yMargin, this.props.yMargin || 0) + selPad)}px  ${NumCast(this.layoutDoc._xMargin, this.props.xMargin || 0) + selPad}px`,
+                                padding: this.layoutDoc._textBoxPadding ? StrCast(this.layoutDoc._textBoxPadding) : `${padding}px`,
                                 pointerEvents: !active ? ((this.layoutDoc.isLinkButton || this.props.onClick) ? "none" : undefined) : undefined
                             }}
                         />
                     </div>
                     {this.sidebarCollection}
-                    {selected ? <div className="formattedTextBox-sidebar-handle" style={{ left: `max(0px, calc(100% - ${this.sidebarWidthPercent} - 5px))`, background: DocListCast(this.dataDoc[this.annotationKey]).length ? "lightBlue" : undefined }} onPointerDown={this.sidebarDown} /> : (null)}
-                    {!this.layoutDoc._showAudio ? (null) :
-                        <div className="formattedTextBox-dictation" onClick={action(e => this._recording = !this._recording)} >
-                            <FontAwesomeIcon className="formattedTextBox-audioFont" style={{ color: this._recording ? "red" : "blue", transitionDelay: "0.6s", opacity: this._recording ? 1 : 0.25, }} icon={"microphone"} size="sm" />
-                        </div>}
+                    {this.sidebarHandle}
+                    {this.audioHandle}
                 </div>
             </div>
         );
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index fb87da744..77dd40f2a 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -642,6 +642,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
                         e.annoDragData.linkDocument = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation");
                     }
                     annotationDoc.isLinkButton = true; // prevents link button fro showing up --- maybe not a good thing?
+                    annotationDoc.isPushpin = e.annoDragData?.dropDocument.annotationOn === this.props.Document;
                     e.annoDragData && e.annoDragData.linkDocument && e.annoDragData?.linkDropCallback?.({ linkDocument: e.annoDragData.linkDocument });
                 }
             });
@@ -733,7 +734,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
                 removeDocument={this.removeDocument}
                 moveDocument={this.moveDocument}
                 addDocument={this.addDocument}
-                docFilters={this.props.docRangeFilters}
+                docFilters={this.props.docFilters}
                 docRangeFilters={this.props.docRangeFilters}
                 CollectionView={undefined}
                 ScreenToLocalTransform={this.overlayTransform}
-- 
cgit v1.2.3-70-g09d2


From 7e5779c7404d92fdd64958d6240a1418a2ee57d7 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 29 Sep 2020 20:37:26 -0400
Subject: simplfiled ':' menu and fixed creating items to not assume a
 template.  add emptyNote.  fixed scrolling in stacking views broken in
 previous commit.  changed formattedTextBox to support stacking sidebar.

---
 src/client/documents/Documents.ts                  | 19 +++---
 src/client/util/CurrentUserUtils.ts                |  7 ++-
 .../views/collections/CollectionStackingView.tsx   | 36 ++++++-----
 .../CollectionStackingViewFieldColumn.tsx          | 31 +++++-----
 src/client/views/collections/TreeView.tsx          |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx | 69 +++++++++++++---------
 7 files changed, 97 insertions(+), 69 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index ad30e7d33..47fa7067d 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1,7 +1,8 @@
 import { runInAction } from "mobx";
 import { basename, extname } from "path";
 import { DateField } from "../../fields/DateField";
-import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym, AclAddonly } from "../../fields/Doc";
+import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../fields/Doc";
+import { Id } from "../../fields/FieldSymbols";
 import { HtmlField } from "../../fields/HtmlField";
 import { InkField } from "../../fields/InkField";
 import { List } from "../../fields/List";
@@ -11,6 +12,7 @@ import { SchemaHeaderField } from "../../fields/SchemaHeaderField";
 import { ComputedField, ScriptField } from "../../fields/ScriptField";
 import { Cast, NumCast, StrCast } from "../../fields/Types";
 import { AudioField, ImageField, PdfField, VideoField, WebField, YoutubeField } from "../../fields/URLField";
+import { SharingPermissions } from "../../fields/util";
 import { MessageStore } from "../../server/Message";
 import { Upload } from "../../server/SharedMediaTypes";
 import { OmitKeys, Utils } from "../../Utils";
@@ -33,6 +35,7 @@ import { AudioBox } from "../views/nodes/AudioBox";
 import { ColorBox } from "../views/nodes/ColorBox";
 import { ComparisonBox } from "../views/nodes/ComparisonBox";
 import { DocHolderBox } from "../views/nodes/DocHolderBox";
+import { FilterBox } from "../views/nodes/FilterBox";
 import { FontIconBox } from "../views/nodes/FontIconBox";
 import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox";
 import { ImageBox } from "../views/nodes/ImageBox";
@@ -50,9 +53,6 @@ import { PresElementBox } from "../views/presentationview/PresElementBox";
 import { SearchBox } from "../views/search/SearchBox";
 import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
 import { DocumentType } from "./DocumentTypes";
-import { FilterBox } from "../views/nodes/FilterBox";
-import { SharingPermissions } from "../../fields/util";
-import { SharingManager } from "../util/SharingManager";
 const path = require('path');
 
 const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", ""));
@@ -208,6 +208,8 @@ export interface DocumentOptions {
     treeViewOutlineMode?: boolean; // whether slide should function as a text outline
     treeViewLockExpandedView?: boolean; // whether the expanded view can be changed
     treeViewDefaultExpandedView?: string; // default expanded view
+    sidebarColor?: string;  // background color of text sidebar
+    sidebarViewType?: string; // collection type of text sidebar
     limitHeight?: number; // maximum height for newly created (eg, from pasting) text documents
     // [key: string]: Opt<Field>;
     pointerHack?: boolean; // for buttons, allows onClick handler to fire onPointerDown
@@ -1094,8 +1096,8 @@ export namespace DocUtils {
         return ctor ? ctor(path, options) : undefined;
     }
 
-    export function addDocumentCreatorMenuItems(docTextAdder: (d: Doc) => void, docAdder: (d: Doc) => void, x: number, y: number): void {
-        ContextMenu.Instance.addItem({
+    export function addDocumentCreatorMenuItems(docTextAdder: (d: Doc) => void, docAdder: (d: Doc) => void, x: number, y: number, simpleMenu: boolean = false): void {
+        !simpleMenu && ContextMenu.Instance.addItem({
             description: "Add Note ...",
             subitems: DocListCast((Doc.UserDoc()["template-notes"] as Doc).data).map((note, i) => ({
                 description: ":" + StrCast(note.title),
@@ -1114,14 +1116,15 @@ export namespace DocUtils {
         });
         ContextMenu.Instance.addItem({
             description: "Add Template Doc ...",
-            subitems: DocListCast(Cast(Doc.UserDoc().myItemCreators, Doc, null)?.data).map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)).filter(doc => doc).map((dragDoc, i) => ({
+            subitems: DocListCast(Cast(Doc.UserDoc().myItemCreators, Doc, null)?.data).filter(btnDoc => !btnDoc.hidden).map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)).filter(doc => doc && doc !== Doc.UserDoc().emptyPresentation).map((dragDoc, i) => ({
                 description: ":" + StrCast(dragDoc.title),
                 event: undoBatch((args: { x: number, y: number }) => {
-                    const newDoc = Doc.ApplyTemplate(dragDoc);
+                    const newDoc = Doc.copyDragFactory(dragDoc);
                     if (newDoc) {
                         newDoc.author = Doc.CurrentUserEmail;
                         newDoc.x = x;
                         newDoc.y = y;
+                        if (newDoc.type === DocumentType.RTF) FormattedTextBox.SelectOnLoad = newDoc[Id];
                         docAdder(newDoc);
                     }
                 }),
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 3e76b189a..7cc35d67a 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -422,9 +422,13 @@ export class CurrentUserUtils {
             doc.emptyScreenshot = Docs.Create.ScreenshotDocument("", { _width: 400, _height: 200, title: "screen snapshot", system: true, cloneFieldFilter: new List<string>(["system"]) });
         }
         if (doc.emptyAudio === undefined) {
-            doc.emptyAudio = Docs.Create.AudioDocument(nullAudio, { _width: 200, title: "ready to record audio", system: true, cloneFieldFilter: new List<string>(["system"]) });
+            doc.emptyAudio = Docs.Create.AudioDocument(nullAudio, { _width: 200, title: "audio recording", system: true, cloneFieldFilter: new List<string>(["system"]) });
             ((doc.emptyAudio as Doc).proto as Doc)["dragFactory-count"] = 0;
         }
+        if (doc.emptyNote === undefined) {
+            doc.emptyNote = Docs.Create.TextDocument("", { _width: 200, title: "text note", system: true, cloneFieldFilter: new List<string>(["system"]) });
+            ((doc.emptyNote as Doc).proto as Doc)["dragFactory-count"] = 0;
+        }
         if (doc.emptyImage === undefined) {
             doc.emptyImage = Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 250, _nativeWidth: 250, title: "an image of a cat", system: true });
         }
@@ -444,6 +448,7 @@ export class CurrentUserUtils {
             this.setupActiveMobileMenu(doc);
         }
         return [
+            { toolTip: "Tap to create a note in a new pane, drag for a note", title: "Note", icon: "sticky-note", click: 'openOnRight(copyDragFactory(this.clickFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyNote as Doc, noviceMode: true, clickFactory: doc.emptyNote as Doc, },
             { toolTip: "Tap to create a collection in a new pane, drag for a collection", title: "Col", icon: "folder", click: 'openOnRight(copyDragFactory(this.clickFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyCollection as Doc, noviceMode: true, clickFactory: doc.emptyPane as Doc, },
             { toolTip: "Tap to create a webpage in a new pane, drag for a webpage", title: "Web", icon: "globe-asia", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyWebpage as Doc, noviceMode: true },
             { toolTip: "Tap to create a progressive slide", title: "Slide", icon: "file", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptySlide as Doc, noviceMode: true },
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 423d39951..daaee67dc 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -33,8 +33,12 @@ const _global = (window /* browser */ || global /* node */) as any;
 type StackingDocument = makeInterface<[typeof collectionSchema, typeof documentSchema]>;
 const StackingDocument = makeInterface(collectionSchema, documentSchema);
 
+export type collectionStackingViewProps = {
+    chromeStatus?: string;
+};
+
 @observer
-export class CollectionStackingView extends CollectionSubView(StackingDocument) {
+export class CollectionStackingView extends CollectionSubView<StackingDocument, Partial<collectionStackingViewProps>>(StackingDocument) {
     _masonryGridRef: HTMLDivElement | null = null;
     _draggerRef = React.createRef<HTMLDivElement>();
     _pivotFieldDisposer?: IReactionDisposer;
@@ -44,15 +48,16 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
     @observable _heightMap = new Map<string, number>();
     @observable _cursor: CursorProperty = "grab";
     @observable _scroll = 0; // used to force the document decoration to update when scrolling
+    @computed get chromeStatus() { return this.props.chromeStatus || StrCast(this.layoutDoc._chromeStatus); }
     @computed get columnHeaders() { return Cast(this.layoutDoc._columnHeaders, listSpec(SchemaHeaderField)); }
     @computed get pivotField() { return StrCast(this.layoutDoc._pivotField); }
     @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc && !pair.layout.hidden).map(pair => pair.layout); }
     @computed get xMargin() { return NumCast(this.layoutDoc._xMargin, 2 * Math.min(this.gridGap, .05 * this.props.PanelWidth())); }
-    @computed get yMargin() { return Math.max(this.layoutDoc._showTitle && !this.layoutDoc._showTitleHover ? 30 : 0, NumCast(this.layoutDoc._yMargin, 5)); } // 2 * this.gridGap)); }
+    @computed get yMargin() { return Math.max(this.layoutDoc._showTitle && !this.layoutDoc._showTitleHover ? 30 : 0, this.props.yMargin || NumCast(this.layoutDoc._yMargin, 5)); } // 2 * this.gridGap)); }
     @computed get gridGap() { return NumCast(this.layoutDoc._gridGap, 10); }
     @computed get isStackingView() { return BoolCast(this.layoutDoc._columnsStack, true); }
     @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; }
-    @computed get showAddAGroup() { return (this.pivotField && (this.layoutDoc._chromeStatus !== 'view-mode' && this.layoutDoc._chromeStatus !== 'disabled')); }
+    @computed get showAddAGroup() { return (this.pivotField && (this.chromeStatus !== 'view-mode' && this.chromeStatus !== 'disabled')); }
     @computed get columnWidth() {
         return Math.min(this.props.PanelWidth() / this.props.ContentScaling() - 2 * this.xMargin,
             this.isStackingView ? Number.MAX_VALUE : this.layoutDoc._columnWidth === -1 ? this.props.PanelWidth() - 2 * this.xMargin : NumCast(this.layoutDoc._columnWidth, 250));
@@ -354,7 +359,8 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
                     const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
                     this.observer = new _global.ResizeObserver(action((entries: any) => {
                         if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
-                            Doc.Layout(doc)._height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))));
+                            const height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))));
+                            Doc.Layout(doc)._height = Math.max(height, NumCast(doc[this.props.fieldKey + "-height"]));
                         }
                     }));
                     this.observer.observe(ref);
@@ -406,7 +412,8 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
                     const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
                     this.observer = new _global.ResizeObserver(action((entries: any) => {
                         if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
-                            Doc.Layout(doc)._height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0);
+                            const height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0);
+                            Doc.Layout(doc)._height = Math.max(height, NumCast(doc[this.props.fieldKey + "-height"]));
                         }
                     }));
                     this.observer.observe(ref);
@@ -444,10 +451,6 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
         return firstEntry[0].heading > secondEntry[0].heading ? 1 : -1;
     }
 
-    onToggle = (checked: Boolean) => {
-        this.layoutDoc._chromeStatus = checked ? "collapsed" : "view-mode";
-    }
-
     onContextMenu = (e: React.MouseEvent): void => {
         // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout
         if (!e.isPropagationStopped()) {
@@ -504,13 +507,14 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
                             style={{ width: !this.isStackingView ? "100%" : this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}>
                             <EditableView {...editableViewProps} />
                         </div>}
-                    {this.layoutDoc._chromeStatus !== 'disabled' && this.props.isSelected() ? <Switch
-                        onChange={this.onToggle}
-                        onClick={this.onToggle}
-                        defaultChecked={this.layoutDoc._chromeStatus !== 'view-mode'}
-                        checkedChildren="edit"
-                        unCheckedChildren="view"
-                    /> : null}
+                    {/* {this.chromeStatus === 'disabled' || !this.props.isSelected() ? (null) :
+                        <Switch
+                            onChange={this.onToggle}
+                            onClick={this.onToggle}
+                            defaultChecked={this.chromeStatus !== 'view-mode'}
+                            checkedChildren="edit"
+                            unCheckedChildren="view"
+                        />} */}
                 </div> </div>
         );
     }
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 44d264b36..1bc989e83 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -22,6 +22,8 @@ import { ContextMenuProps } from "../ContextMenuItem";
 import { EditableView } from "../EditableView";
 import { CollectionStackingView } from "./CollectionStackingView";
 import "./CollectionStackingView.scss";
+import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox";
+import { Id } from "../../../fields/FieldSymbols";
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -137,8 +139,9 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         const maxHeading = this.props.docList.reduce((maxHeading, doc) => NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0);
         const heading = maxHeading === 0 || this.props.docList.length === 0 ? 1 : maxHeading === 1 ? 2 : 3;
         newDoc.heading = heading;
-        this.props.parent.props.addDocument(newDoc);
-        return false;
+        FormattedTextBox.SelectOnLoad = newDoc[Id];
+        FormattedTextBox.SelectOnLoadChar = " ";
+        return this.props.parent.props.addDocument(newDoc);
     }
 
     @action
@@ -228,7 +231,10 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         const docItems: ContextMenuProps[] = [];
         const dataDoc = this.props.parent.props.DataDoc || this.props.parent.Document;
 
-        DocUtils.addDocumentCreatorMenuItems(this.props.parent.props.addDocument, this.props.parent.props.addDocument, x, y);
+        DocUtils.addDocumentCreatorMenuItems((doc) => {
+            FormattedTextBox.SelectOnLoad = doc[Id];
+            return this.props.parent.props.addDocument(doc);
+        }, this.props.parent.props.addDocument, x, y, true);
 
         Array.from(Object.keys(Doc.GetProto(dataDoc))).filter(fieldKey => dataDoc[fieldKey] instanceof RichTextField || dataDoc[fieldKey] instanceof ImageField || typeof (dataDoc[fieldKey]) === "string").map(fieldKey =>
             docItems.push({
@@ -256,13 +262,8 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
                     }
                 }, icon: "compress-arrows-alt"
             }));
-        layoutItems.push({ description: ":freeform", event: () => this.props.parent.props.addDocument(Docs.Create.FreeformDocument([], { _width: 200, _height: 200 })), icon: "compress-arrows-alt" });
-        layoutItems.push({ description: ":carousel", event: () => this.props.parent.props.addDocument(Docs.Create.CarouselDocument([], { _width: 400, _height: 200 })), icon: "compress-arrows-alt" });
-        layoutItems.push({ description: ":columns", event: () => this.props.parent.props.addDocument(Docs.Create.MulticolumnDocument([], { _width: 200, _height: 200 })), icon: "compress-arrows-alt" });
-        layoutItems.push({ description: ":image", event: () => this.props.parent.props.addDocument(Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { _width: 200, _height: 200 })), icon: "compress-arrows-alt" });
-
-        ContextMenu.Instance.addItem({ description: "Doc Fields ...", subitems: docItems, icon: "eye" });
-        ContextMenu.Instance.addItem({ description: "Containers ...", subitems: layoutItems, icon: "eye" });
+        !Doc.UserDoc().noviceMode && ContextMenu.Instance.addItem({ description: "Doc Fields ...", subitems: docItems, icon: "eye" });
+        !Doc.UserDoc().noviceMode && ContextMenu.Instance.addItem({ description: "Containers ...", subitems: layoutItems, icon: "eye" });
         ContextMenu.Instance.setDefaultItem("::", (name: string): void => {
             Doc.GetProto(this.props.parent.props.Document)[name] = "";
             const created = Docs.Create.TextDocument("", { title: name, _width: 250, _autoHeight: true });
@@ -285,7 +286,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         const heading = this._heading;
         const style = this.props.parent;
         const singleColumn = style.isStackingView;
-        const columnYMargin = this.props.headingObject ? 0 : NumCast(this.props.parent.props.Document._yMargin, 5);
+        const columnYMargin = this.props.headingObject ? 0 : NumCast(this.props.parent.yMargin, 5);
         const uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx);
         const evContents = heading ? heading : this.props?.type === "number" ? "0" : `NO ${key.toUpperCase()} VALUE`;
         const headerEditableViewProps = {
@@ -306,10 +307,10 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         const headingView = this.props.headingObject ?
             <div key={heading} className="collectionStackingView-sectionHeader" ref={this._headerRef}
                 style={{
-                    marginTop: NumCast(this.props.parent.props.Document._yMargin, 5),
+                    marginTop: NumCast(this.props.parent.yMargin, 5),
                     width: (style.columnWidth) /
                         ((uniqueHeadings.length +
-                            ((this.props.parent.props.Document._chromeStatus !== 'view-mode' && this.props.parent.props.Document._chromeStatus !== 'disabled') ? 1 : 0)) || 1)
+                            ((this.props.parent.chromeStatus !== 'view-mode' && this.props.parent.chromeStatus !== 'disabled') ? 1 : 0)) || 1)
                 }}>
                 <div className={"collectionStackingView-collapseBar" + (this.props.headingObject.collapsed === true ? " active" : "")} onClick={this.collapseSection}></div>
                 {/* the default bucket (no key value) has a tooltip that describes what it is.
@@ -342,7 +343,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
                 </div>
             </div> : (null);
         for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth / style.numGroupColumns}px `;
-        const chromeStatus = this.props.parent.props.Document._chromeStatus;
+        const chromeStatus = this.props.parent.chromeStatus;
         const type = this.props.parent.props.Document.type;
         return <>
             {this.props.parent.Document._columnsHideIfEmpty ? (null) : headingView}
@@ -365,7 +366,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
                         </div>
                         {(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled' && type !== DocumentType.PRES) ?
                             <div key={`${heading}-add-document`} className="collectionStackingView-addDocumentButton"
-                                style={{ width: style.columnWidth / style.numGroupColumns, marginBottom: 70 }}>
+                                style={{ width: style.columnWidth / style.numGroupColumns, marginBottom: 10 }}>
                                 <EditableView {...newEditableViewProps} menuCallback={this.menuCallback} />
                             </div> : null}
                     </div>
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 06c35de03..1dfa5615a 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -185,7 +185,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     }
 
     public static makeTextBullet() {
-        const bullet = Docs.Create.TextDocument("-text-", { title: "-title-", forceActive: true, _viewType: CollectionViewType.Tree, hideLinkButton: true, _showSidebar: true, treeViewOutlineMode: true, x: 0, y: 0, _xMargin: 0, _yMargin: 0, _autoHeight: true, _singleLine: true, _backgroundColor: "transparent", _width: 1000, _height: 10 });
+        const bullet = Docs.Create.TextDocument("-text-", { title: "-title-", "sidebarColor": "transparent", "sidebarViewType": CollectionViewType.Freeform, forceActive: true, _viewType: CollectionViewType.Tree, hideLinkButton: true, _showSidebar: true, treeViewOutlineMode: true, x: 0, y: 0, _xMargin: 0, _yMargin: 0, _autoHeight: true, _singleLine: true, _backgroundColor: "transparent", _width: 1000, _height: 10 });
         Doc.GetProto(bullet).layout = CollectionView.LayoutString("data");
         Doc.GetProto(bullet).title = ComputedField.MakeFunction('self.text?.Text');
         Doc.GetProto(bullet).data = new List<Doc>([]);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index a3f76839d..89e0450d7 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1627,7 +1627,7 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
         return <div className={freeformclass}
             onScroll={e => {
                 const target = e.target as any;
-                if (getComputedStyle(target.parentElement)?.overflow === "visible") {  // if collection is visible, then scrolling will mess things up since there are no scroll bars
+                if (getComputedStyle(target)?.overflow === "visible") {  // if collection is visible, then scrolling will mess things up since there are no scroll bars
                     target.scrollTop = target.scrollLeft = 0;
                 }
             }}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 1148087c6..93eb94854 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1,5 +1,5 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { isEqual } from "lodash";
+import { isEqual, max } from "lodash";
 import { action, computed, IReactionDisposer, Lambda, observable, reaction, runInAction, trace } from "mobx";
 import { observer } from "mobx-react";
 import { baseKeymap, selectAll } from "prosemirror-commands";
@@ -58,6 +58,8 @@ import "./FormattedTextBox.scss";
 import { FormattedTextBoxComment, formattedTextBoxCommentPlugin, findLinkMark } from './FormattedTextBoxComment';
 import React = require("react");
 import { DocumentManager } from '../../../util/DocumentManager';
+import { CollectionStackingView } from '../../collections/CollectionStackingView';
+import { CollectionViewType } from '../../collections/CollectionView';
 
 export interface FormattedTextBoxProps {
     makeLink?: () => Opt<Doc>;  // bcz: hack: notifies the text document when the container has made a link.  allows the text doc to react and setup a hyeprlink for any selected text
@@ -1166,7 +1168,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 const mark = schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) });
                 const curMarks = this._editorView.state.storedMarks ?? $from?.marksAcross(this._editorView.state.selection.$head) ?? [];
                 const storedMarks = [...curMarks.filter(m => m.type !== mark.type), mark];
-                this._editorView.dispatch(this._editorView.state.tr.setStoredMarks(storedMarks).insertText(FormattedTextBox.SelectOnLoadChar).setStoredMarks(storedMarks));
+                const tr = this._editorView.state.tr.setStoredMarks(storedMarks).insertText(FormattedTextBox.SelectOnLoadChar, this._editorView.state.doc.content.size - 1, this._editorView.state.doc.content.size).setStoredMarks(storedMarks);
+                this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size))));
                 FormattedTextBox.SelectOnLoadChar = "";
             } else if (curText?.Text) {
                 selectAll(this._editorView!.state, this._editorView?.dispatch);
@@ -1496,6 +1499,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     @action
     tryUpdateHeight(limitHeight?: number) {
         let scrollHeight = this.ProseRef?.scrollHeight || 0;
+        this.rootDoc[this.fieldKey + "-height"] = 0;
         if (this.props.renderDepth && this.layoutDoc._autoHeight && !this.props.ignoreAutoHeight && scrollHeight && !this.props.dontRegisterView) {  // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
             scrollHeight = scrollHeight * NumCast(this.layoutDoc._viewScale, 1);
             if (limitHeight && scrollHeight > limitHeight) {
@@ -1517,8 +1521,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 try {
                     const boxHeight = Number(getComputedStyle(this._boxRef.current!).height.replace("px", ""));
                     const outer = this.rootDoc[HeightSym]() - boxHeight - (this.props.ChromeHeight ? this.props.ChromeHeight() : 0);
-                    this.rootDoc._height = newHeight + Math.max(0, outer);
-                    this.layoutDoc._nativeHeight = nh ? scrollHeight : undefined;
+                    const finalHeight = newHeight + Math.max(0, outer);
+                    const maxsidebar = !this.sidebarWidth() ? 0 : Array.from(this._boxRef.current!.getElementsByClassName("collectionStackingViewFieldColumn")).reduce((prev, ele) => Math.max(prev, Number(getComputedStyle(ele).height.replace("px", ""))), 0);
+                    if (this.rootDoc._height !== finalHeight && finalHeight > maxsidebar) {
+                        this.rootDoc._height = finalHeight;
+                        this.layoutDoc._nativeHeight = nh ? scrollHeight : undefined;
+                    }
+                    this.rootDoc[this.fieldKey + "-height"] = finalHeight;
                 } catch (e) { console.log("Error in tryUpdateHeight"); }
             }
         }
@@ -1545,36 +1554,42 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
 
     @computed get sidebarCollection() {
         const fitToBox = this.props.Document._fitToBox;
+        const collectionProps = {
+            ...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit,
+            PanelHeight: this.props.PanelHeight,
+            PanelWidth: this.sidebarWidth,
+            xMargin: 0,
+            yMargin: 0,
+            chromeStatus: "enabled",
+            scaleField: this.annotationKey + "-scale",
+            annotationsKey: this.annotationKey,
+            isAnnotationOverlay: true,
+            fitToBox: fitToBox,
+            focus: this.props.focus,
+            isSelected: this.props.isSelected,
+            select: emptyFunction,
+            active: this.annotationsActive,
+            ContentScaling: returnOne,
+            whenActiveChanged: this.whenActiveChanged,
+            removeDocument: this.removeDocument,
+            moveDocument: this.moveDocument,
+            addDocument: this.addDocument,
+            CollectionView: undefined,
+            ScreenToLocalTransform: this.sidebarScreenToLocal,
+            renderDepth: this.props.renderDepth + 1,
+            ContainingCollectionDoc: this.props.ContainingCollectionDoc,
+        };
         return !this.layoutDoc._showSidebar || this.sidebarWidthPercent === "0%" ? (null) :
-            <div className={"formattedTextBox-sidebar" + (Doc.GetSelectedTool() !== InkTool.None ? "-inking" : "")} style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
-                <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
-                    PanelHeight={this.props.PanelHeight}
-                    PanelWidth={this.sidebarWidth}
-                    xMargin={0}
-                    scaleField={this.annotationKey + "-scale"}
-                    annotationsKey={this.annotationKey}
-                    isAnnotationOverlay={true}
-                    fitToBox={fitToBox}
-                    focus={this.props.focus}
-                    isSelected={this.props.isSelected}
-                    select={emptyFunction}
-                    active={this.annotationsActive}
-                    ContentScaling={returnOne}
-                    whenActiveChanged={this.whenActiveChanged}
-                    removeDocument={this.removeDocument}
-                    moveDocument={this.moveDocument}
-                    addDocument={this.addDocument}
-                    CollectionView={undefined}
-                    ScreenToLocalTransform={this.sidebarScreenToLocal}
-                    renderDepth={this.props.renderDepth + 1}
-                    ContainingCollectionDoc={this.props.ContainingCollectionDoc} />
+            <div className={"formattedTextBox-sidebar" + (Doc.GetSelectedTool() !== InkTool.None ? "-inking" : "")}
+                style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
+                {this.layoutDoc.sidebarViewType === CollectionViewType.Freeform ? <CollectionFreeFormView {...collectionProps} /> : <CollectionStackingView {...collectionProps} />}
             </div>;
     }
 
     @computed get sidebarWidthPercent() { return StrCast(this.layoutDoc._sidebarWidthPercent, "0%"); }
     sidebarWidth = () => Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth();
     sidebarScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth()) / this.props.ContentScaling(), 0);
-    @computed get sidebarColor() { return StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "transparent")); }
+    @computed get sidebarColor() { return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "#e4e4e4")); }
     render() {
         TraceMobx();
         const selected = this.props.isSelected();
-- 
cgit v1.2.3-70-g09d2

