From b292a055401af6236e0537cfad603016d77a535a Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 20 Jun 2022 13:40:07 -0400
Subject: a bunch of changes to make some userDoc() field accesses more
 typesafe by going through CurrentUserUtils.  Some normalization of
 naming/functionality in CurrentUserUtils

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

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index dddae4a34..277fcd59c 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -598,7 +598,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             <>
                 {buttonMenu || noviceExplainer ? <div className="documentButtonMenu">
                     {buttonMenu ? this.buttonMenu : null}
-                    {Doc.UserDoc().noviceMode && noviceExplainer ?
+                    {Doc.noviceMode && noviceExplainer ?
                         <div className="documentExplanation">
                             {noviceExplainer}
                         </div>
-- 
cgit v1.2.3-70-g09d2


From 0dd3bbfc119d48bd2c32f8e55b7051e3ddc530c3 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 21 Jun 2022 14:40:04 -0400
Subject: restored experimental templates.  fixed (enabled) pointer events on
 nested column/row views when container is active.  got rid of
 freezeDimensions which wasn't needed and introduced artifacts for views that
 set it (timeView, GridView)

---
 src/client/documents/Documents.ts                  |  1 +
 src/client/util/CurrentUserUtils.ts                | 74 +++++++++++-----------
 src/client/util/DragManager.ts                     | 11 ++--
 src/client/views/PropertiesView.tsx                |  1 -
 .../views/collections/CollectionStackingView.tsx   |  1 -
 .../views/collections/CollectionTimeView.tsx       |  5 +-
 src/client/views/collections/CollectionView.tsx    |  1 -
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  1 -
 .../collectionGrid/CollectionGridView.tsx          |  1 -
 .../CollectionMulticolumnView.tsx                  | 14 ++--
 .../CollectionMultirowView.tsx                     |  6 +-
 .../collectionSchema/CollectionSchemaView.tsx      |  1 -
 .../collections/collectionSchema/SchemaTable.tsx   |  1 -
 src/client/views/nodes/DocumentContentsView.tsx    |  1 -
 src/client/views/nodes/DocumentView.tsx            |  7 +-
 src/client/views/nodes/button/FontIconBox.tsx      |  4 +-
 16 files changed, 61 insertions(+), 69 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 73b756a8d..59391d150 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -194,6 +194,7 @@ export class DocumentOptions {
     childLimitHeight?: number; // whether to limit the height of collection children.  0 - means  height can be no bigger than width
     childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox layout in tree view)
     childLayoutString?: string; // template string for collection to use to render its children
+    childDocumentsActive?: boolean; // whether child documents are active when parent is document active
     childDontRegisterViews?: boolean;
     childHideLinkButton?: boolean; // hide link buttons on all children
     childContextMenuFilters?: List<ScriptField>;
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 9b5fc5b98..e80fe6776 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1,6 +1,6 @@
 import { computed, observable, reaction } from "mobx";
 import * as rp from 'request-promise';
-import { DataSym, Doc, DocListCast, DocListCastAsync, StrListCast } from "../../fields/Doc";
+import { DataSym, Doc, DocListCast, DocListCastAsync, Opt, StrListCast } from "../../fields/Doc";
 import { Id } from "../../fields/FieldSymbols";
 import { InkTool } from "../../fields/InkField";
 import { List } from "../../fields/List";
@@ -109,40 +109,43 @@ export class CurrentUserUtils {
     }
 
     // initializes experimental advanced template views - slideView,  headerView
-    static setupExperimentalTemplateButtons(doc: Doc, field="template-experimental-buttons") {
-        const tempDocs = DocCast(doc[field]);
-        const requiredTypeNameFields:{opts:DocumentOptions, template:() => Doc}[] = [
+    static setupExperimentalTemplateButtons(doc: Doc, tempDocs?:Doc) {
+        const requiredTypeNameFields:{btnOpts:DocumentOptions, templateOpts:DocumentOptions, template:(opts:DocumentOptions) => Doc}[] = [
             {
-                opts:{type: "slide", icon: "address-card"}, template: () => Docs.Create.MultirowDocument(
+                btnOpts: { title: "slide", icon: "address-card" }, 
+                templateOpts: { _width: 400, _height: 300, title: "slideView", childDocumentsActive: true, _xMargin: 3, _yMargin: 3, system: true }, 
+                template: (opts:DocumentOptions) => Docs.Create.MultirowDocument(
                     [
-                        Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }),
-                        Docs.Create.TextDocument("", { title: "text", _height: 100, system: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) })
-                    ],
-                    { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, system: true }
-                )
+                        Docs.Create.MulticolumnDocument([], { title: "data", _height: 200,  system: true }),
+                        Docs.Create.TextDocument("", { title: "text", _fitWidth:true,  _height: 100, system: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) })
+                    ], opts)
             },
             {
-                opts:{type: "mobile", icon: "mobile"}, template: () => this.mobileButton({ title: "NEW MOBILE BUTTON", onClick: undefined, },
-                    [this.createToolButton({ ignoreClick: true, icon: "mobile", backgroundColor: "transparent" }),
-                    this.mobileTextContainer({},
-                        [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")])
-                    ]
+                btnOpts: { title: "mobile", icon: "mobile" }, 
+                templateOpts: { title: "NEW MOBILE BUTTON", onClick: undefined, }, 
+                template: (opts:DocumentOptions) => this.mobileButton(opts,
+                        [this.createToolButton({ ignoreClick: true, icon: "mobile", backgroundColor: "transparent" }),
+                        this.mobileTextContainer({},
+                            [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")])
+                        ]
                 )
             },
         ];
-        const requiredTypes = requiredTypeNameFields.map(({ opts, template }) => {
-            const docType =  DocListCast(tempDocs?.data)?.find(doc => doc.title === opts.type);
-            const reqdOpts = {
-                dragFactory: template(),
-                title: opts.type,
-                icon: opts.icon
+        const requiredTypes = requiredTypeNameFields.map(({ btnOpts, template, templateOpts }) => {
+            const tempBtn =  DocListCast(tempDocs?.data)?.find(doc => doc.title === btnOpts.title);
+            const reqdScripts = { onDragStart: '{ return copyDragFactory(this.dragFactory); }' };
+            const assignBtnAndTempOpts = (templateBtn:Opt<Doc>, btnOpts:DocumentOptions, templateOptions:DocumentOptions) => {
+                if (templateBtn) {
+                    this.AssignOpts(templateBtn,btnOpts);
+                    this.AssignOpts(DocCast(templateBtn.dragFactory), templateOptions) ?? (templateBtn.dragFactory = template(templateOpts));
+                }
+                return templateBtn;
             };
-            const reqdScripts = {onDragStart: 'copyDragFactory(this.dragFactory)'};
             const makeTemp = (doc:Doc) => {
                 doc.isTemplateDoc = makeTemplate(doc);
                 return doc;
             }
-            return this.AssignScripts(!docType ? makeTemp(CurrentUserUtils.createToolButton(reqdOpts)) : this.AssignOpts(docType, reqdOpts)!, reqdScripts)!;
+            return this.AssignScripts(assignBtnAndTempOpts(tempBtn, btnOpts, templateOpts) ?? CurrentUserUtils.createToolButton( {...btnOpts, dragFactory: makeTemp(template(templateOpts))}), reqdScripts);
         });
 
         const reqdOpts = {
@@ -150,12 +153,9 @@ export class CurrentUserUtils {
             _stayInCollection: true, _hideContextMenu: true, _forceActive: true, system: true,
             _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true,
         };
-        const reqdScripts = {dropConverter : "convertToButtons(dragData)"};
-        const reqdFuncs = {hidden: "IsNoviceMode()"}
-        return this.AssignScripts(!tempDocs ? 
-                (doc[field] = Docs.Create.MasonryDocument(requiredTypes, reqdOpts)) :
-                this.AssignOpts(tempDocs, reqdOpts, requiredTypes)!, 
-            reqdScripts, reqdFuncs);
+        const reqdScripts = { dropConverter : "convertToButtons(dragData)" };
+        const reqdFuncs = { hidden: "IsNoviceMode()" };
+        return this.AssignScripts(this.AssignOpts(tempDocs, reqdOpts, requiredTypes) ?? Docs.Create.MasonryDocument(requiredTypes, reqdOpts), reqdScripts, reqdFuncs);
     }
 
     /// Initializes templates that can be applied to notes
@@ -525,12 +525,12 @@ export class CurrentUserUtils {
     static setupToolsBtnPanel(doc: Doc, field:string) {
         const myTools = DocCast(doc[field]);
         const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc, DocListCast(myTools?.data)?.length ? DocListCast(myTools.data)[0]:undefined);
-        //const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc);
+        const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc,DocListCast(myTools?.data)?.length > 1 ? DocListCast(myTools.data)[1]:undefined);
         const reqdToolOps:DocumentOptions = {
             title: "My Tools", system: true, ignoreClick: true, boxShadow: "0 0",
             _showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, 
         };
-        this.AssignOpts(myTools, reqdToolOps, [creatorBtns, /*templateBtns*/]) ?? (doc[field] = Docs.Create.StackingDocument([creatorBtns, /*templateBtns*/], reqdToolOps));
+        this.AssignOpts(myTools, reqdToolOps, [creatorBtns, templateBtns]) ?? (doc[field] = Docs.Create.StackingDocument([creatorBtns, templateBtns], reqdToolOps));
     }
 
     /// initializes the left sidebar dashboard pane
@@ -749,7 +749,7 @@ export class CurrentUserUtils {
     }
 
     static schemaTools():Button[] {
-        return [{ title: "Show preview", toolTip: "Show preview of selected document", btnType: ButtonType.ToggleButton, buttonText: "Show Preview", icon: "eye", scripts:{onClick:'toggleSchemaPreview(_readOnly_)'}, }];
+        return [{ title: "Show preview", toolTip: "Show preview of selected document", btnType: ButtonType.ToggleButton, buttonText: "Show Preview", icon: "eye", scripts:{ onClick: '{return toggleSchemaPreview(_readOnly_);}'}, }];
     }
 
     static webTools() {
@@ -774,9 +774,9 @@ export class CurrentUserUtils {
             }, // Always show
             { title: "Back", toolTip: "Prev Animation Frame", width: 20, btnType: ButtonType.ClickButton,icon: "chevron-left",  scripts:{onClick: 'prevKeyFrame(_readOnly_)'}, funcs: {hidden: 'IsNoviceMode()'} },
             { title: "Fwd", toolTip: "Next Animation Frame", width: 20, btnType: ButtonType.ClickButton, icon: "chevron-right", scripts:{onClick: 'nextKeyFrame(_readOnly_)'}, funcs: {hidden: 'IsNoviceMode()'}},
-            { title: "Fill", toolTip: "Background Fill Color", width: 20, btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", scripts: { script: "setBackgroundColor(value, _readOnly_)"}, funcs:{ hidden: 'selectedDocumentType()' }}, // Only when a document is selected
-            { title: "Header", toolTip: "Header Color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "heading", scripts: {script: "setHeaderColor(value, _readOnly_)"}, funcs : {hidden: 'selectedDocumentType()'} },
-            { title: "Overlay", toolTip: "Overlay", btnType: ButtonType.ToggleButton, icon: "layer-group", scripts: {onClick : 'toggleOverlay(_readOnly_)'}, funcs: {hidden: 'selectedDocumentType(undefined, "freeform", true)'} }, // Only when floating document is selected in freeform
+            { title: "Fill", toolTip: "Background Fill Color", width: 20, btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", scripts: { script: "setBackgroundColor(value, _readOnly_)"}, funcs:{ hidden: '!selectedDocumentType()' }}, // Only when a document is selected
+            { title: "Header", toolTip: "Header Color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "heading", scripts: {script: "setHeaderColor(value, _readOnly_)"}, funcs : {hidden: '!selectedDocumentType()'} },
+            { title: "Overlay", toolTip: "Overlay", btnType: ButtonType.ToggleButton, icon: "layer-group", scripts: {onClick : 'toggleOverlay(_readOnly_)'}, funcs: {hidden: '!selectedDocumentType(undefined, "freeform", true)'} }, // Only when floating document is selected in freeform
             // { title: "Alias", btnType: ButtonType.ClickButton, icon: "copy", hidden: 'selectedDocumentType()' }, // Only when a document is selected 
             { title: "Text", icon: "text",  subMenu: CurrentUserUtils.textTools(), funcs: { linearViewIsExpanded: `selectedDocumentType("${DocumentType.RTF}")`} }, // Always available
             { title: "Ink", icon: "ink", subMenu: CurrentUserUtils.inkTools(), funcs: { linearViewIsExpanded: `selectedDocumentType("${DocumentType.INK}")`} }, // Always available
@@ -983,7 +983,6 @@ export class CurrentUserUtils {
         doc.savedFilters ?? (doc.savedFilters = new List<Doc>());
         doc.filterDocCount = 0;
         doc.freezeChildren = "remove|add";
-        doc.myHeaderBar ?? (doc.myHeaderBar = Docs.Create.MulticolumnDocument([], { title: "header bar", system: true })); // drop down panel at top of dashboard for stashing documents
         await this.setupLinkDocs(doc, linkDatabaseId);
         await this.setupSharedDocs(doc, sharingDocumentId);  // sets up the right sidebar collection for mobile upload documents and sharing
         this.setupDefaultIconTemplates(doc);  // creates a set of icon templates triggered by the document deoration icon
@@ -995,7 +994,8 @@ export class CurrentUserUtils {
         this.setupLeftSidebarMenu(doc); // the left-side column of buttons that open their contents in a flyout panel on the left
         this.setupDocTemplates(doc); // sets up the template menu of templates
         doc.globalScriptDatabase ?? ( doc.globalScriptDatabase = Docs.Prototypes.MainScriptDocument());
-
+        doc.myHeaderBar ?? (doc.myHeaderBar = Docs.Create.MulticolumnDocument([], { title: "header bar", system: true })); // drop down panel at top of dashboard for stashing documents
+        
         setTimeout(() => DocServer.UPDATE_SERVER_CACHE(), 2500);
         doc.fieldInfos = await Docs.setupFieldInfos();
         if (doc.activeDashboard instanceof Doc) {
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 2b62945af..09b463c2f 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -223,10 +223,13 @@ export namespace DragManager {
             if (docDragData && !docDragData.droppedDocuments.length) {
                 docDragData.dropAction = dragData.userDropAction || dragData.dropAction;
                 docDragData.droppedDocuments =
-                    await Promise.all(dragData.draggedDocuments.map(async d => !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) :
-                        docDragData.dropAction === "alias" ? Doc.MakeAlias(d) :
-                            docDragData.dropAction === "proto" ? Doc.GetProto(d) :
-                                docDragData.dropAction === "copy" ? (await Doc.MakeClone(d)).clone : d));
+                    await Promise.all(dragData.draggedDocuments.map(async d => 
+                        !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? 
+                        addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) :
+                            docDragData.dropAction === "alias" ? Doc.MakeAlias(d) :
+                                docDragData.dropAction === "proto" ? Doc.GetProto(d) :
+                                    docDragData.dropAction === "copy" ? 
+                                        (await Doc.MakeClone(d)).clone : d));
                 !["same", "proto"].includes(docDragData.dropAction as any) && docDragData.droppedDocuments.forEach((drop: Doc, i: number) => {
                     const dragProps = Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec("string"), []);
                     const remProps = (dragData?.removeDropProperties || []).concat(Array.from(dragProps));
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 90c86fa18..faab2ed26 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -304,7 +304,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     rootSelected={returnFalse}
                     styleProvider={DefaultStyleProvider}
                     docViewPath={returnEmptyDoclist}
-                    freezeDimensions={true}
                     dontCenter={"y"}
                     isDocumentActive={returnFalse}
                     isContentActive={emptyFunction}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 277fcd59c..684c919bd 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -250,7 +250,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             isDocumentActive={this.isContentActive}
             LayoutTemplate={this.props.childLayoutTemplate}
             LayoutTemplateString={this.props.childLayoutString}
-            freezeDimensions={this.props.childFreezeDimensions}
             NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || doc._fitWidth && !Doc.NativeWidth(doc) ? width : undefined}  // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
             NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || doc._fitWidth && !Doc.NativeHeight(doc) ? height : undefined}
             dontCenter={this.props.childIgnoreNativeSize ? "xy" : undefined}
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 7573b938a..3dd9d2d84 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -59,7 +59,7 @@ export class CollectionTimeView extends CollectionSubView() {
         //const detailView = (await DocCastAsync(this.props.Document.childClickedOpenTemplateView)) || DocUtils.findTemplate("detailView", StrCast(this.rootDoc.type), "");
         ///const childText = "const alias = getAlias(self); switchView(alias, detailView); alias.dropAction='alias'; alias.removeDropProperties=new List<string>(['dropAction']); useRightSplit(alias, shiftKey); ";
         runInAction(() => {
-            this._childClickedScript = ScriptField.MakeScript("openInLightbox(self, shiftKey)", { this: Doc.name, shiftKey: "boolean" });//, { detailView: detailView! });
+            this._childClickedScript = ScriptField.MakeScript("openInLightbox(self)", { this: Doc.name });
             this._viewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" });
         });
     }
@@ -138,8 +138,7 @@ export class CollectionTimeView extends CollectionSubView() {
                 fitContentsToBox={returnTrue}
                 childClickScript={this._childClickedScript}
                 viewDefDivClick={this._viewDefDivClick}
-                childFreezeDimensions={true}
-                dontScaleFilter={this.dontScaleFilter}
+                //dontScaleFilter={this.dontScaleFilter}
                 layoutEngine={this.layoutEngine} />
         </div>;
     }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 63616263e..b432104a1 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -75,7 +75,6 @@ export interface CollectionViewProps extends FieldViewProps {
     childHideResizeHandles?: () => boolean;
     childLayoutTemplate?: () => (Doc | undefined);// specify a layout Doc template to use for children of the collection
     childLayoutString?: string;
-    childFreezeDimensions?: boolean; // used by TimeView to coerce documents to treat their width height as their native width/height
     childIgnoreNativeSize?: boolean;
     childClickScript?: ScriptField;
     childDoubleClickScript?: ScriptField;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 99eec7892..542b1fce1 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1265,7 +1265,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             styleProvider={this.getClusterColor}
             dataProvider={this.childDataProvider}
             sizeProvider={this.childSizeProvider}
-            freezeDimensions={BoolCast(this.props.Document.childFreezeDimensions, this.props.childFreezeDimensions)}
             dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             bringToFront={this.bringToFront}
             showTitle={this.props.childShowTitle}
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index da102fe18..4e4c33446 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -162,7 +162,6 @@ export class CollectionGridView extends CollectionSubView() {
             DataDoc={layout.resolvedDataDoc as Doc}
             PanelWidth={width}
             PanelHeight={height}
-            freezeDimensions={true}
             ScreenToLocalTransform={dxf}
             onClick={this.onChildClickHandler}
             renderDepth={this.props.renderDepth + 1}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index b7ba94940..777ef464f 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -6,6 +6,7 @@ import { List } from '../../../../fields/List';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
 import { returnFalse } from '../../../../Utils';
 import { DragManager, dropActionType } from '../../../util/DragManager';
+import { SnappingManager } from '../../../util/SnappingManager';
 import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
 import { DocumentView } from '../../nodes/DocumentView';
@@ -242,7 +243,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
         return this.props.addDocTab(doc, where);
     }
     isContentActive = () => this.props.isSelected() || this.props.isContentActive();
-    isChildContentActive = () => this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false;
+    isChildContentActive = () => ((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false;
     getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => {
         return <DocumentView
             Document={layout}
@@ -251,13 +252,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
             docViewPath={this.props.docViewPath}
             LayoutTemplate={this.props.childLayoutTemplate}
             LayoutTemplateString={this.props.childLayoutString}
-            freezeDimensions={this.props.childFreezeDimensions}
             renderDepth={this.props.renderDepth + 1}
-            isContentActive={this.isChildContentActive}
-            isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
-            hideResizeHandles={this.props.childHideResizeHandles?.()}
-            hideDecorationTitle={this.props.childHideDecorationTitle?.()}
-            fitContentsToBox={this.props.fitContentsToBox}
             PanelWidth={width}
             PanelHeight={height}
             rootSelected={this.rootSelected}
@@ -266,6 +261,11 @@ export class CollectionMulticolumnView extends CollectionSubView() {
             onDoubleClick={this.onChildDoubleClickHandler}
             suppressSetHeight={true}
             ScreenToLocalTransform={dxf}
+            isContentActive={this.isChildContentActive}
+            isDocumentActive={this.props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
+            hideResizeHandles={this.props.childHideResizeHandles?.()}
+            hideDecorationTitle={this.props.childHideDecorationTitle?.()}
+            fitContentsToBox={this.props.fitContentsToBox}
             focus={this.props.focus}
             docFilters={this.childDocFilters}
             docRangeFilters={this.childDocRangeFilters}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 338639a83..08385bcb5 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -6,6 +6,7 @@ import { List } from '../../../../fields/List';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
 import { returnFalse } from '../../../../Utils';
 import { DragManager, dropActionType } from '../../../util/DragManager';
+import { SnappingManager } from '../../../util/SnappingManager';
 import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
 import { DocumentView } from '../../nodes/DocumentView';
@@ -242,7 +243,7 @@ export class CollectionMultirowView extends CollectionSubView() {
         return this.props.addDocTab(doc, where);
     }
     isContentActive = () => this.props.isSelected() || this.props.isContentActive();
-    isChildContentActive = () => this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false;
+    isChildContentActive = () => ((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false;
     getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => {
         return <DocumentView
             Document={layout}
@@ -251,7 +252,6 @@ export class CollectionMultirowView extends CollectionSubView() {
             docViewPath={this.props.docViewPath}
             LayoutTemplate={this.props.childLayoutTemplate}
             LayoutTemplateString={this.props.childLayoutString}
-            freezeDimensions={this.props.childFreezeDimensions}
             renderDepth={this.props.renderDepth + 1}
             PanelWidth={width}
             PanelHeight={height}
@@ -261,7 +261,7 @@ export class CollectionMultirowView extends CollectionSubView() {
             onDoubleClick={this.onChildDoubleClickHandler}
             ScreenToLocalTransform={dxf}
             isContentActive={this.isChildContentActive}
-            isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
+            isDocumentActive={this.props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
             hideResizeHandles={this.props.childHideResizeHandles?.()}
             hideDecorationTitle={this.props.childHideDecorationTitle?.()}
             fitContentsToBox={this.props.fitContentsToBox}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index f45068b6a..9eba788a9 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -403,7 +403,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                     Document={this.previewDocument}
                     DataDoc={undefined}
                     fitContentsToBox={returnTrue}
-                    freezeDimensions={true}
                     dontCenter={"y"}
                     focus={DocUtils.DefaultFocus}
                     renderDepth={this.props.renderDepth}
diff --git a/src/client/views/collections/collectionSchema/SchemaTable.tsx b/src/client/views/collections/collectionSchema/SchemaTable.tsx
index bea5b3be6..43266a571 100644
--- a/src/client/views/collections/collectionSchema/SchemaTable.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTable.tsx
@@ -574,7 +574,6 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                         DataDoc={this._showDataDoc}
                         styleProvider={DefaultStyleProvider}
                         docViewPath={returnEmptyDoclist}
-                        freezeDimensions={true}
                         focus={DocUtils.DefaultFocus}
                         renderDepth={this.props.renderDepth}
                         rootSelected={returnFalse}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 70732e74c..db076c069 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -143,7 +143,6 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo
 
     CreateBindings(onClick: Opt<ScriptField>, onInput: Opt<ScriptField>): JsxBindings {
         const docOnlyProps = [  // these are the properties in  DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews
-            "freezeDimensions",
             "hideResizeHandles",
             "hideTitle",
             "treeViewDoc",
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 89096c948..263e1dc4c 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -160,7 +160,6 @@ export interface DocumentViewSharedProps {
 // these props are specific to DocuentViews
 export interface DocumentViewProps extends DocumentViewSharedProps {
     // properties specific to DocumentViews but not to FieldView
-    freezeDimensions?: boolean;
     hideResizeHandles?: boolean; // whether to suppress DocumentDecorations when this document is selected
     hideTitle?: boolean;  // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings
     hideDecorationTitle?: boolean;  // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings
@@ -1220,11 +1219,11 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     @computed get layoutDoc() { return Doc.Layout(this.Document, this.props.LayoutTemplate?.()); }
     @computed get nativeWidth() {
         return this.docView?._componentView?.reverseNativeScaling?.() ? 0 :
-            returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions));
+            returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, !this.fitWidth));
     }
     @computed get nativeHeight() {
         return this.docView?._componentView?.reverseNativeScaling?.() ? 0 :
-            returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions));
+            returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, !this.fitWidth));
     }
     @computed get shouldNotScale() {
         return (this.fitWidth && !this.nativeWidth) ||
@@ -1312,8 +1311,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     ContentScale = () => this.nativeScaling;
     selfView = () => this;
     screenToLocalTransform = () => {
-        const oshift = this.fitWidth && this.ComponentView instanceof FormattedTextBox;
-        const shift = oshift ? -(this.props.PanelHeight() - this.rootDoc[HeightSym]()) / 2 : 0;
         return this.props.ScreenToLocalTransform().translate(-this.centeringX, -this.centeringY).translate(0, shift).scale(1 / this.nativeScaling);
     }
     componentDidMount() {
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index 1b37e729b..85efc67a5 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -903,9 +903,9 @@ ScriptingGlobals.add(function toggleSchemaPreview(checkResult?: boolean) {
     }
     else if (selected) {
         if (NumCast(selected.schemaPreviewWidth) > 0) {
-            selected.schemaPreviewWidth = 200;
-        } else {
             selected.schemaPreviewWidth = 0;
+        } else {
+            selected.schemaPreviewWidth = 200;
         }
     }
 });
-- 
cgit v1.2.3-70-g09d2


From 5bf71bb9fde28de8cc2cedaf03708315933acc30 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 22 Jun 2022 13:46:39 -0400
Subject: more cleanup in currentuserutils.  fixed so that removing items from
 a list in code will remove them from the UI

---
 src/client/documents/Documents.ts                  |   6 +-
 src/client/util/CurrentUserUtils.ts                | 209 ++++++++++-----------
 .../views/collections/CollectionStackingView.tsx   |   3 +-
 3 files changed, 104 insertions(+), 114 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index d0c7d2436..01cfe90da 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -708,8 +708,8 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.PRES), new List<Doc>(), options);
         }
 
-        export function ScriptingDocument(script: Opt<ScriptField>, options: DocumentOptions = {}, fieldKey?: string) {
-            return InstanceFromProto(Prototypes.get(DocumentType.SCRIPTING), script,
+        export function ScriptingDocument(script: Opt<ScriptField>|null, options: DocumentOptions = {}, fieldKey?: string) {
+            return InstanceFromProto(Prototypes.get(DocumentType.SCRIPTING), script ? script: undefined,
                 { ...options, layout: fieldKey ? ScriptingBox.LayoutString(fieldKey) : undefined });
         }
 
@@ -829,7 +829,7 @@ export namespace Docs {
             const nwid = options._nativeWidth || undefined;
             const nhght = options._nativeHeight || undefined;
             if (!nhght && width && height && nwid) options._nativeHeight = Number(nwid) * Number(height) / Number(width);
-            return InstanceFromProto(Prototypes.get(DocumentType.WEB), url ? new WebField(url) : undefined, options);
+            return InstanceFromProto(Prototypes.get(DocumentType.WEB), new WebField(url ? url : "http://www.bing.com/"), options);
         }
 
         export function HtmlDocument(html: string, options: DocumentOptions = {}) {
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index e119828c7..52fbda9a9 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -104,6 +104,7 @@ export class CurrentUserUtils {
                 }
             });
             items?.forEach(item => !DocListCast(doc.data).includes(item) && Doc.AddDocToList(Doc.GetProto(doc), "data", item));
+            items && DocListCast(doc.data).forEach(item => !items.includes(item) && Doc.RemoveDocFromList(Doc.GetProto(doc), "data", item));
         }
         return doc;
     }
@@ -148,9 +149,9 @@ export class CurrentUserUtils {
             return this.AssignScripts(assignBtnAndTempOpts(tempBtn, btnOpts, templateOpts) ?? CurrentUserUtils.createToolButton( {...btnOpts, dragFactory: makeTemp(template(templateOpts))}), reqdScripts);
         });
 
-        const reqdOpts = {
+        const reqdOpts:DocumentOptions = {
             title: "Experimental Tools", _xMargin: 0, _showTitle: "title", _chromeHidden: true,
-            _stayInCollection: true, _hideContextMenu: true, _forceActive: true, system: true,
+            _stayInCollection: true, _hideContextMenu: true, _forceActive: true, system: true, childDocumentsActive: true,
             _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true,
         };
         const reqdScripts = { dropConverter : "convertToButtons(dragData)" };
@@ -197,17 +198,12 @@ export class CurrentUserUtils {
 
     // setup templates for different document types when they are iconified from Document Decorations
     static setupDefaultIconTemplates(doc: Doc, field="template-icons") {
-        const templateIconsDoc = DocCast(doc[field]);
+        const reqdOpts = { title: "icon templates", _height: 75, system: true };
+        const templateIconsDoc = this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([], reqdOpts));
 
         const makeIconTemplate = (type: DocumentType | undefined, templateField: string, iconTemplate: () => Doc) => {
             const iconFieldName = "icon" + (type ? "_" + type : "");
-            if (!templateIconsDoc?.[iconFieldName]) {
-                const template = MakeTemplate(iconTemplate(), true, iconFieldName, templateField);
-                if (templateIconsDoc) {
-                    templateIconsDoc[iconFieldName] = template;
-                }
-                return template;
-            }
+            return DocCast(templateIconsDoc[iconFieldName] ?? (templateIconsDoc[iconFieldName] = MakeTemplate(iconTemplate(), true, iconFieldName, templateField))) ;
         };
         const deiconifyScript = () => ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" });
         const labelBox = (extra: object) => Docs.Create.LabelDocument({
@@ -235,68 +231,37 @@ export class CurrentUserUtils {
             makeIconTemplate("transcription" as any, "transcription", () => labelBox({ _backgroundColor: "orange" })),
             // makeIconTemplate(DocumentType.PDF, "icon", () => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", {}))
         ].filter(d => d).map(d => d!);
-
-        const reqdOpts = { title: "icon templates", _height: 75, system: true };
-        this.AssignOpts(templateIconsDoc, reqdOpts, iconTemplates) ?? (doc[field] = Docs.Create.TreeDocument(iconTemplates, reqdOpts));
+        this.AssignOpts(DocCast(doc[field]), {}, iconTemplates);
     }
 
-    /// initalizes the set of default versions of most document types
+    /// initalizes the set of "empty<DocType>" versions of each document type with default fields.  e.g.,. emptyNote, emptyPresentation
     static creatorBtnDescriptors(doc: Doc): {
         title: string, toolTip: string, icon: string,  ignoreClick?: boolean, dragFactory?: Doc, 
         backgroundColor?: string,  clickFactory?: Doc, scripts?: { onClick?: string, onDragStart?: string}, funcs?: {onDragStart?:string, hidden?: string},
     }[] {
-        const standardOps = () => ({ _fitWidth: true, system: true, "dragFactory-count": 0, cloneFieldFilter: new List<string>(["system"]) });
-        const emptyThings:{key:string,  // the field name where the empty thing will be stored
-                          opts:DocumentOptions,   // the document options that are required for the empty thing
-                          funcs?:{[key:string]: any},  // computed fields that are rquired for the empth thing
-                          creator:(opts:DocumentOptions)=> any // how to create the empty thing if it doesn't exist
-              }[] = [
-            {key: "emptyPresentation", creator: Docs.Create.PresDocument,  opts: { title: "Untitled Presentation", _viewType: CollectionViewType.Stacking, _width: 400, _height: 500, targetDropAction: "alias" as any, _chromeHidden: true, boxShadow: "0 0" }},
-            {key: "emptyCollection", creator: (opts) => Docs.Create.FreeformDocument([], opts), opts: { title: "freeform", _width: 150, _height: 100 }},
-            {key: "emptyPane", creator: (opts) => Docs.Create.FreeformDocument([], opts), opts:  { title: "Untitled Tab", _backgroundGridShow: true, _width: 500, _height: 800 }},
-            {key: "emptyMath", creator: (opts) => Docs.Create.EquationDocument(opts), opts: { title: "Equation", _backgroundGridShow: true, _width: 300, _height: 35 }},
-            {key: "emptySlide", creator: (opts) => Docs.Create.TreeDocument([], opts), funcs: {title: 'self.text?.Text'}, opts: {
-                _viewType: CollectionViewType.Tree, treeViewHasOverlay: true, _fontSize: "20px", _autoHeight: true, 
-                "dragFactory-count": undefined,  allowOverlayDrop: true, treeViewType: TreeViewType.outline, _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, backgroundColor: "white"
-            }},
-            {key: "emptyComparison", creator: Docs.Create.ComparisonDocument, opts: { title: "Comparer", _width: 300, _height: 300 }},
-            {key: "emptyScript", creator: (opts) => Docs.Create.ScriptingDocument(undefined, opts), opts:  { title: "script", _width: 200, _height: 250, }},
-            {key: "emptyScreenshot", creator: Docs.Create.ScreenshotDocument, opts: { title: "empty screenshot", _width: 400, _height: 200 }},
-            {key: "emptyWebCam", creator: (opts) => Docs.Create.WebCamDocument("", opts), opts: { _width: 400, _height: 200, title: "recording", recording:true, system: true, cloneFieldFilter: new List<string>(["system"]) }},
-            {key: "emptyAudio", creator: (opts) => Docs.Create.AudioDocument(nullAudio, opts), opts: { title: "audio recording", x: 200, y: 200, _width: 200, _height: 100, }},
-            {key: "emptyNote", creator: (opts) => Docs.Create.TextDocument("", opts), opts:  { title: "text note", _width: 200, _autoHeight: true }},
-            {key: "emptyButton", creator: Docs.Create.ButtonDocument, opts: { title: "Button", _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, }},
-            {key: "emptyWebpage", creator: (opts) => Docs.Create.WebDocument("http://www.bing.com/", opts), opts: { title: "webpage", _nativeWidth: 850, _height: 512, _width: 400, useCors: true, }},
-            {key: "emptyMap", creator: (opts) =>  Docs.Create.MapDocument([], opts), opts: { title: "map", _showSidebar: true, _width: 800, _height: 600, }},
-            {key: "emptyDataViz", creator: (opts) => Docs.Create.DataVizDocument(opts), opts: { title: "DataViz",                 _width: 300, _height: 300 }},
-        ];
-
-        emptyThings.forEach(thing => 
-            this.AssignScripts(this.AssignOpts(DocCast(doc[thing.key]), {...standardOps(), ...thing.opts}) ?? (doc[thing.key] = thing.creator({...standardOps(), ...thing.opts})), undefined, thing.funcs))
-        
-        if (doc.emptyHeader === undefined) {
-            const json = {
-                doc: {
-                    type: "doc",
-                    content: [
-                        {
-                            type: "paragraph", attrs: {}, content: [{
-                                type: "dashField",
-                                attrs: { fieldKey: "author", docid: "", hideKey: false },
-                                marks: [{ type: "strong" }]
-                            }, {
-                                type: "dashField",
-                                attrs: { fieldKey: "creationDate", docid: "", hideKey: false },
-                                marks: [{ type: "strong" }]
-                            }]
+        const standardOps = (key:string) => ({ title : "Untitled "+ key, _fitWidth: true, system: true, "dragFactory-count": 0, cloneFieldFilter: new List<string>(["system"]) });
+        const json = {
+            doc: {
+                type: "doc",
+                content: [
+                    {
+                        type: "paragraph", attrs: {}, content: [{
+                            type: "dashField",
+                            attrs: { fieldKey: "author", docid: "", hideKey: false },
+                            marks: [{ type: "strong" }]
+                        }, {
+                            type: "dashField",
+                            attrs: { fieldKey: "creationDate", docid: "", hideKey: false },
+                            marks: [{ type: "strong" }]
                         }]
-                },
-                selection: { type: "text", anchor: 1, head: 1 },
-                storedMarks: []
-            };
-            const headerBtnHgt = 10;
-            const headerTemplate = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), {
-                ...standardOps(), title: "text", _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true,
+                    }]
+            },
+            selection: { type: "text", anchor: 1, head: 1 },
+            storedMarks: []
+        };
+        const headerBtnHgt = 10;
+        const headerTemplate = (opts:DocumentOptions) => {
+            const header = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { ...opts, title: "text", 
                 layout:
                 "<HTMLdiv transformOrigin='top left' width='{100/scale}%' height='{100/scale}%' transform='scale({scale})'>" +
                 `    <FormattedTextBox {...props} dontScale='true' fieldKey={'text'}  height='calc(100% - ${headerBtnHgt}px - {this._headerHeight||0}px)'/>` +
@@ -309,28 +274,57 @@ export class CurrentUserUtils {
             // "    <FormattedTextBox {...props} fieldKey={'header'} dontSelectOnLoad={'true'} ignoreAutoHeight={'true'} pointerEvents='{this._headerPointerEvents||`none`}' fontSize='{this._headerFontSize}px' height='{this._headerHeight}px' background='{this._headerColor||this.target.mySharedDocs.userColor}' />" +
             // "    <FormattedTextBox {...props} fieldKey={'text'} position='absolute' top='{(this._headerHeight)*scale}px' height='calc({100/scale}% - {this._headerHeight}px)'/>" +
             // "</div>";
-            Doc.GetProto(headerTemplate).isTemplateDoc = makeTemplate(Doc.GetProto(headerTemplate), true, "headerView");
-            doc.emptyHeader = headerTemplate;
+            Doc.GetProto(header).isTemplateDoc = makeTemplate(Doc.GetProto(header), true, "headerView");
+            Doc.GetProto(header).title = "Untitled Header";
+            return header; 
         }
+        const emptyThings:{key:string,  // the field name where the empty thing will be stored
+                          opts:DocumentOptions,   // the document options that are required for the empty thing
+                          funcs?:{[key:string]: any},  // computed fields that are rquired for the empth thing
+                          creator:(opts:DocumentOptions)=> any // how to create the empty thing if it doesn't exist
+              }[] = [
+            {key: "Note",       creator: opts => Docs.Create.TextDocument("", opts),        opts: { _width: 200, _autoHeight: true }},
+            {key: "Collection", creator: opts => Docs.Create.FreeformDocument([], opts),    opts: { _width: 150, _height: 100 }},
+            {key: "Equation",   creator: opts => Docs.Create.EquationDocument(opts),        opts: { _width: 300, _height: 35, _backgroundGridShow: true, }},
+            {key: "Webpage",    creator: opts => Docs.Create.WebDocument("",opts),          opts: { _width: 400, _height: 512, _nativeWidth: 850, useCors: true, }},
+            {key: "Comparison", creator: Docs.Create.ComparisonDocument,                    opts: { _width: 300, _height: 300 }},
+            {key: "Audio",      creator: opts => Docs.Create.AudioDocument(nullAudio, opts),opts: { _width: 200, _height: 100, }},
+            {key: "Map",        creator: opts => Docs.Create.MapDocument([], opts),         opts: { _width: 800, _height: 600, _showSidebar: true,  }},
+            {key: "Screengrab", creator: Docs.Create.ScreenshotDocument,                    opts: { _width: 400, _height: 200 }},
+            {key: "WebCam",     creator: opts => Docs.Create.WebCamDocument("", opts),      opts: { _width: 400, _height: 200, title: "recording", recording:true, system: true, cloneFieldFilter: new List<string>(["system"]) }},
+            {key: "Button",     creator: Docs.Create.ButtonDocument,                        opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, }},
+            {key: "Script",     creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }},
+            {key: "DataViz",    creator: opts => Docs.Create.DataVizDocument(opts),         opts: { _width: 300, _height: 300 }},
+            {key: "Header",     creator: headerTemplate,                                    opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true,}},
+            {key: "Presentation",creator: Docs.Create.PresDocument,                         opts: { _width: 400, _height: 500, _viewType: CollectionViewType.Stacking, targetDropAction: "alias" as any, _chromeHidden: true, boxShadow: "0 0" }},
+            {key: "Tab",        creator: opts => Docs.Create.FreeformDocument([], opts),    opts: { _width: 500, _height: 800, _backgroundGridShow: true, }},
+            {key: "Slide",      creator: opts => Docs.Create.TreeDocument([], opts),        opts: { _width: 300, _height: 200, _viewType: CollectionViewType.Tree, 
+                                                                                                treeViewHasOverlay: true, _fontSize: "20px", _autoHeight: true, 
+                                                                                                allowOverlayDrop: true, treeViewType: TreeViewType.outline, 
+                                                                                                backgroundColor: "white", _xMargin: 0, _yMargin: 0, _singleLine: true 
+                                                                                            }, funcs: {title: 'self.text?.Text'}},
+            ];
+
+        emptyThings.forEach(thing => 
+            this.AssignScripts(this.AssignOpts(DocCast(doc["empty"+thing.key]), {...standardOps(thing.key), ...thing.opts}) ?? (doc["empty"+thing.key] = thing.creator({...standardOps(thing.key), ...thing.opts})), undefined, thing.funcs))
+        
         
         return [
-            { toolTip: "Tap or drag to create a note",            title: "Note", icon: "sticky-note",   dragFactory: doc.emptyNote as Doc,        scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))',  onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, },
-            { toolTip: "Tap or drag to create a collection",      title: "Col", icon: "folder",         dragFactory: doc.emptyCollection as Doc,  scripts: {onClick: 'openOnRight(copyDragFactory(this.clickFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, clickFactory: doc.emptyPane as Doc, },
-            { toolTip: "Tap or drag to create an equation",       title: "Math", icon: "calculator",    dragFactory: doc.emptyMath as Doc,        scripts: {onClick: 'openOnRight(copyDragFactory(this.clickFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, },
-            { toolTip: "Tap or drag to create a webpage",         title: "Web", icon: "globe-asia",     dragFactory: doc.emptyWebpage as Doc,     scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))',  onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, },
-            { toolTip: "Tap or drag to create a comparison box",  title: "Compare", icon: "columns",    dragFactory: doc.emptyComparison as Doc,  scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))',  onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, },
-            { toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone",   dragFactory: doc.emptyAudio as Doc,       scripts: {onClick: 'openInOverlay(copyDragFactory(this.dragFactory))',onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, },
-            { toolTip: "Tap or drag to create a map",             title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc,         scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))',  onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, },
-            { toolTip: "Tap or drag to create a custom note",     title: "Custom", icon: "window-maximize", dragFactory: doc.emptyHeader as Doc,  scripts: {onClick: 'openOnRight(delegateDragFactory(this.dragFactory))', onDragStart: '{ return delegateDragFactory(this.dragFactory);}'},  },
-            { toolTip: "Tap or drag to create a progressive slide",title: "Slide", icon: "file",        dragFactory: doc.emptySlide as Doc,       scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))',  onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs: { hidden: 'IsNoviceMode()'} },
-            { toolTip: "Tap or drag to create a screen grabber",  title: "Grab", icon: "photo-video",   dragFactory: doc.emptyScreenshot as Doc,  scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))',  onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs: { hidden: 'IsNoviceMode()'} },
-            { toolTip: "Tap or drag to create a WebCam recorder", title: "WebCam", icon: "photo-video", dragFactory: doc.emptyWebCam as Doc,      scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))',  onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs: { hidden: 'IsNoviceMode()'}},
-            { toolTip: "Tap or drag to create a button",          title: "Button", icon: "bolt",        dragFactory: doc.emptyButton as Doc,      scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))',  onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs:{ hidden: 'IsNoviceMode()'} },
-            { toolTip: "Tap or drag to create a scripting box",   title: "Script", icon: "terminal",    dragFactory: doc.emptyScript as Doc,      scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))',  onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs: { hidden: 'IsNoviceMode()'}},
-            { toolTip: "Tap or drag to create a mobile view",     title: "Phone", icon: "mobile",       dragFactory: doc.activeMobileMenu as Doc, scripts: {onClick: 'openOnRight(Doc.UserDoc().activeMobileMenu)',     onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, funcs: {hidden: 'IsNoviceMode()'} },
-            { toolTip: "Tap or drag to create a data viz node",   title: "DataViz", icon: "file",       dragFactory: doc.emptyDataViz as Doc,     scripts: {onClick: 'openOnRight(Doc.UserDoc().activeMobileMenu)',     onDragStart: '{ return copyDragFactory(this.dragFactory);}'} },
+            { toolTip: "Tap or drag to create a note",            title: "Note", icon: "sticky-note",   dragFactory: doc.emptyNote as Doc, },
+            { toolTip: "Tap or drag to create a collection",      title: "Col", icon: "folder",         dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab),  scripts: { onClick: 'openOnRight(copyDragFactory(this.clickFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, },
+            { toolTip: "Tap or drag to create an equation",       title: "Math", icon: "calculator",    dragFactory: doc.emptyEquation as Doc, },
+            { toolTip: "Tap or drag to create a webpage",         title: "Web", icon: "globe-asia",     dragFactory: doc.emptyWebpage as Doc, },
+            { toolTip: "Tap or drag to create a comparison box",  title: "Compare", icon: "columns",    dragFactory: doc.emptyComparison as Doc, },
+            { toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone",   dragFactory: doc.emptyAudio as Doc, },
+            { toolTip: "Tap or drag to create a map",             title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc, },
+            { toolTip: "Tap or drag to create a screen grabber",  title: "Grab", icon: "photo-video",   dragFactory: doc.emptyScreengrab as Doc,  funcs: { hidden: 'IsNoviceMode()'} },
+            { toolTip: "Tap or drag to create a WebCam recorder", title: "WebCam", icon: "photo-video", dragFactory: doc.emptyWebCam as Doc,      funcs: { hidden: 'IsNoviceMode()'}},
+            { toolTip: "Tap or drag to create a button",          title: "Button", icon: "bolt",        dragFactory: doc.emptyButton as Doc,      funcs: { hidden: 'IsNoviceMode()'} },
+            { toolTip: "Tap or drag to create a scripting box",   title: "Script", icon: "terminal",    dragFactory: doc.emptyScript as Doc,      funcs: { hidden: 'IsNoviceMode()'}},
+            { toolTip: "Tap or drag to create a data viz node",   title: "DataViz", icon: "file",       dragFactory: doc.emptyDataViz as Doc, },
+            { toolTip: "Tap or drag to create a data note",       title: "DataNote", icon: "window-maximize", dragFactory: doc.emptyHeader as Doc,  scripts: {onClick: 'openOnRight(delegateDragFactory(this.dragFactory))', onDragStart: '{ return delegateDragFactory(this.dragFactory);}'},  },
             { toolTip: "Toggle a Calculator REPL",                title: "repl", icon: "calculator",                                              scripts: {onClick: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' } },
-          ];
+          ].map(tuple => ({scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, ...tuple, }))
     }
 
     /// Initalizes the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools
@@ -345,9 +339,10 @@ export class CurrentUserUtils {
             return this.AssignScripts(this.AssignOpts(btn, opts) ?? Docs.Create.FontIconDocument(opts), reqdOpts.scripts, reqdOpts.funcs);
         });
 
-        const reqdOpts = {
+        const reqdOpts:DocumentOptions = {
             title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, system: true,
             _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true,
+            childDocumentsActive: true
         };
         const reqdScripts = { dropConverter: "convertToButtons(dragData)" };
         return this.AssignScripts(this.AssignOpts(dragCreatorDoc, reqdOpts, creatorBtns) ?? Docs.Create.MasonryDocument(creatorBtns, reqdOpts), reqdScripts);
@@ -357,34 +352,26 @@ export class CurrentUserUtils {
     static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}}[] {
         const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())";
         return [
-            { title: "Dashboards",      target: CurrentUserUtils.MyDashboards,     icon: "desktop",     scripts:{onClick: 'selectMainMenu(self)'} },
-            { title: "Search",          target: CurrentUserUtils.MySearcher,       icon: "search",      scripts:{onClick: 'selectMainMenu(self)'} },
-            { title: "Files",           target: CurrentUserUtils.MyFilesystem,     icon: "folder-open", scripts:{onClick: 'selectMainMenu(self)'} },
-            { title: "Tools",           target: CurrentUserUtils.MyTools,          icon: "wrench",      scripts:{onClick: 'selectMainMenu(self)'}, funcs: {hidden: "IsNoviceMode()"} },
-            { title: "Imports",         target: CurrentUserUtils.MyImports,        icon: "upload",      scripts:{onClick: 'selectMainMenu(self)'} },
-            { title: "Recently Closed", target: CurrentUserUtils.MyRecentlyClosed, icon: "archive",     scripts:{onClick: 'selectMainMenu(self)'} },
-            { title: "Shared with me",  target: CurrentUserUtils.MySharedDocs,     icon: "users",       scripts:{onClick: 'selectMainMenu(self)'}, funcs:{badgeValue:badgeValue}},
-            { title: "Trails",          target: CurrentUserUtils.MyTrails,         icon: "pres-trail",  scripts:{onClick: 'selectMainMenu(self)'} },
-            { title: "User Doc",        target: CurrentUserUtils.MyUserDocView,    icon: "address-card",scripts:{onClick: 'selectMainMenu(self)'}, funcs: {hidden: "IsNoviceMode()"} },
-        ];
+            { title: "Dashboards",      target: this.setupDashboards(doc, "myDashboards"),         icon: "desktop",     },
+            { title: "Search",          target: this.setupSearcher(doc, "mySearcher"),             icon: "search",      },
+            { title: "Files",           target: this.setupFilesystem(doc, "myFilesystem"),         icon: "folder-open", },
+            { title: "Tools",           target: this.setupToolsBtnPanel(doc, "myTools"),           icon: "wrench",      funcs: {hidden: "IsNoviceMode()"} },
+            { title: "Imports",         target: this.setupImportSidebar(doc, "myImports"),         icon: "upload",      },
+            { title: "Recently Closed", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), icon: "archive",     },
+            { title: "Shared Docs",     target: this.MySharedDocs,                                 icon: "users",       funcs:{badgeValue:badgeValue}},
+            { title: "Trails",          target: this.setupTrails(doc, "myTrails"),                 icon: "pres-trail",  },
+            { title: "User Doc View",   target: this.setupUserDocView(doc, "myUserDocView"),       icon: "address-card",funcs: {hidden: "IsNoviceMode()"} },
+        ].map(tuple => ({...tuple, scripts:{onClick: 'selectMainMenu(self)'}}));
     }
 
-    /// setup the left sidebar container and panels that can be displayed within it
+    /// the empty panel that is filled with whichever left menu button's panel has been selected
     static setupLeftSidebarPanel(doc: Doc, field="myLeftSidebarPanel") {
         this.AssignOpts(DocCast(doc[field]), {}) ?? (doc[field] = ((doc:Doc) => {doc.system = true; return doc;})(new Doc()));
-        CurrentUserUtils.setupSearcher(doc, "mySearcher");
-        CurrentUserUtils.setupToolsBtnPanel(doc, "myTools");
-        CurrentUserUtils.setupImportSidebar(doc, "myImports");
-        CurrentUserUtils.setupDashboards(doc, "myDashboards");
-        CurrentUserUtils.setupTrails(doc, "myTrails");
-        CurrentUserUtils.setupFilesystem(doc, "myFilesystem");
-        CurrentUserUtils.setupRecentlyClosedDocs(doc, "myRecentlyClosed");
-        CurrentUserUtils.setupUserDocView(doc, "myUserDocView");
     }
 
     /// Initializes the left sidebar menu buttons and the panels they open up
     static setupLeftSidebarMenu(doc: Doc, field="myLeftSidebarMenu") {
-        this.setupLeftSidebarPanel(doc); // the tools/panels opened up by the menu buttons
+        this.setupLeftSidebarPanel(doc);
         const myLeftSidebarMenu = DocCast(doc[field]);
         const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, scripts, funcs }) => {
             const btnDoc = myLeftSidebarMenu ? DocListCast(myLeftSidebarMenu.data).find(doc => doc.title === title) : undefined;
@@ -520,7 +507,7 @@ export class CurrentUserUtils {
             dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Search Panel", system: true, childDropAction: "alias", 
             _lockedPosition: true, _viewType: CollectionViewType.Schema, _searchDoc: true,
         };
-        this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.SearchDocument(reqdOpts));
+        return this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.SearchDocument(reqdOpts));
     }
 
     /// Initializes the panel of draggable tools that is opened from the left sidebar.
@@ -532,7 +519,7 @@ export class CurrentUserUtils {
             title: "My Tools", system: true, ignoreClick: true, boxShadow: "0 0",
             _showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, 
         };
-        this.AssignOpts(myTools, reqdToolOps, [creatorBtns, templateBtns]) ?? (doc[field] = Docs.Create.StackingDocument([creatorBtns, templateBtns], reqdToolOps));
+        return this.AssignOpts(myTools, reqdToolOps, [creatorBtns, templateBtns]) ?? (doc[field] = Docs.Create.StackingDocument([creatorBtns, templateBtns], reqdToolOps));
     }
 
     /// initializes the left sidebar dashboard pane
@@ -595,6 +582,7 @@ export class CurrentUserUtils {
         if (Cast(myTrails.contextMenuScripts, listSpec(ScriptField), null)?.length !== contextMenuScripts.length) {
             myTrails.contextMenuScripts = new List<ScriptField>(contextMenuScripts.map(script => ScriptField.MakeFunction(script)!));
         }
+        return myTrails;
     }
 
     /// initializes the left sidebar File system pane
@@ -624,10 +612,11 @@ export class CurrentUserUtils {
         if (Cast(myFilesystem.childContextMenuScripts, listSpec(ScriptField), null)?.length !== childContextMenuScripts.length) {
             myFilesystem.childContextMenuScripts = new List<ScriptField>(childContextMenuScripts.map(script => ScriptField.MakeFunction(script)!));
         }
+        return myFilesystem;
     }
 
     /// initializes the panel displaying docs that have been recently closed
-    static setupRecentlyClosedDocs(doc: Doc, field:string) {
+    static setupRecentlyClosed(doc: Doc, field:string) {
         const reqdOpts:DocumentOptions = { _showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, 
             title: "My Recently Closed", buttonMenu: true, childHideLinkButton: true, treeViewHideTitle: true, childDropAction: "alias", system: true,
             treeViewTruncateTitleWidth: 150, ignoreClick: true,  boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same",
@@ -651,6 +640,7 @@ export class CurrentUserUtils {
         if (!Cast(recentlyClosed.contextMenuScripts, listSpec(ScriptField),null)?.find((script) => script.script.originalScript === clearAll("self"))) {
             recentlyClosed.contextMenuScripts = new List<ScriptField>([ScriptField.MakeScript(clearAll("self"))!])
         }
+        return recentlyClosed;
     }
 
     /// creates a new, empty filter doc
@@ -674,7 +664,7 @@ export class CurrentUserUtils {
             treeViewHideTitle: true, treeViewTruncateTitleWidth: 150
         };
         if (!doc[field]) this.AssignOpts(doc, {treeViewOpen: true, treeViewExpandedView: "fields" })
-        this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([doc], reqdOpts));
+        return this.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([doc], reqdOpts));
     }
 
     static linearButtonList = (title: string, opts: DocumentOptions, docs: Doc[]) => Docs.Create.LinearDocument(docs, {
@@ -903,7 +893,7 @@ export class CurrentUserUtils {
             buttonText: "Import", icon: "upload", system: true };
         const reqdBtnScripts = { onClick: "importDocument()" };
         const newImportBtn = this.AssignOpts(DocCast(myImports.buttonMenuDoc), reqdBtnOpts) ?? (myImports.buttonMenuDoc = Docs.Create.FontIconDocument(reqdBtnOpts));
-        this.AssignScripts(newImportBtn, reqdBtnScripts);
+        return this.AssignScripts(newImportBtn, reqdBtnScripts);
     }
 
     static setupClickEditorTemplates(doc: Doc) {
@@ -1055,7 +1045,6 @@ export class CurrentUserUtils {
         }
 
         if (doc) {  // this has the side-effect of setting the main container since we're assigning the active/guest dashboard
-            !("presentationView" in doc) && (doc.presentationView = new List<Doc>([Docs.Create.TreeDocument([], { title: "Presentation" })]));
             userDoc ? (CurrentUserUtils.ActiveDashboard = doc) : (CurrentUserUtils.GuestDashboard = doc);
         }
         const state = CurrentUserUtils._urlState;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 684c919bd..4e8c14039 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -229,6 +229,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         }
     }
     isContentActive = () => this.props.isSelected() || this.props.isContentActive();
+    isChildContentActive = () => this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive));
     getDisplayDoc(doc: Doc, width: () => number) {
         const dataDoc = (!doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS) ? undefined : this.props.DataDoc;
         const height = () => this.getDocHeight(doc);
@@ -245,7 +246,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             styleProvider={this.styleProvider}
             docViewPath={this.props.docViewPath}
             fitWidth={this.props.childFitWidth}
-            isContentActive={emptyFunction}
+            isContentActive={this.isChildContentActive}
             onKey={this.onKeyDown}
             isDocumentActive={this.isContentActive}
             LayoutTemplate={this.props.childLayoutTemplate}
-- 
cgit v1.2.3-70-g09d2

