From 8264ac5484c0c7b5d47cb78ce60f5d6568e736d9 Mon Sep 17 00:00:00 2001
From: anika-ahluwalia <anika.ahluwalia@gmail.com>
Date: Sat, 4 Jul 2020 17:25:10 -0500
Subject: redesigned editing menu, added link descriptions and popup on created

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

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

diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 620b977fa..26c41f524 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -207,7 +207,7 @@ class TreeView extends React.Component<TreeViewProps> {
         if (complete.linkDragData) {
             const sourceDoc = complete.linkDragData.linkSourceDocument;
             const destDoc = this.doc;
-            DocUtils.MakeLink({ doc: sourceDoc }, { doc: destDoc }, "tree link");
+            DocUtils.MakeLink({ doc: sourceDoc }, { doc: destDoc }, "tree link", "");
             e.stopPropagation();
         }
         const docDragData = complete.docDragData;
-- 
cgit v1.2.3-70-g09d2


From 0e2a5196b47c05eab74d0aae06c2db4a9528f0fb Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 13 Jul 2020 20:44:03 -0400
Subject: switched context menus to be less hierarchical.

---
 src/client/util/CurrentUserUtils.ts                |  2 -
 src/client/util/SettingsManager.scss               |  2 +-
 src/client/util/SettingsManager.tsx                | 14 ++++++-
 src/client/views/ContextMenuItem.tsx               |  6 +++
 .../views/collections/CollectionCarousel3DView.tsx | 13 +-----
 .../views/collections/CollectionCarouselView.tsx   | 14 +------
 .../views/collections/CollectionTreeView.tsx       |  2 +-
 src/client/views/collections/CollectionView.tsx    |  6 +--
 .../collectionFreeForm/FormatShapePane.tsx         | 26 ++++++------
 .../collectionGrid/CollectionGridView.tsx          |  5 +--
 src/client/views/nodes/DocumentView.tsx            | 38 ++++++++---------
 src/client/views/nodes/ImageBox.tsx                | 48 +++++++++++-----------
 src/client/views/nodes/LabelBox.tsx                |  2 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx | 48 +++++++++++-----------
 14 files changed, 111 insertions(+), 115 deletions(-)

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

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 39781a5ce..048ab9edc 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -423,8 +423,6 @@ export class CurrentUserUtils {
             // { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activeInkPen = this;', ischecked: `sameDocs(this.activeInkPen, this)`, backgroundColor: "white", activeInkPen: doc },
             { title: "Drag a document previewer", label: "Prev", icon: "expand", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory,true)', dragFactory: doc.emptyDocHolder as Doc },
             { title: "Toggle a Calculator REPL", label: "repl", icon: "calculator", click: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' },
-            { title: "Connect a Google Account", label: "Google Account", icon: "external-link-alt", click: 'GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken(true)' },
-            { title: "Connect a Hypothesis Account", label: "Hypothesis Account", icon: "heading", click: 'HypothesisAuthenticationManager.Instance.fetchOrGenerateAccessToken(true)' },
         ];
 
     }
diff --git a/src/client/util/SettingsManager.scss b/src/client/util/SettingsManager.scss
index 13c65042c..6d394a38d 100644
--- a/src/client/util/SettingsManager.scss
+++ b/src/client/util/SettingsManager.scss
@@ -56,7 +56,7 @@
         .settings-type {
             display: flex;
             flex-direction: column;
-            flex-basis: 30%;
+            flex-basis: 45%;
 
         }
 
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index 9888cce48..f7ca3942b 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -11,6 +11,8 @@ import { Networking } from "../Network";
 import { CurrentUserUtils } from "./CurrentUserUtils";
 import { Utils } from "../../Utils";
 import { Doc } from "../../fields/Doc";
+import HypothesisAuthenticationManager from "../apis/HypothesisAuthenticationManager";
+import GoogleAuthenticationManager from "../apis/GoogleAuthenticationManager";
 
 library.add(fa.faWindowClose);
 
@@ -83,6 +85,14 @@ export default class SettingsManager extends React.Component<{}> {
     noviceToggle = (event: any) => {
         Doc.UserDoc().noviceMode = !Doc.UserDoc().noviceMode;
     }
+    @action
+    googleAuthorize = (event: any) => {
+        GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken(true)
+    }
+    @action
+    hypothesisAuthorize = (event: any) => {
+        HypothesisAuthenticationManager.Instance.fetchAccessToken(true)
+    }
 
     private get settingsInterface() {
         return (
@@ -96,7 +106,9 @@ export default class SettingsManager extends React.Component<{}> {
                 <div className="settings-body">
                     <div className="settings-type">
                         <button onClick={this.onClick} value="password">reset password</button>
-                        <button onClick={this.noviceToggle} value="data">{`toggle ${Doc.UserDoc().noviceMode ? "developer" : "novice"} mode`}</button>
+                        <button onClick={this.noviceToggle} value="data">{`Set ${Doc.UserDoc().noviceMode ? "developer" : "novice"} mode`}</button>
+                        <button onClick={this.googleAuthorize} value="data">{`Link to Google`}</button>
+                        <button onClick={this.hypothesisAuthorize} value="data">{`Link to Hypothes.is`}</button>
                         <button onClick={() => window.location.assign(Utils.prepend("/logout"))}>
                             {CurrentUserUtils.GuestWorkspace ? "Exit" : "Log Out"}
                         </button>
diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index 99840047f..68ebd8e14 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -19,6 +19,7 @@ export interface OriginalMenuProps {
 export interface SubmenuProps {
     description: string;
     subitems: ContextMenuProps[];
+    noexpand?: boolean;
     icon: IconProp; //maybe should be optional (icon?)
     closeMenu?: () => void;
 }
@@ -96,6 +97,11 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
                 <div className="contextMenu-subMenu-cont" style={{ marginLeft: "25%", left: "0px", marginTop }}>
                     {this._items.map(prop => <ContextMenuItem {...prop} key={prop.description} closeMenu={this.props.closeMenu} />)}
                 </div>;
+            if (!("noexpand" in this.props)) {
+                return <>
+                    {this._items.map(prop => <ContextMenuItem {...prop} key={prop.description} closeMenu={this.props.closeMenu} />)}
+                </>;
+            }
             return (
                 <div className={"contextMenu-item" + (this.props.selected ? " contextMenu-itemSelected" : "")} style={{ alignItems: where }}
                     onMouseLeave={this.onPointerLeave} onMouseEnter={this.onPointerEnter}>
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index 1344b70f4..8f1cd5311 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -108,17 +108,6 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume
         }, 1500);
     }
 
-    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()) {
-            ContextMenu.Instance.addItem({
-                description: "Make Hero Image", event: () => {
-                    const index = NumCast(this.layoutDoc._itemIndex);
-                    (this.dataDoc || Doc.GetProto(this.props.Document)).hero = ObjectField.MakeCopy(this.childLayoutPairs[index].layout.data as ObjectField);
-                }, icon: "plus"
-            });
-        }
-    }
     _downX = 0;
     _downY = 0;
     onPointerDown = (e: React.PointerEvent) => {
@@ -184,7 +173,7 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume
         const index = NumCast(this.layoutDoc._itemIndex);
         const translateX = (1 - index) / this.childLayoutPairs.length * 100;
 
-        return <div className="collectionCarousel3DView-outer" onClick={this.onClick} onPointerDown={this.onPointerDown} ref={this.createDashEventsTarget} onContextMenu={this.onContextMenu}>
+        return <div className="collectionCarousel3DView-outer" onClick={this.onClick} onPointerDown={this.onPointerDown} ref={this.createDashEventsTarget}>
             <div className="carousel-wrapper" style={{ transform: `translateX(calc(${translateX}%` }}>
                 {this.content}
             </div>
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index bd0e4fc9a..b3fecfb91 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -83,18 +83,6 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
         </>;
     }
 
-
-    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()) {
-            ContextMenu.Instance?.addItem({
-                description: "Make Hero Image", event: () => {
-                    const index = NumCast(this.layoutDoc._itemIndex);
-                    (this.dataDoc || Doc.GetProto(this.props.Document)).hero = ObjectField.MakeCopy(this.childLayoutPairs[index].layout.data as ObjectField);
-                }, icon: "plus"
-            });
-        }
-    }
     _downX = 0;
     _downY = 0;
     onPointerDown = (e: React.PointerEvent) => {
@@ -119,7 +107,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
     }
 
     render() {
-        return <div className="collectionCarouselView-outer" onClick={this.onClick} onPointerDown={this.onPointerDown} ref={this.createDashEventsTarget} onContextMenu={this.onContextMenu}>
+        return <div className="collectionCarouselView-outer" onClick={this.onClick} onPointerDown={this.onPointerDown} ref={this.createDashEventsTarget}>
             {this.content}
             {this.props.Document._chromeStatus !== "replaced" ? this.buttons : (null)}
         </div>;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 26c41f524..dbd39d8df 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -780,7 +780,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
         onClicks.push({
             description: "Edit onChecked Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.doc, undefined, "onCheckedClick"), "edit onCheckedClick"), icon: "edit"
         });
-        !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" });
+        !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "hand-point-right" });
     }
     outerXf = () => Utils.GetScreenTransform(this._mainEle!);
     onTreeDrop = (e: React.DragEvent) => this.onExternalDrop(e, {});
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index df21d6a28..cbd1ac9af 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -272,7 +272,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
             subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) });
         }
         addExtras && subItems.push({ description: "lightbox", event: action(() => this._isLightboxOpen = true), icon: "eye" });
-        !existingVm && ContextMenu.Instance.addItem({ description: category, subitems: subItems, icon: "eye" });
+        !existingVm && ContextMenu.Instance.addItem({ description: category, noexpand: true, subitems: subItems, icon: "eye" });
     }
 
     onContextMenu = (e: React.MouseEvent): void => {
@@ -294,7 +294,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
             if (this.props.Document.childClickedOpenTemplateView instanceof Doc) {
                 layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childClickedOpenTemplateView as Doc, "onRight"), icon: "project-diagram" });
             }
-            layoutItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" });
+            !Doc.UserDoc().noviceMode && layoutItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" });
 
             !existing && cm.addItem({ description: "Options...", subitems: layoutItems, icon: "hand-point-right" });
 
@@ -314,7 +314,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                     icon: "edit",
                     event: () => this.props.Document[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)),
                 }));
-            !existingOnClick && cm.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" });
+            !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "hand-point-right" });
 
             if (!Doc.UserDoc().noviceMode) {
                 const more = cm.findByDescription("More...");
diff --git a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
index 56ba9e96a..9d9ce7f36 100644
--- a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
+++ b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
@@ -11,6 +11,7 @@ import { DocumentType } from "../../../documents/DocumentTypes";
 import { SelectionManager } from "../../../util/SelectionManager";
 import AntimodeMenu from "../../AntimodeMenu";
 import "./FormatShapePane.scss";
+import { undoBatch } from "../../../util/UndoManager";
 
 @observer
 export default class FormatShapePane extends AntimodeMenu {
@@ -118,6 +119,7 @@ export default class FormatShapePane extends AntimodeMenu {
         }
     }
 
+    @undoBatch
     @action
     rotate = (degrees: number) => {
         this.selectedInk?.forEach(action(inkView => {
@@ -160,7 +162,7 @@ export default class FormatShapePane extends AntimodeMenu {
     colorPicker(setter: (color: string) => {}) {
         return <div className="btn-group-palette" key="colorpicker" >
             {this._palette.map(color =>
-                <button className="antimodeMenu-button" key={color} onPointerDown={action(() => setter(color))} style={{ zIndex: 1001, position: "relative" }}>
+                <button className="antimodeMenu-button" key={color} onPointerDown={undoBatch(action(() => setter(color)))} style={{ zIndex: 1001, position: "relative" }}>
                     <div className="color-previewII" style={{ backgroundColor: color }} />
                 </button>)}
         </div>;
@@ -171,11 +173,11 @@ export default class FormatShapePane extends AntimodeMenu {
                 type="text" value={value}
                 onChange={e => setter(e.target.value)}
                 autoFocus />
-            <button className="antiMenu-Buttonup" key="up" onPointerDown={action(() => this.upDownButtons("up", key))}>
+            <button className="antiMenu-Buttonup" key="up" onPointerDown={undoBatch(action(() => this.upDownButtons("up", key)))}>
                 ˄
             </button>
             <br />
-            <button className="antiMenu-Buttonup" key="down" onPointerDown={action(() => this.upDownButtons("down", key))} style={{ marginTop: -8 }}>
+            <button className="antiMenu-Buttonup" key="down" onPointerDown={undoBatch(action(() => this.upDownButtons("down", key)))} style={{ marginTop: -8 }}>
                 ˅
             </button>
         </>;
@@ -183,7 +185,7 @@ export default class FormatShapePane extends AntimodeMenu {
 
     colorButton(value: string, setter: () => {}) {
         return <>
-            <button className="antimodeMenu-button" key="fill" onPointerDown={action(e => setter())} style={{ position: "absolute", right: 80 }}>
+            <button className="antimodeMenu-button" key="fill" onPointerDown={undoBatch(action(e => setter()))} style={{ position: "absolute", right: 80 }}>
                 <FontAwesomeIcon icon="fill-drip" size="lg" />
                 <div className="color-previewI" style={{ backgroundColor: value ?? "121212" }} />
             </button>
@@ -206,10 +208,10 @@ export default class FormatShapePane extends AntimodeMenu {
 
     @computed get propertyGroupItems() {
         const fillCheck = <div key="fill" style={{ display: this._subOpen[0] ? "" : "none", width: "inherit", backgroundColor: "#323232", color: "white", }}>
-            <input className="formatShapePane-inputBtn" type="radio" checked={this.unFilled} onChange={action(() => this.unFilled = true)} />
+            <input className="formatShapePane-inputBtn" type="radio" checked={this.unFilled} onChange={undoBatch(action(() => this.unFilled = true))} />
                 No Fill
             <br />
-            <input className="formatShapePane-inputBtn" type="radio" checked={this.solidFil} onChange={action(() => this.solidFil = true)} />
+            <input className="formatShapePane-inputBtn" type="radio" checked={this.solidFil} onChange={undoBatch(action(() => this.solidFil = true))} />
                 Solid Fill
             <br /> <br />
             {this.solidFil ? "Color" : ""}
@@ -218,22 +220,22 @@ export default class FormatShapePane extends AntimodeMenu {
         </div>;
 
         const markers = <>
-            <input key="markHead" className="formatShapePane-inputBtn" type="checkbox" checked={this.markHead !== ""} onChange={action(() => this.markHead = this.markHead ? "" : "arrow")} />
+            <input key="markHead" className="formatShapePane-inputBtn" type="checkbox" checked={this.markHead !== ""} onChange={undoBatch(action(() => this.markHead = this.markHead ? "" : "arrow"))} />
                 Arrow Head
             <br />
-            <input key="markTail" className="formatShapePane-inputBtn" type="checkbox" checked={this.markTail !== ""} onChange={action(() => this.markTail = this.markTail ? "" : "arrow")} />
+            <input key="markTail" className="formatShapePane-inputBtn" type="checkbox" checked={this.markTail !== ""} onChange={undoBatch(action(() => this.markTail = this.markTail ? "" : "arrow"))} />
                 Arrow End
             <br />
         </>;
 
         const lineCheck = <div key="lineCheck" style={{ display: this._subOpen[1] ? "" : "none", width: "inherit", backgroundColor: "#323232", color: "white", }}>
-            <input className="formatShapePane-inputBtn" type="radio" checked={this.unStrokd} onChange={action(() => this.unStrokd = true)} />
+            <input className="formatShapePane-inputBtn" type="radio" checked={this.unStrokd} onChange={undoBatch(action(() => this.unStrokd = true))} />
                 No Line
             <br />
-            <input className="formatShapePane-inputBtn" type="radio" checked={this.solidStk} onChange={action(() => this.solidStk = true)} />
+            <input className="formatShapePane-inputBtn" type="radio" checked={this.solidStk} onChange={undoBatch(action(() => this.solidStk = true))} />
                 Solid Line
             <br />
-            <input className="formatShapePane-inputBtn" type="radio" checked={this.dashdStk ? true : false} onChange={action(() => this.dashdStk = "2")} />
+            <input className="formatShapePane-inputBtn" type="radio" checked={this.dashdStk ? true : false} onChange={undoBatch(action(() => this.dashdStk = "2"))} />
                 Dash Line
             <br />
             <br />
@@ -253,7 +255,7 @@ export default class FormatShapePane extends AntimodeMenu {
             <br /> <br />
                 Width {this.widInput}
             <br /> <br />
-            <input className="formatShapePane-inputBtn" style={{ right: 0 }} type="checkbox" checked={this._lock} onChange={action(() => this._lock = !this._lock)} />
+            <input className="formatShapePane-inputBtn" style={{ right: 0 }} type="checkbox" checked={this._lock} onChange={undoBatch(action(() => this._lock = !this._lock))} />
                 Lock Ratio
             <br />  <br />
                 Rotation {this.rotInput}
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index 2015ca930..188b88c41 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -1,7 +1,7 @@
 import { action, computed, Lambda, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from "react";
-import { Doc, Opt } from '../../../../fields/Doc';
+import { Doc, Opt, WidthSym } from '../../../../fields/Doc';
 import { documentSchema } from '../../../../fields/documentSchemas';
 import { Id } from '../../../../fields/FieldSymbols';
 import { makeInterface } from '../../../../fields/Schema';
@@ -248,8 +248,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) {
      */
     onContextMenu = () => {
         const displayOptionsMenu: ContextMenuProps[] = [];
-        displayOptionsMenu.push({ description: "Contents", event: () => this.props.Document.display = "contents", icon: "copy" });
-        displayOptionsMenu.push({ description: "Undefined", event: () => this.props.Document.display = undefined, icon: "exclamation" });
+        displayOptionsMenu.push({ description: "Toggle Content Display Style", event: () => this.props.Document.display = this.props.Document.display ? undefined : "contents", icon: "copy" });
         ContextMenu.Instance.addItem({ description: "Display", subitems: displayOptionsMenu, icon: "tv" });
     }
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 6ef976ceb..a586e81d8 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -770,6 +770,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const options = cm.findByDescription("Options...");
         const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : [];
         const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layoutKey)], Doc, null);
+        optionItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
         templateDoc && optionItems.push({ description: "Open Template   ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" });
         !options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "compass" });
 
@@ -783,14 +784,14 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link on Right", event: this.toggleFollowOnRight, icon: "concierge-bell" });
         onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? "Remove Click Behavior" : "Follow Link", event: this.toggleLinkButtonBehavior, icon: "concierge-bell" });
         onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "edit" });
-        !existingOnClick && cm.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" });
+        !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "hand-point-right" });
 
         const funcs: ContextMenuProps[] = [];
         if (this.layoutDoc.onDragStart) {
             funcs.push({ description: "Drag an Alias", icon: "edit", event: () => this.Document.dragFactory && (this.layoutDoc.onDragStart = ScriptField.MakeFunction('getAlias(this.dragFactory)')) });
             funcs.push({ description: "Drag a Copy", icon: "edit", event: () => this.Document.dragFactory && (this.layoutDoc.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)')) });
             funcs.push({ description: "Drag Document", icon: "edit", event: () => this.layoutDoc.onDragStart = undefined });
-            cm.addItem({ description: "OnDrag...", subitems: funcs, icon: "asterisk" });
+            cm.addItem({ description: "OnDrag...", noexpand: true, subitems: funcs, icon: "asterisk" });
         }
 
         const more = cm.findByDescription("More...");
@@ -817,29 +818,28 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 // a.download = `DocExport-${this.props.Document[Id]}.zip`;
                 // a.click();
             });
+            moreItems.push({ description: "Copy ID", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "fingerprint" });
         }
-        moreItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
-        moreItems.push({ description: "Copy ID", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "fingerprint" });
         moreItems.push({ description: "Delete", event: this.deleteClicked, icon: "trash" });
         moreItems.push({ description: "Share", event: () => SharingManager.Instance.open(this), icon: "external-link-alt" });
         !more && cm.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" });
         cm.moveAfter(cm.findByDescription("More...")!, cm.findByDescription("OnClick...")!);
 
-        const help = cm.findByDescription("Help...");
-        const helpItems: ContextMenuProps[] = help && "subitems" in help ? help.subitems : [];
-        helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument(Utils.prepend("/assets/cheat-sheet.pdf"), { _width: 300, _height: 300 }), "onRight"), icon: "keyboard" });
-        helpItems.push({ description: "Show Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
-        cm.addItem({ description: "Help...", subitems: helpItems, icon: "question" });
-
-        const existingAcls = cm.findByDescription("Privacy...");
-        const aclItems: ContextMenuProps[] = existingAcls && "subitems" in existingAcls ? existingAcls.subitems : [];
-        aclItems.push({ description: "Make Add Only", event: () => this.setAcl("addOnly"), icon: "concierge-bell" });
-        aclItems.push({ description: "Make Read Only", event: () => this.setAcl("readOnly"), icon: "concierge-bell" });
-        aclItems.push({ description: "Make Private", event: () => this.setAcl("ownerOnly"), icon: "concierge-bell" });
-        aclItems.push({ description: "Make Editable", event: () => this.setAcl("write"), icon: "concierge-bell" });
-        aclItems.push({ description: "Test Private", event: () => this.testAcl("ownerOnly"), icon: "concierge-bell" });
-        aclItems.push({ description: "Test Readonly", event: () => this.testAcl("readOnly"), icon: "concierge-bell" });
-        !existingAcls && cm.addItem({ description: "Privacy...", subitems: aclItems, icon: "question" });
+        // const help = cm.findByDescription("Help...");
+        // const helpItems: ContextMenuProps[] = help && "subitems" in help ? help.subitems : [];
+        // helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument(Utils.prepend("/assets/cheat-sheet.pdf"), { _width: 300, _height: 300 }), "onRight"), icon: "keyboard" });
+        // helpItems.push({ description: "Show Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
+        // cm.addItem({ description: "Help...", subitems: helpItems, icon: "question" });
+
+        // const existingAcls = cm.findByDescription("Privacy...");
+        // const aclItems: ContextMenuProps[] = existingAcls && "subitems" in existingAcls ? existingAcls.subitems : [];
+        // aclItems.push({ description: "Make Add Only", event: () => this.setAcl("addOnly"), icon: "concierge-bell" });
+        // aclItems.push({ description: "Make Read Only", event: () => this.setAcl("readOnly"), icon: "concierge-bell" });
+        // aclItems.push({ description: "Make Private", event: () => this.setAcl("ownerOnly"), icon: "concierge-bell" });
+        // aclItems.push({ description: "Make Editable", event: () => this.setAcl("write"), icon: "concierge-bell" });
+        // aclItems.push({ description: "Test Private", event: () => this.testAcl("ownerOnly"), icon: "concierge-bell" });
+        // aclItems.push({ description: "Test Readonly", event: () => this.testAcl("readOnly"), icon: "concierge-bell" });
+        // !existingAcls && cm.addItem({ description: "Privacy...", subitems: aclItems, icon: "question" });
 
         // const recommender_subitems: ContextMenuProps[] = [];
 
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index d16aa528c..4eba21eab 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -157,29 +157,31 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
         const field = Cast(this.dataDoc[this.fieldKey], ImageField);
         if (field) {
             const funcs: ContextMenuProps[] = [];
-            funcs.push({ description: "Rotate", event: this.rotate, icon: "expand-arrows-alt" });
-            funcs.push({ description: "Export to Google Photos", event: () => GooglePhotos.Transactions.UploadImages([this.props.Document]), icon: "caret-square-right" });
-            funcs.push({ description: "Copy path", event: () => Utils.CopyText(field.url.href), icon: "expand-arrows-alt" });
-            // funcs.push({
-            //     description: "Reset Native Dimensions", event: action(async () => {
-            //         const curNW = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]);
-            //         const curNH = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]);
-            //         if (this.props.PanelWidth() / this.props.PanelHeight() > curNW / curNH) {
-            //             this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelHeight() * curNW / curNH;
-            //             this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelHeight();
-            //         } else {
-            //             this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelWidth();
-            //             this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelWidth() * curNH / curNW;
-            //         }
-            //     }), icon: "expand-arrows-alt"
-            // });
-
-            const existingAnalyze = ContextMenu.Instance?.findByDescription("Analyzers...");
-            const modes: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : [];
-            modes.push({ description: "Generate Tags", event: this.generateMetadata, icon: "tag" });
-            modes.push({ description: "Find Faces", event: this.extractFaces, icon: "camera" });
-            //modes.push({ description: "Recommend", event: this.extractText, icon: "brain" });
-            !existingAnalyze && ContextMenu.Instance?.addItem({ description: "Analyzers...", subitems: modes, icon: "hand-point-right" });
+            funcs.push({ description: "Rotate Clockwise 90", event: this.rotate, icon: "expand-arrows-alt" });
+            if (!Doc.UserDoc().noviceMode) {
+                funcs.push({ description: "Export to Google Photos", event: () => GooglePhotos.Transactions.UploadImages([this.props.Document]), icon: "caret-square-right" });
+                funcs.push({ description: "Copy path", event: () => Utils.CopyText(field.url.href), icon: "expand-arrows-alt" });
+                // funcs.push({
+                //     description: "Reset Native Dimensions", event: action(async () => {
+                //         const curNW = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]);
+                //         const curNH = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]);
+                //         if (this.props.PanelWidth() / this.props.PanelHeight() > curNW / curNH) {
+                //             this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelHeight() * curNW / curNH;
+                //             this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelHeight();
+                //         } else {
+                //             this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelWidth();
+                //             this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelWidth() * curNH / curNW;
+                //         }
+                //     }), icon: "expand-arrows-alt"
+                // });
+
+                const existingAnalyze = ContextMenu.Instance?.findByDescription("Analyzers...");
+                const modes: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : [];
+                modes.push({ description: "Generate Tags", event: this.generateMetadata, icon: "tag" });
+                modes.push({ description: "Find Faces", event: this.extractFaces, icon: "camera" });
+                //modes.push({ description: "Recommend", event: this.extractText, icon: "brain" });
+                !existingAnalyze && ContextMenu.Instance?.addItem({ description: "Analyzers...", subitems: modes, icon: "hand-point-right" });
+            }
 
             ContextMenu.Instance?.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
         }
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 836ef4149..0dfbdc5cf 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -41,7 +41,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps, LabelDocument
             }, icon: "trash"
         });
 
-        ContextMenu.Instance.addItem({ description: "OnClick...", subitems: funcs, icon: "asterisk" });
+        ContextMenu.Instance.addItem({ description: "OnClick...", noexpand: true, subitems: funcs, icon: "asterisk" });
     }
 
     @undoBatch
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 01ac765b9..f87b28c7f 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -479,7 +479,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             });
         });
         changeItems.push({ description: "FreeForm", event: () => DocUtils.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), icon: "eye" });
-        appearanceItems.push({ description: "Change Perspective...", subitems: changeItems, icon: "external-link-alt" });
+        appearanceItems.push({ description: "Change Perspective...", noexpand: true, subitems: changeItems, icon: "external-link-alt" });
         const uicontrols: ContextMenuProps[] = [];
         uicontrols.push({ description: "Toggle Sidebar", event: () => this.layoutDoc._showSidebar = !this.layoutDoc._showSidebar, icon: "expand-arrows-alt" });
         uicontrols.push({ description: "Toggle Dictation Icon", event: () => this.layoutDoc._showAudio = !this.layoutDoc._showAudio, icon: "expand-arrows-alt" });
@@ -489,10 +489,29 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 proto instanceof Doc && (proto.BROADCAST_MESSAGE = Cast(this.rootDoc[this.fieldKey], RichTextField)?.Text)), icon: "expand-arrows-alt"
         });
 
-        appearanceItems.push({ description: "UI Controls...", subitems: uicontrols, icon: "asterisk" });
+        appearanceItems.push({ description: "UI Controls...", noexpand: true, subitems: uicontrols, icon: "asterisk" });
         this.rootDoc.isTemplateDoc && appearanceItems.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.rootDoc), icon: "eye" });
         Doc.UserDoc().defaultTextLayout && appearanceItems.push({ description: "Reset default note style", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" });
-        appearanceItems.push({
+
+        !appearance && ContextMenu.Instance.addItem({ description: "Appearance...", subitems: appearanceItems, icon: "eye" });
+
+        const funcs: ContextMenuProps[] = [];
+
+        const highlighting: ContextMenuProps[] = [];
+        ["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option =>
+            highlighting.push({
+                description: (FormattedTextBox._highlights.indexOf(option) === -1 ? "Highlight " : "Unhighlight ") + option, event: () => {
+                    e.stopPropagation();
+                    if (FormattedTextBox._highlights.indexOf(option) === -1) {
+                        FormattedTextBox._highlights.push(option);
+                    } else {
+                        FormattedTextBox._highlights.splice(FormattedTextBox._highlights.indexOf(option), 1);
+                    }
+                    this.updateHighlights();
+                }, icon: "expand-arrows-alt"
+            }));
+        funcs.push({ description: "highlighting...", noexpand: true, subitems: highlighting, icon: "hand-point-right" });
+        funcs.push({
             description: "Convert to be a template style", event: () => {
                 if (!this.layoutDoc.isTemplateDoc) {
                     const title = StrCast(this.rootDoc.title);
@@ -517,29 +536,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.rootDoc);
             }, icon: "eye"
         });
-        !appearance && ContextMenu.Instance.addItem({ description: "Appearance...", subitems: appearanceItems, icon: "eye" });
+        funcs.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" });
 
-        const funcs: ContextMenuProps[] = [];
-
-        //funcs.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" });
-        funcs.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" });
         funcs.push({ description: "Toggle Single Line", event: () => this.layoutDoc._singleLine = !this.layoutDoc._singleLine, icon: "expand-arrows-alt" });
-
-        const highlighting: ContextMenuProps[] = [];
-        ["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option =>
-            highlighting.push({
-                description: (FormattedTextBox._highlights.indexOf(option) === -1 ? "Highlight " : "Unhighlight ") + option, event: () => {
-                    e.stopPropagation();
-                    if (FormattedTextBox._highlights.indexOf(option) === -1) {
-                        FormattedTextBox._highlights.push(option);
-                    } else {
-                        FormattedTextBox._highlights.splice(FormattedTextBox._highlights.indexOf(option), 1);
-                    }
-                    this.updateHighlights();
-                }, icon: "expand-arrows-alt"
-            }));
-        funcs.push({ description: "highlighting...", subitems: highlighting, icon: "hand-point-right" });
-
+        funcs.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" });
         ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
         this._downX = this._downY = Number.NaN;
     }
-- 
cgit v1.2.3-70-g09d2


From f6db7693e18e06c467a7136c591bd12a2cc96c7f Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 14 Jul 2020 14:20:53 -0400
Subject: fixed issues with creating & using scripting boxes by making
 scriptFields be a function, not value, prop

---
 src/client/documents/Documents.ts                  |  2 ++
 src/client/util/CurrentUserUtils.ts                | 26 ++++++++++++------
 src/client/views/OverlayView.scss                  |  2 ++
 src/client/views/TemplateMenu.tsx                  |  7 +++--
 .../views/collections/CollectionCarousel3DView.tsx | 10 +++----
 .../views/collections/CollectionCarouselView.tsx   |  7 +++--
 .../views/collections/CollectionStackingView.tsx   |  4 +--
 .../views/collections/CollectionTreeView.tsx       | 30 +++++++++++---------
 src/client/views/collections/CollectionView.tsx    | 11 +++++---
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  9 +++---
 .../collectionGrid/CollectionGridView.tsx          |  2 +-
 .../CollectionMulticolumnView.tsx                  |  4 +--
 .../CollectionMultirowView.tsx                     |  4 +--
 src/client/views/nodes/DocumentView.tsx            | 32 +++++++++++-----------
 src/fields/documentSchemas.ts                      |  1 -
 15 files changed, 87 insertions(+), 64 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index a415e17c8..90cef31d9 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -136,6 +136,8 @@ export interface DocumentOptions {
     dontRegisterChildViews?: boolean;
     lookupField?: ScriptField; // script that returns the value of a field. This script is passed the rootDoc, layoutDoc, field, and container of the document.  see PresBox.
     "onDoubleClick-rawScript"?: string; // onDoubleClick script in raw text form
+    "onChildDoubleClick-rawScript"?: string; // onChildDoubleClick script in raw text form
+    "onChildClick-rawScript"?: string // on ChildClick script in raw text form
     "onClick-rawScript"?: string; // onClick script in raw text form
     "onCheckedClick-rawScript"?: string; // onChecked script in raw text form
     "onCheckedClick-params"?: List<string>; // parameter list for onChecked treeview functions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 7a06e1bc1..ad8336e8a 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -413,7 +413,7 @@ export class CurrentUserUtils {
             { title: "Drag a presentation view", label: "Prezi", icon: "tv", click: 'openOnRight(Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().activePresentation = getCopy(this.dragFactory,true)`, dragFactory: doc.emptyPresentation as Doc },
             { title: "Drag a search box", label: "Query", icon: "search", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' },
             { title: "Drag a scripting box", label: "Script", icon: "terminal", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyScript as Doc },
-            // { title: "Drag an import folder", label: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' },
+            { title: "Drag an import folder", label: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' },
             { title: "Drag a mobile view", label: "Phone", icon: "mobile", click: 'openOnRight(Doc.UserDoc().activeMobileMenu)', drag: 'this.dragFactory', dragFactory: doc.activeMobileMenu as Doc },
             // { title: "Drag an instance of the device collection", label: "Buxton", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.Buxton()' },
             // { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this)', backgroundColor: "blue", ischecked: `sameDocs(this.activeInkPen,  this)`, activeInkPen: doc },
@@ -775,17 +775,17 @@ export class CurrentUserUtils {
 
     static setupClickEditorTemplates(doc: Doc) {
         if (doc["clickFuncs-child"] === undefined) {
+            // to use this function, select it from the context menu of a collection.  then edit the onChildClick script.  Add two Doc variables: 'target' and 'thisContainer', then assign 'target' to some target collection.  After that, clicking on any document in the initial collection will open it in the target 
             const openInTarget = Docs.Create.ScriptingDocument(ScriptField.MakeScript(
-                "docCast(thisContainer.target).then((target) => {" +
-                "     target && docCast(this.source).then((source) => { " +
-                "           target.proto.data = new List([source || this]); " +
-                "      }); " +
-                "})",
-                { target: Doc.name }), { title: "Click to open in target", _width: 300, _height: 200, targetScriptKey: "onChildClick" });
+                "docCast(thisContainer.target).then((target) => target && (target.proto.data = new List([self]))) ",
+                { thisContainer: Doc.name }), {
+                title: "Click to open in target", _width: 300, _height: 200,
+                targetScriptKey: "onChildClick",
+            });
 
             const openDetail = Docs.Create.ScriptingDocument(ScriptField.MakeScript(
                 "openOnRight(self.doubleClickView)",
-                { target: Doc.name }), { title: "Double click to open doubleClickView", _width: 300, _height: 200, targetScriptKey: "onChildDoubleClick" });
+                {}), { title: "Double click to open doubleClickView", _width: 300, _height: 200, targetScriptKey: "onChildDoubleClick" });
 
             doc["clickFuncs-child"] = Docs.Create.TreeDocument([openInTarget, openDetail], { title: "on Child Click function templates" });
         }
@@ -797,14 +797,22 @@ export class CurrentUserUtils {
                 title: "onClick", "onClick-rawScript": "console.log('click')",
                 isTemplateDoc: true, isTemplateForField: "onClick", _width: 300, _height: 200
             }, "onClick");
+            const onChildClick = Docs.Create.ScriptingDocument(undefined, {
+                title: "onChildClick", "onChildClick-rawScript": "console.log('child click')",
+                isTemplateDoc: true, isTemplateForField: "onChildClick", _width: 300, _height: 200
+            }, "onChildClick");
             const onDoubleClick = Docs.Create.ScriptingDocument(undefined, {
                 title: "onDoubleClick", "onDoubleClick-rawScript": "console.log('double click')",
                 isTemplateDoc: true, isTemplateForField: "onDoubleClick", _width: 300, _height: 200
             }, "onDoubleClick");
+            const onChildDoubleClick = Docs.Create.ScriptingDocument(undefined, {
+                title: "onChildDoubleClick", "onChildDoubleClick-rawScript": "console.log('child double click')",
+                isTemplateDoc: true, isTemplateForField: "onChildDoubleClick", _width: 300, _height: 200
+            }, "onChildDoubleClick");
             const onCheckedClick = Docs.Create.ScriptingDocument(undefined, {
                 title: "onCheckedClick", "onCheckedClick-rawScript": "console.log(heading + checked + containingTreeView)", "onCheckedClick-params": new List<string>(["heading", "checked", "containingTreeView"]), isTemplateDoc: true, isTemplateForField: "onCheckedClick", _width: 300, _height: 200
             }, "onCheckedClick");
-            doc.clickFuncs = Docs.Create.TreeDocument([onClick, onDoubleClick, onCheckedClick], { title: "onClick funcs" });
+            doc.clickFuncs = Docs.Create.TreeDocument([onClick, onChildClick, onDoubleClick, onCheckedClick], { title: "onClick funcs" });
         }
         PromiseValue(Cast(doc.clickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast));
 
diff --git a/src/client/views/OverlayView.scss b/src/client/views/OverlayView.scss
index 26c2e0e1e..09a349012 100644
--- a/src/client/views/OverlayView.scss
+++ b/src/client/views/OverlayView.scss
@@ -3,6 +3,8 @@
     overflow: hidden;
     display: flex;
     flex-direction: column;
+    top: 0;
+    left: 0;
 }
 
 .overlayWindow-outerDiv,
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 916e631d0..9fb8a227e 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -108,8 +108,9 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
 
     return100 = () => 100;
     @computed get scriptField() {
-        return ScriptField.MakeScript("docs.map(d => switchView(d, this))", { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name, firstDoc: Doc.name },
+        const script = ScriptField.MakeScript("docs.map(d => switchView(d, this))", { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name, firstDoc: Doc.name },
             { docs: new List<Doc>(this.props.docViews.map(dv => dv.props.Document)) });
+        return script ? () => script : undefined;
     }
     templateIsUsed = (selDoc: Doc, templateDoc: Doc) => {
         const template = StrCast(templateDoc.dragFactory ? Cast(templateDoc.dragFactory, Doc, null)?.title : templateDoc.title);
@@ -142,8 +143,8 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                 ContainingCollectionView={undefined}
                 docFilters={returnEmptyFilter}
                 rootSelected={returnFalse}
-                onCheckedClick={this.scriptField!}
-                onChildClick={this.scriptField!}
+                onCheckedClick={this.scriptField}
+                onChildClick={this.scriptField}
                 LibraryPath={emptyPath}
                 dropAction={undefined}
                 active={returnTrue}
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index 8f1cd5311..8e9970ada 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -38,15 +38,15 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume
 
     panelWidth = () => this.props.PanelWidth() / 3;
     panelHeight = () => this.props.PanelHeight() * 0.6;
+    onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick);
     @computed get content() {
         const currentIndex = NumCast(this.layoutDoc._itemIndex);
         const displayDoc = (childPair: { layout: Doc, data: Doc }) => {
+            const script = ScriptField.MakeScript("child._showCaption = 'caption'", { child: Doc.name }, { child: childPair.layout });
+            const onChildClick = script && (() => script);
             return <ContentFittingDocumentView {...this.props}
-                onDoubleClick={ScriptCast(this.layoutDoc.onChildDoubleClick)}
-                onClick={ScriptField.MakeScript(
-                    "child._showCaption = 'caption'",
-                    { child: Doc.name },
-                    { child: childPair.layout })}
+                onDoubleClick={this.onChildDoubleClick}
+                onClick={onChildClick}
                 renderDepth={this.props.renderDepth + 1}
                 LayoutTemplate={this.props.ChildLayoutTemplate}
                 LayoutTemplateString={this.props.ChildLayoutString}
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index b3fecfb91..404dc0daa 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -14,6 +14,7 @@ import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
 import { ContextMenu } from '../ContextMenu';
 import { ObjectField } from '../../../fields/ObjectField';
 import { returnFalse } from '../../../Utils';
+import { ScriptField } from '../../../fields/ScriptField';
 
 type CarouselDocument = makeInterface<[typeof documentSchema, typeof collectionSchema]>;
 const CarouselDocument = makeInterface(documentSchema, collectionSchema);
@@ -40,14 +41,16 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
         this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length;
     }
     panelHeight = () => this.props.PanelHeight() - 50;
+    onContentDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick);
+    onContentClick = () => ScriptCast(this.layoutDoc.onChildClick);
     @computed get content() {
         const index = NumCast(this.layoutDoc._itemIndex);
         return !(this.childLayoutPairs?.[index]?.layout instanceof Doc) ? (null) :
             <>
                 <div className="collectionCarouselView-image" key="image">
                     <ContentFittingDocumentView {...this.props}
-                        onDoubleClick={ScriptCast(this.layoutDoc.onChildDoubleClick)}
-                        onClick={ScriptCast(this.layoutDoc.onChildClick)}
+                        onDoubleClick={this.onContentDoubleClick}
+                        onClick={this.onContentClick}
                         renderDepth={this.props.renderDepth + 1}
                         LayoutTemplate={this.props.ChildLayoutTemplate}
                         LayoutTemplateString={this.props.ChildLayoutString}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 9d8790dda..838e1f664 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -163,8 +163,8 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
         this.createDashEventsTarget(ele!); //so the whole grid is the drop target?
     }
 
-    @computed get onChildClickHandler() { return this.props.childClickScript || ScriptCast(this.Document.onChildClick); }
-    @computed get onChildDoubleClickHandler() { return this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); }
+    @computed get onChildClickHandler() { return () => this.props.childClickScript || ScriptCast(this.Document.onChildClick); }
+    @computed get onChildDoubleClickHandler() { return () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); }
 
     addDocTab = (doc: Doc, where: string) => {
         if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index dbd39d8df..8438248ad 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -61,8 +61,8 @@ export interface TreeViewProps {
     treeViewHideHeaderFields: () => boolean;
     treeViewPreventOpen: boolean;
     renderedIds: string[]; // list of document ids rendered used to avoid unending expansion of items in a cycle
-    onCheckedClick?: ScriptField;
-    onChildClick?: ScriptField;
+    onCheckedClick?: () => ScriptField;
+    onChildClick?: () => ScriptField;
     ignoreFields?: string[];
 }
 
@@ -76,7 +76,7 @@ export interface TreeViewProps {
  * treeViewExpandedView : name of field whose contents are being displayed as the document's subtree
  */
 class TreeView extends React.Component<TreeViewProps> {
-    private _editTitleScript: ScriptField | undefined;
+    private _editTitleScript: (() => ScriptField) | undefined;
     private _header?: React.RefObject<HTMLDivElement> = React.createRef();
     private _treedropDisposer?: DragManager.DragDropDisposer;
     private _dref = React.createRef<HTMLDivElement>();
@@ -124,7 +124,8 @@ class TreeView extends React.Component<TreeViewProps> {
 
     constructor(props: any) {
         super(props);
-        this._editTitleScript = ScriptField.MakeScript(`{setInPlace(self, 'editTitle', '${this._uniqueId}'); selectDoc(self);} `);
+        const script = ScriptField.MakeScript(`{setInPlace(self, 'editTitle', '${this._uniqueId}'); selectDoc(self);} `);
+        this._editTitleScript = script && (() => script);
         if (Doc.GetT(this.doc, "editTitle", "string", true) === "*") Doc.SetInPlace(this.doc, "editTitle", this._uniqueId, false);
     }
 
@@ -368,13 +369,13 @@ class TreeView extends React.Component<TreeViewProps> {
         }
     }
 
-    get onCheckedClick() { return this.props.onCheckedClick || ScriptCast(this.doc.onCheckedClick); }
+    get onCheckedClick() { return this.props.onCheckedClick || (() => ScriptCast(this.doc.onCheckedClick)); }
 
     @action
     bulletClick = (e: React.MouseEvent) => {
-        if (this.onCheckedClick && this.doc.type !== DocumentType.COL) {
+        if (this.onCheckedClick() && this.doc.type !== DocumentType.COL) {
             // this.props.document.treeViewChecked = this.props.document.treeViewChecked === "check" ? "x" : this.props.document.treeViewChecked === "x" ? undefined : "check";
-            this.onCheckedClick.script.run({
+            this.onCheckedClick()?.script.run({
                 this: this.doc.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.doc,
                 heading: this.props.containingCollection.title,
                 checked: this.doc.treeViewChecked === "check" ? "x" : this.doc.treeViewChecked === "x" ? undefined : "check",
@@ -388,7 +389,7 @@ class TreeView extends React.Component<TreeViewProps> {
 
     @computed get renderBullet() {
         TraceMobx();
-        const checked = this.doc.type === DocumentType.COL ? undefined : this.onCheckedClick ? (this.doc.treeViewChecked ?? "unchecked") : undefined;
+        const checked = this.doc.type === DocumentType.COL ? undefined : this.onCheckedClick() ? (this.doc.treeViewChecked ?? "unchecked") : undefined;
         return <div className="bullet"
             title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : "view fields"}
             onClick={this.bulletClick}
@@ -539,8 +540,8 @@ class TreeView extends React.Component<TreeViewProps> {
         treeViewPreventOpen: boolean,
         renderedIds: string[],
         libraryPath: Doc[] | undefined,
-        onCheckedClick: ScriptField | undefined,
-        onChildClick: ScriptField | undefined,
+        onCheckedClick?: () => ScriptField,
+        onChildClick?: () => ScriptField,
         ignoreFields: string[] | undefined
     ) {
         const viewSpecScript = Cast(containingCollection.viewSpecScript, ScriptField);
@@ -658,8 +659,8 @@ class TreeView extends React.Component<TreeViewProps> {
 export type collectionTreeViewProps = {
     treeViewHideTitle?: boolean;
     treeViewHideHeaderFields?: boolean;
-    onCheckedClick?: ScriptField;
-    onChildClick?: ScriptField;
+    onCheckedClick?: () => ScriptField;
+    onChildClick?: () => ScriptField;
 };
 
 @observer
@@ -797,6 +798,9 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
     onKeyPress = (e: React.KeyboardEvent) => {
         console.log(e);
     }
+    onChildClick = () => {
+        return this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick);
+    }
     render() {
         TraceMobx();
         if (!(this.doc instanceof Doc)) return (null);
@@ -839,7 +843,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
                                 moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform,
                                 this.outerXf, this.props.active, this.props.PanelWidth, this.props.ChromeHeight, this.props.renderDepth, () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeViewHideHeaderFields),
                                 BoolCast(this.doc.treeViewPreventOpen), [], this.props.LibraryPath, this.props.onCheckedClick,
-                                this.props.onChildClick || ScriptCast(this.doc.onChildClick), this.props.ignoreFields)
+                                this.onChildClick, this.props.ignoreFields)
                         }
                     </ul>
                 </div >
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index cbd1ac9af..5165a8f11 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -305,14 +305,16 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                 { key: "onChildDoubleClick", name: "On Child Double Clicked" }];
             funcs.map(func => onClicks.push({
                 description: `Edit ${func.name} script`, icon: "edit", event: (obj: any) => {
-                    ScriptBox.EditButtonScript(func.name + "...", this.props.Document, func.key, obj.x, obj.y, { thisContainer: Doc.name });
+                    const alias = Doc.MakeAlias(this.props.Document);
+                    DocUtils.makeCustomViewClicked(alias, undefined, func.key);
+                    this.props.addDocTab(alias, "onRight");
                 }
             }));
             DocListCast(Cast(Doc.UserDoc()["clickFuncs-child"], Doc, null).data).forEach(childClick =>
                 onClicks.push({
                     description: `Set child ${childClick.title}`,
                     icon: "edit",
-                    event: () => this.props.Document[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)),
+                    event: () => Doc.GetProto(this.props.Document)[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)),
                 }));
             !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "hand-point-right" });
 
@@ -470,7 +472,8 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
     get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; } // this makes the tree view collection ignore these filters (otherwise, the filters would filter themselves)
     @computed get scriptField() {
         const scriptText = "setDocFilter(containingTreeView, heading, this.title, checked)";
-        return ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name });
+        const script = ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name });
+        return script ? () => script : undefined;
     }
     @computed get filterView() {
         TraceMobx();
@@ -523,7 +526,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
                         ContentScaling={returnOne}
                         focus={returnFalse}
                         treeViewHideHeaderFields={true}
-                        onCheckedClick={this.scriptField!}
+                        onCheckedClick={this.scriptField}
                         ignoreFields={this.ignoreFields}
                         annotationsKey={""}
                         dontRegisterView={true}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index ef6ea8f99..1d23d92bf 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -46,6 +46,7 @@ import "./CollectionFreeFormView.scss";
 import MarqueeOptionsMenu from "./MarqueeOptionsMenu";
 import { MarqueeView } from "./MarqueeView";
 import React = require("react");
+import { AnyAaaaRecord } from "dns";
 
 library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload);
 
@@ -939,8 +940,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
     }
 
     @computed get libraryPath() { return this.props.LibraryPath ? [...this.props.LibraryPath, this.props.Document] : []; }
-    @computed get onChildClickHandler() { return this.props.childClickScript || ScriptCast(this.Document.onChildClick); }
-    @computed get onChildDoubleClickHandler() { return this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); }
+    @computed get onChildClickHandler() { return () => (this.props.childClickScript || ScriptCast(this.Document.onChildClick)); }
+    @computed get onChildDoubleClickHandler() { return () => (this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick)); }
     @computed get backgroundActive() { return this.layoutDoc.isBackground && (this.props.ContainingCollectionView?.active() || this.props.active()); }
     backgroundHalo = () => BoolCast(this.Document.useClusters);
     parentActive = (outsideReaction: boolean) => this.props.active(outsideReaction) || this.backgroundActive ? true : false;
@@ -1151,7 +1152,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             (elements) => this._layoutElements = elements || [],
             { fireImmediately: true, name: "doLayout" });
 
-        const handler = (e: Event) => this.handleDragging(e, (e as CustomEvent<DragEvent>).detail);
+        const handler = (e: any) => this.handleDragging(e, (e as CustomEvent<DragEvent>).detail);
 
         document.addEventListener("dashDragging", handler);
     }
@@ -1159,7 +1160,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
     componentWillUnmount() {
         this._layoutComputeReaction?.();
 
-        const handler = (e: Event) => this.handleDragging(e, (e as CustomEvent<DragEvent>).detail);
+        const handler = (e: any) => this.handleDragging(e, (e as CustomEvent<DragEvent>).detail);
         document.removeEventListener("dashDragging", handler);
     }
 
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index 188b88c41..b2e506dfa 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -31,7 +31,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) {
     @observable private _rowHeight: Opt<number>; // temporary store of row height to make change undoable
     @observable private _scroll: number = 0; // required to make sure the decorations box container updates on scroll
 
-    @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
+    @computed get onChildClickHandler() { return () => ScriptCast(this.Document.onChildClick); }
 
     @computed get numCols() { return NumCast(this.props.Document.gridNumCols, 10); }
     @computed get rowHeight() { return this._rowHeight === undefined ? NumCast(this.props.Document.gridRowHeight, 100) : this._rowHeight; }
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index cd25c21b4..402e7563d 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -202,8 +202,8 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
     }
 
 
-    @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
-    @computed get onChildDoubleClickHandler() { return ScriptCast(this.Document.onChildDoubleClick); }
+    @computed get onChildClickHandler() { return () => ScriptCast(this.Document.onChildClick); }
+    @computed get onChildDoubleClickHandler() { return () => ScriptCast(this.Document.onChildDoubleClick); }
 
 
     addDocTab = (doc: Doc, where: string) => {
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 51dcdcfe6..e4ef9b436 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -202,8 +202,8 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
     }
 
 
-    @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
-    @computed get onChildDoubleClickHandler() { return ScriptCast(this.Document.onChildDoubleClick); }
+    @computed get onChildClickHandler() { return () => ScriptCast(this.Document.onChildClick); }
+    @computed get onChildDoubleClickHandler() { return () => ScriptCast(this.Document.onChildDoubleClick); }
 
     addDocTab = (doc: Doc, where: string) => {
         if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 11be4c2e7..e338d5203 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -11,7 +11,7 @@ import { InkTool } from '../../../fields/InkField';
 import { listSpec } from "../../../fields/Schema";
 import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
 import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
+import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from "../../../fields/Types";
 import { TraceMobx } from '../../../fields/util';
 import { GestureUtils } from '../../../pen-gestures/GestureUtils';
 import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils, emptyPath } from "../../../Utils";
@@ -68,10 +68,10 @@ export interface DocumentViewProps {
     ignoreAutoHeight?: boolean;
     contextMenuItems?: () => { script: ScriptField, label: string }[];
     rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected
-    onClick?: ScriptField;
-    onDoubleClick?: ScriptField;
-    onPointerDown?: ScriptField;
-    onPointerUp?: ScriptField;
+    onClick?: () => ScriptField;
+    onDoubleClick?: () => ScriptField;
+    onPointerDown?: () => ScriptField;
+    onPointerUp?: () => ScriptField;
     treeViewDoc?: Doc;
     dropAction?: dropActionType;
     dragDivName?: string;
@@ -127,10 +127,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     @computed get freezeDimensions() { return this.props.FreezeDimensions; }
     @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
     @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
-    @computed get onClickHandler() { return this.props.onClick || Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null)); }
-    @computed get onDoubleClickHandler() { return this.props.onDoubleClick || Cast(this.layoutDoc.onDoubleClick, ScriptField, null) || this.Document.onDoubleClick; }
-    @computed get onPointerDownHandler() { return this.props.onPointerDown ? this.props.onPointerDown : this.Document.onPointerDown; }
-    @computed get onPointerUpHandler() { return this.props.onPointerUp ? this.props.onPointerUp : this.Document.onPointerUp; }
+    @computed get onClickHandler() { return this.props.onClick?.() ? this.props.onClick : (() => Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null))); }
+    @computed get onDoubleClickHandler() { return this.props.onDoubleClick?.() ? this.props.onDoubleClick : () => (Cast(this.layoutDoc.onDoubleClick, ScriptField, null) || this.Document.onDoubleClick); }
+    @computed get onPointerDownHandler() { return this.props.onPointerDown?.() ? this.props.onPointerDown : () => ScriptCast(this.Document.onPointerDown) }
+    @computed get onPointerUpHandler() { return this.props.onPointerUp ?? (() => ScriptCast(this.Document.onPointerUp)); }
     NativeWidth = () => this.nativeWidth;
     NativeHeight = () => this.nativeHeight;
 
@@ -293,10 +293,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             let stopPropagate = true;
             let preventDefault = true;
             !this.props.Document.isBackground && this.props.bringToFront(this.props.Document);
-            if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
+            if (this._doubleTap && this.props.renderDepth && !this.onClickHandler()?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
                 if (!(e.nativeEvent as any).formattedHandled) {
-                    if (this.onDoubleClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself
-                        const func = () => this.onDoubleClickHandler.script.run({
+                    if (this.onDoubleClickHandler()?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself
+                        const func = () => this.onDoubleClickHandler()?.script.run({
                             this: this.layoutDoc,
                             self: this.rootDoc,
                             thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey
@@ -316,9 +316,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                         Doc.UnBrushDoc(this.props.Document);
                     }
                 }
-            } else if (this.onClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself
+            } else if (this.onClickHandler()?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself
                 //SelectionManager.DeselectAll();
-                const func = () => this.onClickHandler.script.run({
+                const func = () => this.onClickHandler()?.script.run({
                     this: this.layoutDoc,
                     self: this.rootDoc,
                     thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey
@@ -553,8 +553,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     onPointerUp = (e: PointerEvent): void => {
         this.cleanUpInteractions();
 
-        if (this.onPointerUpHandler?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
-            this.onPointerUpHandler.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log);
+        if (this.onPointerUpHandler()?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
+            this.onPointerUpHandler()?.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log);
             document.removeEventListener("pointerup", this.onPointerUp);
             return;
         }
diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts
index 61a37ef8a..9dda644f3 100644
--- a/src/fields/documentSchemas.ts
+++ b/src/fields/documentSchemas.ts
@@ -3,7 +3,6 @@ import { ScriptField } from "./ScriptField";
 import { Doc } from "./Doc";
 import { DateField } from "./DateField";
 import { SchemaHeaderField } from "./SchemaHeaderField";
-import { Schema } from "prosemirror-model";
 
 export const documentSchema = createSchema({
     // content properties
-- 
cgit v1.2.3-70-g09d2


From d97a4f470456a89597017d643bf5139a2f8ef3e0 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 14 Jul 2020 15:00:54 -0400
Subject: possible fix for dragging icons problem caused by setisdragging
 invalidating the dragged element

---
 src/client/util/DragManager.ts                      | 2 +-
 src/client/views/collections/CollectionTreeView.tsx | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

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

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 5f34509a1..40467abaf 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -330,7 +330,6 @@ export namespace DragManager {
             DragManager.Root().appendChild(dragDiv);
         }
         dragLabel.style.display = "";
-        SnappingManager.SetIsDragging(true);
         const scaleXs: number[] = [];
         const scaleYs: number[] = [];
         const xs: number[] = [];
@@ -394,6 +393,7 @@ export namespace DragManager {
                 set[i].hasAttribute("style") && ((set[i] as any).style.pointerEvents = "none");
             }
 
+            SnappingManager.SetIsDragging(true);
             dragDiv.appendChild(dragElement);
             return dragElement;
         });
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 8438248ad..eb355fa2b 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -405,6 +405,7 @@ class TreeView extends React.Component<TreeViewProps> {
     contextMenuItems = () => [{ script: ScriptField.MakeFunction(`DocFocus(self)`)!, label: "Focus" }];
     truncateTitleWidth = () => NumCast(this.props.treeViewDoc.treeViewTruncateTitleWidth, 0);
     showTitleEdit = () => ["*", this._uniqueId].includes(Doc.GetT(this.doc, "editTitle", "string", true) || "");
+    onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.editTitleScript));
     /**
      * Renders the EditableView title element for placement into the tree.
      */
@@ -438,7 +439,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 addDocTab={this.props.addDocTab}
                 rootSelected={returnTrue}
                 pinToPres={emptyFunction}
-                onClick={this.props.onChildClick || this._editTitleScript}
+                onClick={this.onChildClick}
                 dropAction={this.props.dropAction}
                 moveDocument={this.move}
                 removeDocument={this.removeDoc}
-- 
cgit v1.2.3-70-g09d2


From 8db52ec4cabe3a7f8568cfc7547cfd87e3aa0ae7 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 14 Jul 2020 15:48:15 -0400
Subject: from last

---
 src/client/views/collections/CollectionTreeView.tsx | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

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

diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index eb355fa2b..96a2e23c9 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -369,13 +369,13 @@ class TreeView extends React.Component<TreeViewProps> {
         }
     }
 
-    get onCheckedClick() { return this.props.onCheckedClick || (() => ScriptCast(this.doc.onCheckedClick)); }
+    get onCheckedClick() { return this.props.onCheckedClick?.() ?? ScriptCast(this.doc.onCheckedClick); }
 
     @action
     bulletClick = (e: React.MouseEvent) => {
-        if (this.onCheckedClick() && this.doc.type !== DocumentType.COL) {
+        if (this.onCheckedClick && this.doc.type !== DocumentType.COL) {
             // this.props.document.treeViewChecked = this.props.document.treeViewChecked === "check" ? "x" : this.props.document.treeViewChecked === "x" ? undefined : "check";
-            this.onCheckedClick()?.script.run({
+            this.onCheckedClick?.script.run({
                 this: this.doc.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.doc,
                 heading: this.props.containingCollection.title,
                 checked: this.doc.treeViewChecked === "check" ? "x" : this.doc.treeViewChecked === "x" ? undefined : "check",
@@ -389,7 +389,7 @@ class TreeView extends React.Component<TreeViewProps> {
 
     @computed get renderBullet() {
         TraceMobx();
-        const checked = this.doc.type === DocumentType.COL ? undefined : this.onCheckedClick() ? (this.doc.treeViewChecked ?? "unchecked") : undefined;
+        const checked = this.doc.type === DocumentType.COL ? undefined : this.onCheckedClick ? (this.doc.treeViewChecked ?? "unchecked") : undefined;
         return <div className="bullet"
             title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : "view fields"}
             onClick={this.bulletClick}
@@ -541,8 +541,8 @@ class TreeView extends React.Component<TreeViewProps> {
         treeViewPreventOpen: boolean,
         renderedIds: string[],
         libraryPath: Doc[] | undefined,
-        onCheckedClick?: () => ScriptField,
-        onChildClick?: () => ScriptField,
+        onCheckedClick: undefined | (() => ScriptField),
+        onChildClick: undefined | (() => ScriptField),
         ignoreFields: string[] | undefined
     ) {
         const viewSpecScript = Cast(containingCollection.viewSpecScript, ScriptField);
-- 
cgit v1.2.3-70-g09d2

