From fa6aa3f3d13cade1cd46d954dbfee6f8566bcc86 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 29 Mar 2021 13:20:14 -0400
Subject: initial changes to cleanup pointer events.

---
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

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

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f0d99611a..eca655099 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -67,7 +67,6 @@ export const panZoomSchema = createSchema({
 type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof collectionSchema, typeof documentSchema, typeof pageSchema]>;
 const PanZoomDocument = makeInterface(panZoomSchema, collectionSchema, documentSchema, pageSchema);
 export type collectionFreeformViewProps = {
-    parentActive: (outsideReaction: boolean) => boolean;
     annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox)
     viewDefDivClick?: ScriptField;
     childPointerEvents?: boolean;
@@ -152,7 +151,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
     getKeyFrameEditing = () => this._keyframeEditing;
     onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick);
     onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
-    parentActive = (outsideReaction: boolean) => this.props.active(outsideReaction) || this.props.parentActive?.(outsideReaction) || this.backgroundActive || this.layoutDoc._viewType === CollectionViewType.Pile ? true : false;
     elementFunc = () => this._layoutElements;
     shrinkWrap = () => {
         const vals = this.fitToContentVals;
@@ -1036,8 +1034,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             removeDocument={this.props.removeDocument}
             moveDocument={this.props.moveDocument}
             pinToPres={this.props.pinToPres}
-            whenActiveChanged={this.props.whenActiveChanged}
-            parentActive={this.parentActive}
+            whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
             docViewPath={this.props.docViewPath}
             styleProvider={this.getClusterColor}
             layerProvider={this.props.layerProvider}
@@ -1046,6 +1043,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             freezeDimensions={this.props.childFreezeDimensions}
             dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             bringToFront={this.bringToFront}
+            documentActive={() => this.props.active()}
             dontRegisterView={this.props.dontRegisterView}
             pointerEvents={this.backgroundActive || this.props.childPointerEvents ? "all" :
                 (this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? "none" : undefined}
-- 
cgit v1.2.3-70-g09d2


From 7db0fe589afa3281894afb0a0d3bd6b9983c9d33 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 29 Mar 2021 19:04:08 -0400
Subject: still cleaning up all the active/selection code.

---
 src/client/documents/Documents.ts                  |   5 +-
 src/client/util/DragManager.ts                     |   7 +-
 src/client/views/DocComponent.tsx                  |  58 +++++--
 src/client/views/MainView.tsx                      |   8 +-
 src/client/views/SidebarAnnos.tsx                  |   4 +-
 src/client/views/TemplateMenu.tsx                  |   2 +-
 .../views/collections/CollectionCarousel3DView.tsx |   2 +-
 src/client/views/collections/CollectionMapView.tsx |   2 +-
 .../collections/CollectionMasonryViewFieldRow.tsx  |   2 +-
 .../views/collections/CollectionSchemaView.tsx     |  14 +-
 .../collections/CollectionStackedTimeline.tsx      |   2 +-
 .../views/collections/CollectionStackingView.tsx   |   4 +-
 .../views/collections/CollectionTimeView.tsx       |   2 +-
 .../views/collections/CollectionTreeView.tsx       |   4 +-
 src/client/views/collections/CollectionView.tsx    | 190 +++++----------------
 src/client/views/collections/TabDocView.tsx        |   2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  16 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |   2 +-
 .../collectionGrid/CollectionGridView.tsx          |   4 +-
 src/client/views/nodes/AudioBox.tsx                |  14 +-
 src/client/views/nodes/ComparisonBox.tsx           |   6 +-
 src/client/views/nodes/DocumentContentsView.tsx    |   1 +
 src/client/views/nodes/DocumentView.tsx            |  17 +-
 src/client/views/nodes/FieldView.tsx               |   2 +-
 src/client/views/nodes/FilterBox.tsx               |   2 +-
 src/client/views/nodes/ImageBox.tsx                |   8 +-
 src/client/views/nodes/KeyValuePair.tsx            |   2 +-
 src/client/views/nodes/PDFBox.tsx                  |  16 +-
 src/client/views/nodes/PresBox.tsx                 |   3 +-
 src/client/views/nodes/ScreenshotBox.tsx           |   8 +-
 src/client/views/nodes/ScriptingBox.tsx            |   4 +-
 src/client/views/nodes/VideoBox.tsx                |  20 +--
 src/client/views/nodes/WebBox.tsx                  |  16 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  14 +-
 src/client/views/pdf/PDFViewer.tsx                 |  12 +-
 src/fields/util.ts                                 |   2 +-
 36 files changed, 206 insertions(+), 271 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 9406b374e..81fb204de 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1322,7 +1322,10 @@ export namespace DocUtils {
     export function LeavePushpin(doc: Doc) {
         if (doc.isPushpin) return undefined;
         const context = Cast(doc.context, Doc, null) ?? Cast(doc.annotationOn, Doc, null);
-        const hasContextAnchor = DocListCast(doc.links).some(l => (l.anchor2 === doc && Cast(l.anchor1, Doc, null)?.annotationOn === context) || (l.anchor1 === doc && Cast(l.anchor2, Doc, null)?.annotationOn === context));
+        const hasContextAnchor = DocListCast(doc.links).
+            some(l =>
+                (l.anchor2 === doc && Cast(l.anchor1, Doc, null)?.annotationOn === context) ||
+                (l.anchor1 === doc && Cast(l.anchor2, Doc, null)?.annotationOn === context));
         if (context && !hasContextAnchor && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG)) {
             const pushpin = Docs.Create.FontIconDocument({
                 title: "pushpin", label: "", annotationOn: Cast(doc.annotationOn, Doc, null), isPushpin: true,
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 38d0ecaa6..abf1af669 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -379,7 +379,12 @@ export namespace DragManager {
             if (docsBeingDragged.length) {
                 const pdfBox = dragElement.getElementsByTagName("canvas");
                 const pdfBoxSrc = ele.getElementsByTagName("canvas");
-                Array.from(pdfBox).map((pb, i) => pb.getContext('2d')!.drawImage(pdfBoxSrc[i], 0, 0));
+                Array.from(pdfBox).filter(pb => pb.width && pb.height).map((pb, i) => {
+                    const context = pb.getContext('2d')!;
+                    console.log(getComputedStyle(pb).width);
+                    console.log(getComputedStyle(pdfBoxSrc[i]).width);
+                    context.drawImage(pdfBoxSrc[i], 0, 0);
+                });
             }
             [dragElement, ...Array.from(dragElement.getElementsByTagName('*'))].forEach(ele =>
                 ele.hasAttribute("style") && ((ele as any).style.pointerEvents = "none"));
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 3f6715560..5c0fe6b97 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -10,6 +10,8 @@ import { ScriptField } from '../../fields/ScriptField';
 import { GetEffectiveAcl, SharingPermissions, distributeAcls, denormalizeEmail } from '../../fields/util';
 import { CurrentUserUtils } from '../util/CurrentUserUtils';
 import { DocUtils } from '../documents/Documents';
+import { returnFalse } from '../../Utils';
+import { UndoManager } from '../util/UndoManager';
 
 
 ///  DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView)
@@ -34,7 +36,7 @@ export function DocComponent<P extends DocComponentProps, T>(schemaCtor: (doc: D
     return Component;
 }
 
-/// FieldViewBoxProps  -  a generic base class for field views that are not annotatable (e.g. AudioBox, FormattedTextBox)
+/// FieldViewBoxProps  -  a generic base class for field views that are not annotatable (e.g. InkingStroke, ColorBox)
 interface ViewBoxBaseProps {
     Document: Doc;
     DataDoc?: Doc;
@@ -74,22 +76,23 @@ export interface ViewBoxAnnotatableProps {
     Document: Doc;
     DataDoc?: Doc;
     fieldKey: string;
-    layerProvider?: (doc: Doc) => boolean;
-    active: () => boolean;
+    filterAddDocument?: (doc: Doc[]) => boolean;  // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
+    layerProvider?: (doc: Doc, assign?: boolean) => boolean;
+    isContentActive: () => boolean;
     select: (isCtrlPressed: boolean) => void;
     whenChildContentsActiveChanged: (isActive: boolean) => void;
     isSelected: (outsideReaction?: boolean) => boolean;
     rootSelected: (outsideReaction?: boolean) => boolean;
     renderDepth: number;
+    isAnnotationOverlay?: boolean;
 }
-export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T>(schemaCtor: (doc: Doc) => T) {
+export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T>(schemaCtor: (doc: Doc) => T, _annotationKey: string = "annotations") {
     class Component extends Touchable<P> {
-        @observable _annotationKey: string = "annotations";
+        @observable _annotationKey: string = _annotationKey;
 
         @observable _isAnyChildContentActive = false;
         //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
         @computed get Document(): T { return schemaCtor(this.props.Document); }
-
         // This is the "The Document" -- it encapsulates, data, layout, and any templates
         @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; }
         // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info
@@ -125,7 +128,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
 
         protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
 
-        @computed public get annotationKey() { return this.fieldKey + "-" + this._annotationKey; }
+        @computed public get annotationKey() { return this.fieldKey + (this._annotationKey ? "-" + this._annotationKey : ""); }
 
         @action.bound
         removeDocument(doc: Doc | Doc[], annotationKey?: string, leavePushpin?: boolean): boolean {
@@ -156,16 +159,28 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
 
             return false;
         }
-        // if the moved document is already in this overlay collection nothing needs to be done.
-        // otherwise, if the document can be removed from where it was, it will then be added to this document's overlay collection. 
+        // this is called with the document that was dragged and the collection to move it into.
+        // if the target collection is the same as this collection, then the move will be allowed.
+        // otherwise, the document being moved must be able to be removed from its container before
+        // moving it into the target.
         @action.bound
-        moveDocument(doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean, annotationKey?: string): boolean {
-            return Doc.AreProtosEqual(this.props.Document, targetCollection) ? true : this.removeDocument(doc, annotationKey, true) ? addDocument(doc) : false;
+        moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean, annotationKey?: string): boolean => {
+            if (Doc.AreProtosEqual(this.props.Document, targetCollection)) {
+                return true;
+            }
+            const first = doc instanceof Doc ? doc : doc[0];
+            if (!first?._stayInCollection && addDocument !== returnFalse) {
+                return UndoManager.RunInTempBatch(() => this.removeDocument(doc, annotationKey, true) && addDocument(doc));
+            }
+            return false;
         }
         @action.bound
         addDocument(doc: Doc | Doc[], annotationKey?: string): boolean {
             const docs = doc instanceof Doc ? [doc] : doc;
-            docs.map(doc => doc.context = Doc.GetProto(doc).annotationOn = this.props.Document);
+            if (this.props.filterAddDocument?.(docs) === false ||
+                docs.find(doc => Doc.AreProtosEqual(doc, this.props.Document))) {
+                return false;
+            }
             const targetDataDoc = this.props.Document[DataSym];
             const docList = DocListCast(targetDataDoc[annotationKey ?? this.annotationKey]);
             const added = docs.filter(d => !docList.includes(d));
@@ -187,10 +202,21 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
                     }
 
                     if (effectiveAcl === AclAddonly) {
-                        added.map(doc => Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc));
+                        added.map(doc => {
+                            this.props.layerProvider?.(doc, true);
+                            Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
+                            doc.context = this.props.Document;
+                            if (annotationKey ?? this._annotationKey) Doc.GetProto(doc).annotationOn = this.props.Document;
+                        });
                     }
                     else {
-                        added.map(doc => doc.context = this.props.Document);
+                        added.filter(doc => [AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))).map(doc => {  // only make a pushpin if we have acl's to edit the document
+                            this.props.layerProvider?.(doc, true);
+                            DocUtils.LeavePushpin(doc);
+                            doc._stayInCollection = undefined;
+                            doc.context = this.props.Document;
+                            if (annotationKey ?? this._annotationKey) Doc.GetProto(doc).annotationOn = this.props.Document;
+                        });
                         const annoDocs = targetDataDoc[annotationKey ?? this.annotationKey] as List<Doc>;
                         if (annoDocs) annoDocs.push(...added);
                         else targetDataDoc[annotationKey ?? this.annotationKey] = new List<Doc>(added);
@@ -202,10 +228,10 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
         }
 
         whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive));
-        active = (outsideReaction?: boolean) => (CurrentUserUtils.SelectedTool === InkTool.None &&
+        isContentActive = (outsideReaction?: boolean) => (CurrentUserUtils.SelectedTool === InkTool.None &&
             (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.renderDepth === 0 || this.props.rootSelected(outsideReaction)) ? true : false)
         annotationsActive = (outsideReaction?: boolean) => (CurrentUserUtils.SelectedTool !== InkTool.None ||
-            (this.props.layerProvider?.(this.props.Document) === false && this.props.active()) ||
+            (this.props.layerProvider?.(this.props.Document) !== false && this.props.isContentActive?.()) ||
             (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.renderDepth === 0) ? true : false)
     }
     return Component;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index bb6a091cb..83949eba2 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -485,7 +485,7 @@ export class MainView extends React.Component {
                     rootSelected={returnTrue}
                     bringToFront={emptyFunction}
                     select={emptyFunction}
-                    active={returnFalse}
+                    isContentActive={returnFalse}
                     isSelected={returnFalse}
                     docViewPath={returnEmptyDoclist}
                     moveDocument={this.moveButtonDoc}
@@ -547,7 +547,7 @@ export class MainView extends React.Component {
                 fieldKey="data"
                 dropAction="move"
                 isSelected={returnTrue}
-                active={returnTrue}
+                isContentActive={returnTrue}
                 select={returnTrue}
                 setHeight={returnFalse}
                 addDocument={undefined}
@@ -593,7 +593,7 @@ export class MainView extends React.Component {
                     pinToPres={returnFalse}
                     ScreenToLocalTransform={Transform.Identity}
                     bringToFront={returnFalse}
-                    active={returnFalse}
+                    isContentActive={returnFalse}
                     whenChildContentsActiveChanged={returnFalse}
                     focus={returnFalse}
                     docViewPath={returnEmptyDoclist}
@@ -665,7 +665,7 @@ export class MainView extends React.Component {
                             pinToPres={returnFalse}
                             ScreenToLocalTransform={Transform.Identity}
                             bringToFront={returnFalse}
-                            active={returnFalse}
+                            isContentActive={returnFalse}
                             whenChildContentsActiveChanged={returnFalse}
                             focus={returnFalse}
                             PanelWidth={() => 500}
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index d3216bc94..4514e3ebb 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -98,7 +98,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
         };
         return !this.props.layoutDoc._showSidebar ? (null) :
             <div style={{
-                position: "absolute", pointerEvents: this.props.active() ? "all" : undefined, top: 0, right: 0,
+                position: "absolute", pointerEvents: this.props.isContentActive() ? "all" : undefined, top: 0, right: 0,
                 background: this.props.styleProvider?.(this.props.rootDoc, this.props, StyleProp.WidgetColor),
                 width: `${this.panelWidth()}px`,
                 height: "100%"
@@ -120,7 +120,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
                         scaleField={this.sidebarKey() + "-scale"}
                         isAnnotationOverlay={false}
                         select={emptyFunction}
-                        active={this.props.annotationsActive}
+                        isContentActive={this.props.annotationsActive}
                         scaling={returnOne}
                         whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
                         childHideDecorationTitle={returnTrue}
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 34b0e4d99..5491a81e6 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -141,7 +141,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                 onCheckedClick={this.scriptField}
                 onChildClick={this.scriptField}
                 dropAction={undefined}
-                active={returnTrue}
+                isContentActive={returnTrue}
                 bringToFront={emptyFunction}
                 focus={emptyFunction}
                 whenChildContentsActiveChanged={emptyFunction}
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index 452c79f88..b2ae441d6 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -126,7 +126,7 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume
     }
 
     @computed get buttons() {
-        if (!this.props.active()) return null;
+        if (!this.props.isContentActive()) return null;
         return <div className="arrow-buttons" >
             <div key="back" className="carousel3DView-back" style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }}
                 onClick={(e) => this.onArrowClick(e, -1)}
diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx
index 92288c1f2..2d7569d45 100644
--- a/src/client/views/collections/CollectionMapView.tsx
+++ b/src/client/views/collections/CollectionMapView.tsx
@@ -208,7 +208,7 @@ export class CollectionMapView extends CollectionSubView<MapSchema, Partial<IMap
 
     render() {
         const { childLayoutPairs } = this;
-        const { Document, fieldKey, active, google } = this.props;
+        const { Document, fieldKey, isContentActive: active, google } = this.props;
         const mapLoc = this.getLocation(this.rootDoc, `${fieldKey}-mapCenter`, false);
         let center = mapLoc;
         if (center === undefined) {
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index ba701b2a4..a94e706eb 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -281,7 +281,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
                         gridTemplateColumns: numberRange(rows).reduce((list: string, i: any) => list + ` ${this.props.parent.columnWidth}px`, ""),
                     }}>
                     {this.props.parent.children(this.props.docList)}
-                    {this.props.showHandle && this.props.parent.props.active() ? this.props.parent.columnDragger : (null)}
+                    {this.props.showHandle && this.props.parent.props.isContentActive() ? this.props.parent.columnDragger : (null)}
                 </div>
             </div>;
     }
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index dc2880a48..d49403d8e 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -328,7 +328,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
     @action
     onWheel(e: React.WheelEvent) {
         const scale = this.props.ScreenToLocalTransform().Scale;
-        this.props.active(true) && e.stopPropagation();
+        this.props.isContentActive(true) && e.stopPropagation();
     }
 
     @computed get renderMenuContent() {
@@ -444,7 +444,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
             renderDepth={this.props.renderDepth}
             moveDocument={this.props.moveDocument}
             ScreenToLocalTransform={this.props.ScreenToLocalTransform}
-            active={this.props.active}
+            active={this.props.isContentActive}
             onDrop={this.onExternalDrop}
             addDocTab={this.props.addDocTab}
             pinToPres={this.props.pinToPres}
@@ -533,11 +533,11 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
         this.columns = columns;
     }
 
-    onZoomMenu = (e: React.WheelEvent) => this.props.active(true) && e.stopPropagation();
+    onZoomMenu = (e: React.WheelEvent) => this.props.isContentActive(true) && e.stopPropagation();
 
     render() {
         TraceMobx();
-        if (!this.props.active()) setTimeout(() => this.closeHeader(), 0);
+        if (!this.props.isContentActive()) setTimeout(() => this.closeHeader(), 0);
         const menuContent = this.renderMenuContent;
         const menu = <div className="collectionSchema-header-menu"
             onWheel={e => this.onZoomMenu(e)}
@@ -553,21 +553,21 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
         return <div className={"collectionSchemaView" + (this.props.Document._searchDoc ? "-searchContainer" : "-container")}
             style={{
                 overflow: this.props.scrollOverflow === true ? "scroll" : undefined, backgroundColor: "white",
-                pointerEvents: this.props.Document._searchDoc !== undefined && !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined,
+                pointerEvents: this.props.Document._searchDoc !== undefined && !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined,
                 width: name === "collectionSchemaView-searchContainer" ? "auto" : this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative",
             }}  >
             <div className="collectionSchemaView-tableContainer"
                 style={{ width: `calc(100% - ${this.previewWidth()}px)` }}
                 onContextMenu={this.onSpecificMenu}
                 onPointerDown={this.onPointerDown}
-                onWheel={e => this.props.active(true) && e.stopPropagation()}
+                onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}
                 onDrop={e => this.onExternalDrop(e, {})}
                 ref={this.createTarget}>
                 {this.schemaTable}
             </div>
             {this.dividerDragger}
             {!this.previewWidth() ? (null) : this.previewPanel}
-            {this._headerOpen && this.props.active() ? menu : null}
+            {this._headerOpen && this.props.isContentActive() ? menu : null}
         </div>;
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 304643d52..d6aca6f00 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -114,7 +114,7 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
     onPointerDownTimeline = (e: React.PointerEvent): void => {
         const rect = this._timeline?.getBoundingClientRect();
         const clientX = e.clientX;
-        if (rect && this.props.active()) {
+        if (rect && this.props.isContentActive()) {
             const wasPlaying = this.props.playing();
             if (wasPlaying) this.props.Pause();
             const wasSelecting = CollectionStackedTimeline.SelectingRegion === this;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 3087aeb81..4dab9d94a 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -533,14 +533,14 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
                 <div className={this.isStackingView ? "collectionStackingView" : "collectionMasonryView"}
                     ref={this.createRef}
                     style={{
-                        overflowY: this.props.active() ? "auto" : "hidden",
+                        overflowY: this.props.isContentActive() ? "auto" : "hidden",
                         background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor),
                         pointerEvents: this.backgroundEvents ? "all" : undefined
                     }}
                     onScroll={action(e => this._scroll = e.currentTarget.scrollTop)}
                     onDrop={this.onExternalDrop.bind(this)}
                     onContextMenu={this.onContextMenu}
-                    onWheel={e => this.props.active(true) && e.stopPropagation()} >
+                    onWheel={e => this.props.isContentActive(true) && e.stopPropagation()} >
                     {this.renderedSections}
                     {!this.showAddAGroup ? (null) :
                         <div key={`${this.props.Document[Id]}-addGroup`} className="collectionStackingView-addGroupButton"
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 0702febae..f41043179 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -136,7 +136,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
     }
 
     @computed get contents() {
-        return <div className="collectionTimeView-innards" key="timeline" style={{ pointerEvents: this.props.active() ? undefined : "none" }}
+        return <div className="collectionTimeView-innards" key="timeline" style={{ pointerEvents: this.props.isContentActive() ? undefined : "none" }}
             onClick={this.contentsDown}>
             <CollectionFreeFormView {...this.props}
                 engineProps={{ pivotField: this.pivotField, docFilters: this.docFilters, docRangeFilters: this.docRangeFilters }}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 788cb01f6..f69a3a331 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -197,7 +197,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
     @computed get fileSysMode() { return this.doc.treeViewType === "fileSystem"; }
     onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick);
     whenChildContentsActiveChanged = (isActive: boolean) => { this.props.whenChildContentsActiveChanged(this._isChildActive = isActive); };
-    active = (outsideReaction: boolean | undefined) => this.props.active(outsideReaction) || this._isChildActive;
+    active = (outsideReaction: boolean | undefined) => this.props.isContentActive(outsideReaction) || this._isChildActive;
     panelWidth = () => this.props.PanelWidth() - 20; // bcz: 20 is the 10 + 10 for the left and right padding.
     @computed get treeChildren() {
         TraceMobx();
@@ -224,7 +224,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
         const background = this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor);
         const paddingX = `${NumCast(this.doc._xPadding, 15)}px`;
         const paddingTop = `${NumCast(this.doc._yPadding, 20)}px`;
-        const pointerEvents = !this.props.active() && !SnappingManager.GetIsDragging() && !this._isChildActive ? "none" : undefined;
+        const pointerEvents = !this.props.isContentActive() && !SnappingManager.GetIsDragging() && !this._isChildActive ? "none" : undefined;
 
         return !this.treeChildren ? (null) : (
             <div className="collectionTreeView-container" onContextMenu={this.onContextMenu}>
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index f8c846f7f..28099a995 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -2,26 +2,23 @@ import { action, computed, observable } from 'mobx';
 import { observer } from "mobx-react";
 import * as React from 'react';
 import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app
-import { DateField } from '../../../fields/DateField';
-import { AclAddonly, AclAdmin, AclEdit, AclPrivate, AclReadonly, AclSym, DataSym, Doc, DocListCast, DocListCastAsync, Field } from '../../../fields/Doc';
+import { Doc, DocListCast } from '../../../fields/Doc';
+import { documentSchema } from '../../../fields/documentSchemas';
 import { Id } from '../../../fields/FieldSymbols';
-import { List } from '../../../fields/List';
 import { ObjectField } from '../../../fields/ObjectField';
+import { makeInterface } from '../../../fields/Schema';
 import { ScriptField } from '../../../fields/ScriptField';
-import { Cast, ScriptCast, StrCast, DateCast } from '../../../fields/Types';
-import { denormalizeEmail, distributeAcls, GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util';
-import { returnFalse } from '../../../Utils';
-import { Docs, DocUtils } from '../../documents/Documents';
-import { BranchTask, BranchCreate } from '../../documents/Gitlike';
-import { DocumentType } from '../../documents/DocumentTypes';
+import { Cast, ScriptCast, StrCast } from '../../../fields/Types';
+import { TraceMobx } from '../../../fields/util';
+import { DocUtils } from '../../documents/Documents';
+import { BranchCreate, BranchTask } from '../../documents/Gitlike';
 import { CurrentUserUtils } from '../../util/CurrentUserUtils';
 import { ImageUtils } from '../../util/Import & Export/ImageUtils';
 import { InteractionUtils } from '../../util/InteractionUtils';
-import { UndoManager } from '../../util/UndoManager';
 import { ContextMenu } from "../ContextMenu";
 import { ContextMenuProps } from '../ContextMenuItem';
+import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
 import { FieldView, FieldViewProps } from '../nodes/FieldView';
-import { Touchable } from '../Touchable';
 import { CollectionCarousel3DView } from './CollectionCarousel3DView';
 import { CollectionCarouselView } from './CollectionCarouselView';
 import { CollectionDockingView } from "./CollectionDockingView";
@@ -64,7 +61,6 @@ export enum CollectionViewType {
 export interface CollectionViewProps extends FieldViewProps {
     isAnnotationOverlay?: boolean;  // is the collection an annotation overlay (eg an overlay on an image/video/etc)
     layoutEngine?: () => string;
-    filterAddDocument?: (doc: Doc | Doc[]) => boolean;  // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
     setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
 
     // property overrides for child documents
@@ -81,19 +77,20 @@ export interface CollectionViewProps extends FieldViewProps {
     childClickScript?: ScriptField;
     childDoubleClickScript?: ScriptField;
 }
+
+type CollectionDocument = makeInterface<[typeof documentSchema]>;
+const CollectionDocument = makeInterface(documentSchema);
 @observer
-export class CollectionView extends Touchable<CollectionViewProps> {
+export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & CollectionViewProps, CollectionDocument>(CollectionDocument, "") {
     public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); }
 
-    _isChildActive = false;   //TODO should this be observable?
-    @observable private _curLightboxImg = 0;
     @observable private static _safeMode = false;
     public static SetSafeMode(safeMode: boolean) { this._safeMode = safeMode; }
 
     protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
 
     get collectionViewType(): CollectionViewType | undefined {
-        const viewField = StrCast(this.props.Document._viewType);
+        const viewField = StrCast(this.layoutDoc._viewType);
         if (CollectionView._safeMode) {
             switch (viewField) {
                 case CollectionViewType.Freeform:
@@ -104,121 +101,24 @@ export class CollectionView extends Touchable<CollectionViewProps> {
         return viewField as any as CollectionViewType;
     }
 
-    active = (outsideReaction?: boolean) => {
-        return this.props.renderDepth === 0 ||
-            this.props.isSelected(outsideReaction) ||
-            this.props.rootSelected(outsideReaction) ||
-            (this.props.layerProvider?.(this.props.Document) !== false && (this.props.Document.forceActive || this.props.Document._isGroup)) ||
-            this._isChildActive ?
-            true :
-            false;
-    }
-
-    whenChildContentsActiveChanged = (isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isChildActive = isActive);
-
-    @action.bound
-    addDocument = (doc: Doc | Doc[]): boolean => {
-        if (this.props.filterAddDocument?.(doc) === false) {
-            return false;
-        }
-
-        const docs = doc instanceof Doc ? [doc] : doc;
-
-        if (docs.find(doc => Doc.AreProtosEqual(doc, this.props.Document))) return false;
-        const targetDataDoc = this.props.Document[DataSym];
-        const docList = DocListCast(targetDataDoc[this.props.fieldKey]);
-        const added = docs.filter(d => !docList.includes(d));
-        const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
-
-        if (added.length) {
-            if (effectiveAcl === AclPrivate || effectiveAcl === AclReadonly) {
-                return false;
-            }
-            else {
-                if (this.props.Document[AclSym] && Object.keys(this.props.Document[AclSym])) {
-                    added.forEach(d => {
-                        for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
-                            if (d.author === denormalizeEmail(key.substring(4)) && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d, true);
-                            //else if (this.props.Document[key] === SharingPermissions.Admin) distributeAcls(key, SharingPermissions.Add, d, true);
-                            //else distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true);
-                        }
-                    });
-                }
-
-                if (effectiveAcl === AclAddonly) {
-                    added.map(doc => {
-                        this.props.layerProvider?.(doc, true);// assigns layer values to the newly added document... testing the utility of this
-                        Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc);
-                        doc.context = this.props.Document;
-                    });
-                }
-                else {
-                    added.filter(doc => [AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))).map(doc => {  // only make a pushpin if we have acl's to edit the document
-                        DocUtils.LeavePushpin(doc);
-                        doc._stayInCollection = undefined;
-                        doc.context = this.props.Document;
-                    });
-                    added.map(doc => this.props.layerProvider?.(doc, true));// assigns layer values to the newly added document... testing the utility of this
-                    (targetDataDoc[this.props.fieldKey] as List<Doc>).push(...added);
-                    targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
-                }
-            }
-        }
-        return true;
-    }
-
-    @action.bound
-    removeDocument = (doc: any): boolean => {
-        const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
-        const indocs = doc instanceof Doc ? [doc] : doc as Doc[];
-        const docs = indocs.filter(doc => effectiveAcl === AclEdit || effectiveAcl === AclAdmin || GetEffectiveAcl(doc) === AclAdmin);
-        if (docs.length) {
-            const targetDataDoc = this.props.Document[DataSym];
-            const value = DocListCast(targetDataDoc[this.props.fieldKey]);
-            const toRemove = value.filter(v => docs.includes(v));
-            if (toRemove.length !== 0) {
-                const recent = Cast(Doc.UserDoc().myRecentlyClosedDocs, Doc) as Doc;
-                toRemove.forEach(doc => {
-                    const ind = (targetDataDoc[this.props.fieldKey] as List<Doc>).indexOf(doc);
-                    if (ind !== -1) {
-                        Doc.RemoveDocFromList(targetDataDoc, this.props.fieldKey, doc);
-                        doc.context = undefined;
-                        recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true);
-                    }
-                });
-                return true;
-            }
-        }
-        return false;
-    }
-
-    // this is called with the document that was dragged and the collection to move it into.
-    // if the target collection is the same as this collection, then the move will be allowed.
-    // otherwise, the document being moved must be able to be removed from its container before
-    // moving it into the target.
-    @action.bound
-    moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => {
-        if (Doc.AreProtosEqual(this.props.Document, targetCollection)) {
-            return true;
-        }
-        const first = doc instanceof Doc ? doc : doc[0];
-        if (!first?._stayInCollection && addDocument !== returnFalse) {
-            return UndoManager.RunInTempBatch(() => this.removeDocument(doc) && addDocument(doc));
-        }
-        return false;
-    }
-
     showIsTagged = () => {
         return (null);
         // this section would display an icon in the bototm right of a collection to indicate that all
         // photos had been processed through Google's content analysis API and Google's tags had been
         // assigned to the documents googlePhotosTags field.
-        // const children = DocListCast(this.props.Document[this.props.fieldKey]);
+        // const children = DocListCast(this.rootDoc[this.props.fieldKey]);
         // const imageProtos = children.filter(doc => Cast(doc.data, ImageField)).map(Doc.GetProto);
         // const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags);
         // return !allTagged ? (null) : <img id={"google-tags"} src={"/assets/google_tags.png"} />;
     }
 
+    isContentActive = (outsideReaction?: boolean) => {
+        return this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.renderDepth === 0 || this.props.rootSelected(outsideReaction) ||
+            (this.props.layerProvider?.(this.rootDoc) !== false && (this.rootDoc.forceActive || this.rootDoc._isGroup))
+            ?
+            true : false;
+    }
+
     screenToLocalTransform = () => this.props.renderDepth ? this.props.ScreenToLocalTransform() : this.props.ScreenToLocalTransform().scale(this.props.PanelWidth() / this.bodyPanelWidth());
     private SubView = (type: CollectionViewType, props: SubCollectionViewProps) => {
         TraceMobx();
@@ -251,7 +151,6 @@ export class CollectionView extends Touchable<CollectionViewProps> {
         }
         subItems.push({ description: "Schema", event: () => func(CollectionViewType.Schema), icon: "th-list" });
         subItems.push({ description: "Tree", event: () => func(CollectionViewType.Tree), icon: "tree" });
-        !Doc.UserDoc().noviceMode && subItems.push({ description: "Stacking", event: () => func(CollectionViewType.Stacking), icon: "ellipsis-v" });
         subItems.push({ description: "Stacking", event: () => func(CollectionViewType.Stacking)._autoHeight = true, icon: "ellipsis-v" });
         subItems.push({ description: "Multicolumn", event: () => func(CollectionViewType.Multicolumn), icon: "columns" });
         subItems.push({ description: "Multirow", event: () => func(CollectionViewType.Multirow), icon: "columns" });
@@ -262,7 +161,7 @@ export class CollectionView extends Touchable<CollectionViewProps> {
         !Doc.UserDoc().noviceMode && subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" });
         subItems.push({ description: "Grid", event: () => func(CollectionViewType.Grid), icon: "th-list" });
 
-        if (!Doc.IsSystem(this.props.Document) && !this.props.Document.annotationOn) {
+        if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.annotationOn) {
             const existingVm = ContextMenu.Instance.findByDescription(category);
             const catItems = existingVm && "subitems" in existingVm ? existingVm.subitems : [];
             catItems.push({ description: "Add a Perspective...", addDivider: true, noexpand: true, subitems: subItems, icon: "eye" });
@@ -272,9 +171,9 @@ export class CollectionView extends Touchable<CollectionViewProps> {
 
     onContextMenu = (e: React.MouseEvent): void => {
         const cm = ContextMenu.Instance;
-        if (cm && !e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
+        if (cm && !e.isPropagationStopped() && this.rootDoc[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
             this.setupViewTypes("UI Controls...", vtype => {
-                const newRendition = Doc.MakeAlias(this.props.Document);
+                const newRendition = Doc.MakeAlias(this.rootDoc);
                 newRendition._viewType = vtype;
                 this.props.addDocTab(newRendition, "add:right");
                 return newRendition;
@@ -282,34 +181,34 @@ export class CollectionView extends Touchable<CollectionViewProps> {
 
             const options = cm.findByDescription("Options...");
             const optionItems = options && "subitems" in options ? options.subitems : [];
-            !Doc.UserDoc().noviceMode ? optionItems.splice(0, 0, { description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" }) : null;
-            if (this.props.Document.childLayout instanceof Doc) {
-                optionItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, "add:right"), icon: "project-diagram" });
+            !Doc.UserDoc().noviceMode ? optionItems.splice(0, 0, { description: `${this.rootDoc.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.rootDoc.forceActive = !this.rootDoc.forceActive, icon: "project-diagram" }) : null;
+            if (this.rootDoc.childLayout instanceof Doc) {
+                optionItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.rootDoc.childLayout as Doc, "add:right"), icon: "project-diagram" });
             }
-            if (this.props.Document.childClickedOpenTemplateView instanceof Doc) {
-                optionItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childClickedOpenTemplateView as Doc, "add:right"), icon: "project-diagram" });
+            if (this.rootDoc.childClickedOpenTemplateView instanceof Doc) {
+                optionItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.rootDoc.childClickedOpenTemplateView as Doc, "add:right"), icon: "project-diagram" });
             }
-            !Doc.UserDoc().noviceMode && optionItems.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 && optionItems.push({ description: `${this.rootDoc.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.rootDoc.isInPlaceContainer = !this.rootDoc.isInPlaceContainer, icon: "project-diagram" });
 
             optionItems.push({
-                description: "Create Branch", event: async () => this.props.addDocTab(await BranchCreate(this.props.Document), "add:right"), icon: "project-diagram"
+                description: "Create Branch", event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), "add:right"), icon: "project-diagram"
             });
             optionItems.push({
-                description: "Pull Master", event: () => BranchTask(this.props.Document, "pull"), icon: "project-diagram"
+                description: "Pull Master", event: () => BranchTask(this.rootDoc, "pull"), icon: "project-diagram"
             });
             optionItems.push({
-                description: "Merge Branches", event: () => BranchTask(this.props.Document, "merge"), icon: "project-diagram"
+                description: "Merge Branches", event: () => BranchTask(this.rootDoc, "merge"), icon: "project-diagram"
             });
 
             !options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "hand-point-right" });
 
-            if (!Doc.UserDoc().noviceMode && !this.props.Document.annotationOn) {
+            if (!Doc.UserDoc().noviceMode && !this.rootDoc.annotationOn) {
                 const existingOnClick = cm.findByDescription("OnClick...");
                 const onClicks = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
                 const funcs = [{ key: "onChildClick", name: "On Child Clicked" }, { key: "onChildDoubleClick", name: "On Child Double Clicked" }];
                 funcs.map(func => onClicks.push({
                     description: `Edit ${func.name} script`, icon: "edit", event: (obj: any) => {
-                        const alias = Doc.MakeAlias(this.props.Document);
+                        const alias = Doc.MakeAlias(this.rootDoc);
                         DocUtils.makeCustomViewClicked(alias, undefined, func.key);
                         this.props.addDocTab(alias, "add:right");
                     }
@@ -318,15 +217,15 @@ export class CollectionView extends Touchable<CollectionViewProps> {
                     onClicks.push({
                         description: `Set child ${childClick.title}`,
                         icon: "edit",
-                        event: () => Doc.GetProto(this.props.Document)[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)),
+                        event: () => Doc.GetProto(this.rootDoc)[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)),
                     }));
-                !Doc.IsSystem(this.props.Document) && !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "mouse-pointer" });
+                !Doc.IsSystem(this.rootDoc) && !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "mouse-pointer" });
             }
 
             if (!Doc.UserDoc().noviceMode) {
                 const more = cm.findByDescription("More...");
                 const moreItems = more && "subitems" in more ? more.subitems : [];
-                moreItems.push({ description: "Export Image Hierarchy", icon: "columns", event: () => ImageUtils.ExportHierarchyToFileSystem(this.props.Document) });
+                moreItems.push({ description: "Export Image Hierarchy", icon: "columns", event: () => ImageUtils.ExportHierarchyToFileSystem(this.rootDoc) });
                 !more && cm.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" });
             }
         }
@@ -334,27 +233,26 @@ export class CollectionView extends Touchable<CollectionViewProps> {
 
     bodyPanelWidth = () => this.props.PanelWidth();
 
-    childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null);
-    @computed get childLayoutString() { return StrCast(this.props.Document.childLayoutString); }
+    childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.rootDoc.childLayoutTemplate, Doc, null);
+    @computed get childLayoutString() { return StrCast(this.rootDoc.childLayoutString); }
 
     render() {
         TraceMobx();
         const props: SubCollectionViewProps = {
             ...this.props,
             addDocument: this.addDocument,
-            removeDocument: this.removeDocument,
             moveDocument: this.moveDocument,
-            active: this.active,
-            whenChildContentsActiveChanged: this.whenChildContentsActiveChanged,
+            removeDocument: this.removeDocument,
+            isContentActive: this.isContentActive,
             PanelWidth: this.bodyPanelWidth,
             PanelHeight: this.props.PanelHeight,
+            ScreenToLocalTransform: this.screenToLocalTransform,
             childLayoutTemplate: this.childLayoutTemplate,
             childLayoutString: this.childLayoutString,
-            ScreenToLocalTransform: this.screenToLocalTransform,
             CollectionView: this,
         };
         return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
-            style={{ pointerEvents: this.props.layerProvider?.(this.props.Document) === false ? "none" : undefined }}>
+            style={{ pointerEvents: this.props.layerProvider?.(this.rootDoc) === false ? "none" : undefined }}>
             {this.showIsTagged()}
             {this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
         </div>);
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index dcd874089..ec3f3090b 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -420,7 +420,7 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                     childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
                     noOverlay={true} // don't render overlay Docs since they won't scale
                     setHeight={returnFalse}
-                    active={returnTrue}
+                    isContentActive={returnTrue}
                     select={emptyFunction}
                     dropAction={undefined}
                     isSelected={returnFalse}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index eca655099..b74bca5d3 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -116,7 +116,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
 
     @computed get views() { return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); }
     @computed get backgroundEvents() { return this.props.layerProvider?.(this.layoutDoc) === false && SnappingManager.GetIsDragging(); }
-    @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && (this.props.ContainingCollectionView?.active() || this.props.active()); }
+    @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && (this.props.ContainingCollectionView?.isContentActive() || this.props.isContentActive()); }
     @computed get fitToContentVals() {
         return {
             bounds: { ...this.contentBounds, cx: (this.contentBounds.x + this.contentBounds.r) / 2, cy: (this.contentBounds.y + this.contentBounds.b) / 2 },
@@ -457,7 +457,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             return;
         }
         this._hitCluster = this.pickCluster(this.getTransform().transformPoint(e.clientX, e.clientY));
-        if (e.button === 0 && !e.altKey && !e.ctrlKey && this.props.active(true)) {
+        if (e.button === 0 && !e.altKey && !e.ctrlKey && this.props.isContentActive(true)) {
             document.removeEventListener("pointermove", this.onPointerMove);
             document.removeEventListener("pointerup", this.onPointerUp);
             document.addEventListener("pointermove", this.onPointerMove);
@@ -482,7 +482,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             const pt = me.changedTouches[0];
             if (pt) {
                 this._hitCluster = this.pickCluster(this.getTransform().transformPoint(pt.clientX, pt.clientY));
-                if (!e.shiftKey && !e.altKey && !e.ctrlKey && this.props.active(true)) {
+                if (!e.shiftKey && !e.altKey && !e.ctrlKey && this.props.isContentActive(true)) {
                     this.removeMoveListeners();
                     this.addMoveListeners();
                     this.removeEndListeners();
@@ -645,7 +645,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         if (this.props.Document._isGroup) return; // groups don't pan when dragged -- instead let the event go through to allow the group itself to drag
         if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) return;
         if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) {
-            if (this.props.active(true)) e.stopPropagation();
+            if (this.props.isContentActive(true)) e.stopPropagation();
         } else if (!e.cancelBubble) {
             if (CurrentUserUtils.SelectedTool === InkTool.None) {
                 if (this.tryDragCluster(e, this._hitCluster)) {
@@ -733,7 +733,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
 
     @action
     handle2PointersDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>) => {
-        if (!e.nativeEvent.cancelBubble && this.props.active(true)) {
+        if (!e.nativeEvent.cancelBubble && this.props.isContentActive(true)) {
             // const pt1: React.Touch | null = e.targetTouches.item(0);
             // const pt2: React.Touch | null = e.targetTouches.item(1);
             // // if (!pt1 || !pt2) return;
@@ -817,7 +817,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming
             e.stopPropagation();
         }
-        else if (this.props.active(true) && !this.Document._isGroup) {
+        else if (this.props.isContentActive(true) && !this.Document._isGroup) {
             e.stopPropagation();
             e.preventDefault();
             this.zoom(e.clientX, e.clientY, e.deltaY); // if (!this.props.isAnnotationOverlay) // bcz: do we want to zoom in on images/videos/etc?
@@ -1043,7 +1043,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             freezeDimensions={this.props.childFreezeDimensions}
             dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             bringToFront={this.bringToFront}
-            documentActive={() => this.props.active()}
+            isDocumentActive={() => this.props.isContentActive()}
             dontRegisterView={this.props.dontRegisterView}
             pointerEvents={this.backgroundActive || this.props.childPointerEvents ? "all" :
                 (this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? "none" : undefined}
@@ -1486,7 +1486,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
                 width: `${100 / (this.contentScaling || 1)}%`,
                 height: this.isAnnotationOverlay && this.Document.scrollHeight ? this.Document.scrollHeight : `${100 / (this.contentScaling || 1)}%`// : this.isAnnotationOverlay ? (this.Document.scrollHeight ? this.Document.scrollHeight : "100%") : this.props.PanelHeight()
             }}>
-            {this.Document._freeformLOD && !this.props.active() && !this.props.isAnnotationOverlay && this.props.renderDepth > 0 ?
+            {this.Document._freeformLOD && !this.props.isContentActive() && !this.props.isAnnotationOverlay && this.props.renderDepth > 0 ?
                 this.placeholder : this.marqueeView}
             {this.props.noOverlay ? (null) : <CollectionFreeFormOverlayView elements={this.elementFunc} />}
 
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index af391a078..d7a0d3f34 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -167,7 +167,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             } else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) {
                 FormattedTextBox.SelectOnLoadChar = Doc.UserDoc().defaultTextLayout && !this.props.childLayoutString ? e.key : "";
                 FormattedTextBox.LiveTextUndo = UndoManager.StartBatch("live text batch");
-                this.props.addLiveTextDocument(CurrentUserUtils.GetNewTextDoc("-typed text-", x, y, 200, 100, this.props.xMargin === 0, this.props.isAnnotationOverlay ? this.props.Document : undefined));
+                this.props.addLiveTextDocument(CurrentUserUtils.GetNewTextDoc("-typed text-", x, y, 200, 100, this.props.xMargin === 0));
                 e.stopPropagation();
             }
     }
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index 35eed3bc2..b0030471d 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -295,7 +295,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) {
      * Handles text document creation on double click.
      */
     onPointerDown = (e: React.PointerEvent) => {
-        if (this.props.active(true)) {
+        if (this.props.isContentActive(true)) {
             setupMoveUpEvents(this, e, returnFalse, returnFalse,
                 (e: PointerEvent, doubleTap?: boolean) => {
                     if (doubleTap) {
@@ -315,7 +315,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) {
     render() {
         return (
             <div className="collectionGridView-contents" ref={this.createDashEventsTarget}
-                style={{ pointerEvents: !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined }}
+                style={{ pointerEvents: !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined }}
                 onContextMenu={this.onContextMenu}
                 onPointerDown={this.onPointerDown}
                 onDrop={this.onExternalDrop}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index d4d2bea76..970f9bd95 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -17,7 +17,7 @@ import { SnappingManager } from "../../util/SnappingManager";
 import { CollectionStackedTimeline } from "../collections/CollectionStackedTimeline";
 import { ContextMenu } from "../ContextMenu";
 import { ContextMenuProps } from "../ContextMenuItem";
-import { ViewBoxAnnotatableComponent } from "../DocComponent";
+import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent";
 import "./AudioBox.scss";
 import { FieldView, FieldViewProps } from './FieldView';
 import { LinkDocPreview } from "./LinkDocPreview";
@@ -29,7 +29,7 @@ type AudioDocument = makeInterface<[typeof documentSchema]>;
 const AudioDocument = makeInterface(documentSchema);
 
 @observer
-export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioDocument>(AudioDocument) {
+export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, AudioDocument>(AudioDocument, "annotations") {
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(AudioBox, fieldKey); }
     public static Enabled = false;
     static playheadWidth = 30; // width of playhead
@@ -63,7 +63,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     @computed get pauseTime() { return this._pauseEnd - this._pauseStart; } // total time paused to update the correct time
     @computed get heightPercent() { return AudioBox.heightPercent; }
 
-    constructor(props: Readonly<FieldViewProps>) {
+    constructor(props: Readonly<ViewBoxAnnotatableProps & FieldViewProps>) {
         super(props);
         AudioBox.Instance = this;
 
@@ -267,7 +267,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
 
     // returns the html audio element
     @computed get audio() {
-        return <audio ref={this.setRef} className={`audiobox-control${this.active() ? "-interactive" : ""}`}>
+        return <audio ref={this.setRef} className={`audiobox-control${this.isContentActive() ? "-interactive" : ""}`}>
             <source src={this.path} type="audio/mpeg" />
             Not supported.
         </audio>;
@@ -337,7 +337,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
             isChildActive={this.isActiveChild}
             Play={this.Play}
             Pause={this.Pause}
-            active={this.active}
+            isContentActive={this.isContentActive}
             playLink={this.playLink}
             PanelWidth={this.timelineWidth}
             PanelHeight={this.timelineHeight}
@@ -345,7 +345,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     }
 
     render() {
-        const interactive = SnappingManager.GetIsDragging() || this.active() ? "-interactive" : "";
+        const interactive = SnappingManager.GetIsDragging() || this.isContentActive() ? "-interactive" : "";
         return <div className="audiobox-container"
             onContextMenu={this.specificContextMenu}
             onClick={!this.path && !this._recorder ? this.recordAudioAnnotation : undefined}
@@ -370,7 +370,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                             RECORD
                         </button>}
                 </div> :
-                <div className="audiobox-controls" style={{ pointerEvents: this._isAnyChildContentActive || this.active() ? "all" : "none" }} >
+                <div className="audiobox-controls" style={{ pointerEvents: this._isAnyChildContentActive || this.isContentActive() ? "all" : "none" }} >
                     <div className="audiobox-dictation" />
                     <div className="audiobox-player" style={{ height: `${AudioBox.heightPercent}%` }} >
                         <div className="audiobox-playhead" style={{ width: AudioBox.playheadWidth }} title={this.mediaState === "paused" ? "play" : "pause"} onClick={this.Play}> <FontAwesomeIcon style={{ width: "100%", position: "absolute", left: "0px", top: "5px", borderWidth: "thin", borderColor: "white" }} icon={this.mediaState === "paused" ? "play" : "pause"} size={"1x"} /></div>
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index d71bb1397..0a9d7e809 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -9,7 +9,7 @@ import { emptyFunction, OmitKeys, setupMoveUpEvents } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { undoBatch } from '../../util/UndoManager';
-import { ViewBoxAnnotatableComponent } from '../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
 import "./ComparisonBox.scss";
 import { DocumentView } from './DocumentView';
 import { FieldView, FieldViewProps } from './FieldView';
@@ -21,7 +21,7 @@ type ComparisonDocument = makeInterface<[typeof comparisonSchema, typeof documen
 const ComparisonDocument = makeInterface(comparisonSchema, documentSchema);
 
 @observer
-export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps, ComparisonDocument>(ComparisonDocument) {
+export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, ComparisonDocument>(ComparisonDocument, "annotations") {
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ComparisonBox, fieldKey); }
     protected _multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined;
     private _disposers: (DragManager.DragDropDisposer | undefined)[] = [undefined, undefined];
@@ -102,7 +102,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps, C
         };
 
         return (
-            <div className={`comparisonBox${this.active() || SnappingManager.GetIsDragging() ? "-interactive" : ""}` /* change className to easily disable/enable pointer events in CSS */}>
+            <div className={`comparisonBox${this.isContentActive() || SnappingManager.GetIsDragging() ? "-interactive" : ""}` /* change className to easily disable/enable pointer events in CSS */}>
                 {displayBox("after", 1, this.props.PanelWidth() - 3)}
                 <div className="clip-div" style={{ width: clipWidth, transition: this._animating, background: StrCast(this.layoutDoc._backgroundColor, "gray") }}>
                     {displayBox("before", 0, 0)}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 553cfcdf7..b53827371 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -40,6 +40,7 @@ import React = require("react");
 import { TraceMobx, GetEffectiveAcl } from "../../../fields/util";
 import { ScriptField } from "../../../fields/ScriptField";
 import XRegExp = require("xregexp");
+import { DocumentType } from "../../documents/DocumentTypes";
 
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 19ed417c0..e4f1ac8ed 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -110,6 +110,7 @@ export interface DocumentViewSharedProps {
     whenChildContentsActiveChanged: (isActive: boolean) => void;
     rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected
     addDocTab: (doc: Doc, where: string) => boolean;
+    filterAddDocument?: (doc: []) => boolean;  // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
     addDocument?: (doc: Doc | Doc[]) => boolean;
     removeDocument?: (doc: Doc | Doc[]) => boolean;
     moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
@@ -130,7 +131,8 @@ export interface DocumentViewProps extends DocumentViewSharedProps {
     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
     treeViewDoc?: Doc;
-    documentActive?: () => boolean; // whether a document should handle pointer events
+    isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events
+    isContentActive?: () => boolean | undefined; // whether a document should handle pointer events
     contentPointerEvents?: string; // pointer events allowed for content of a document view.  eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
     radialMenu?: String[];
     LayoutTemplateString?: string;
@@ -175,7 +177,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     _componentView: Opt<DocComponentView>; // needs to be accessed from DocumentView wrapper class
 
     private get topMost() { return this.props.renderDepth === 0; }
-    private get active() { return this.props.documentActive?.() || this.props.isSelected(true); }
     public get displayName() { return "DocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive
     public get ContentDiv() { return this._mainCont.current; }
     public get LayoutFieldKey() { return Doc.LayoutFieldKey(this.layoutDoc); }
@@ -279,7 +280,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             this._downX = touch.clientX;
             this._downY = touch.clientY;
             if (!e.nativeEvent.cancelBubble) {
-                if ((this.active || this.layoutDoc.onDragStart || this.onClickHandler) && !e.ctrlKey && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) e.stopPropagation();
+                if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart || this.onClickHandler) && !e.ctrlKey && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) e.stopPropagation();
                 this.removeMoveListeners();
                 this.addMoveListeners();
                 this.removeEndListeners();
@@ -290,10 +291,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     }
 
     handle1PointerMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>) => {
-        if (e.cancelBubble && this.active) {
+        if (e.cancelBubble && this.props.isDocumentActive?.()) {
             this.removeMoveListeners();
         }
-        else if (!e.cancelBubble && (this.active || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
+        else if (!e.cancelBubble && (this.props.isDocumentActive?.() || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
             const touch = me.touchEvent.changedTouches.item(0);
             if (touch && (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3)) {
                 if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler)) {
@@ -510,7 +511,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         if ((!e.nativeEvent.cancelBubble || this.onClickHandler || this.layoutDoc.onDragStart) &&
             // if this is part of a template, let the event go up to the tempalte root unless right/ctrl clicking
             !(this.props.Document.rootDocument && !(e.ctrlKey || e.button > 0))) {
-            if ((this.active || this.layoutDoc.onDragStart) &&
+            if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) &&
                 !e.ctrlKey &&
                 (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) &&
                 !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
@@ -527,10 +528,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 
     onPointerMove = (e: PointerEvent): void => {
         if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool))) return;
-        if (e.cancelBubble && this.active) {
+        if (e.cancelBubble && this.props.isDocumentActive?.()) {
             document.removeEventListener("pointermove", this.onPointerMove); // stop listening to pointerMove if something else has stopPropagated it (e.g., the MarqueeView)
         }
-        else if (!e.cancelBubble && (this.active || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
+        else if (!e.cancelBubble && (this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
             if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
                 if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) {
                     document.removeEventListener("pointermove", this.onPointerMove);
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 97f53aac0..0fc7a752f 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -18,8 +18,8 @@ export interface FieldViewProps extends DocumentViewSharedProps {
     fieldKey: string;
     scrollOverflow?: boolean; // bcz: would like to think this can be avoided -- need to look at further
 
-    active: (outsideReaction?: boolean) => boolean;
     select: (isCtrlPressed: boolean) => void;
+    isContentActive: (outsideReaction?: boolean) => boolean;
     isSelected: (outsideReaction?: boolean) => boolean;
     scaling?: () => number;
     setHeight: (height: number) => void;
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index 39db6f46c..bf5a6b7d2 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -215,7 +215,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
                     isSelected={returnFalse}
                     select={returnFalse}
                     bringToFront={emptyFunction}
-                    active={returnTrue}
+                    isContentActive={returnTrue}
                     whenChildContentsActiveChanged={returnFalse}
                     treeViewHideTitle={true}
                     focus={returnFalse}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index efb9dcb4f..0f2e3e65d 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -20,7 +20,7 @@ import { undoBatch } from '../../util/UndoManager';
 import { ContextMenu } from "../../views/ContextMenu";
 import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
 import { ContextMenuProps } from '../ContextMenuItem';
-import { ViewBoxAnnotatableComponent } from '../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
 import { MarqueeAnnotator } from '../MarqueeAnnotator';
 import { StyleProp } from '../StyleProvider';
 import { FaceRectangles } from './FaceRectangles';
@@ -46,7 +46,7 @@ const uploadIcons = {
 };
 
 @observer
-export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageDocument>(ImageDocument) {
+export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, ImageDocument>(ImageDocument, "annotations") {
     protected _multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined;
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); }
     private _imgRef: React.RefObject<HTMLImageElement> = React.createRef();
@@ -319,7 +319,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
     }
     @action
     marqueeDown = (e: React.PointerEvent) => {
-        if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.active(true)) this._marqueeing = [e.clientX, e.clientY];
+        if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true)) this._marqueeing = [e.clientX, e.clientY];
     }
     @action
     finishMarquee = () => {
@@ -358,7 +358,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
                 focus={this.props.focus}
                 isSelected={this.props.isSelected}
                 select={emptyFunction}
-                active={this.annotationsActive}
+                isContentActive={this.annotationsActive}
                 whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}>
                 {this.contentFunc}
             </CollectionFreeFormView>
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index e03293332..881cbf2bb 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -72,7 +72,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             dropAction: "alias",
             bringToFront: emptyFunction,
             renderDepth: 1,
-            active: returnFalse,
+            isContentActive: returnFalse,
             whenChildContentsActiveChanged: emptyFunction,
             ScreenToLocalTransform: Transform.Identity,
             focus: emptyFunction,
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index cef294692..3eaa6e0f4 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -16,7 +16,7 @@ import { undoBatch } from '../../util/UndoManager';
 import { panZoomSchema } from '../collections/collectionFreeForm/CollectionFreeFormView';
 import { ContextMenu } from '../ContextMenu';
 import { ContextMenuProps } from '../ContextMenuItem';
-import { ViewBoxAnnotatableComponent } from "../DocComponent";
+import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent";
 import { PDFViewer } from "../pdf/PDFViewer";
 import { SidebarAnnos } from '../SidebarAnnos';
 import { FieldView, FieldViewProps } from './FieldView';
@@ -28,7 +28,7 @@ type PdfDocument = makeInterface<[typeof documentSchema, typeof panZoomSchema, t
 const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema);
 
 @observer
-export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocument>(PdfDocument) {
+export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, PdfDocument>(PdfDocument, "annotations") {
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PDFBox, fieldKey); }
     private _searchString: string = "";
     private _initialScrollTarget: Opt<Doc>;
@@ -171,9 +171,9 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
         </>;
         const searchTitle = `${!this._searching ? "Open" : "Close"} Search Bar`;
         const curPage = this.Document._curPage || 1;
-        return !this.active() ? (null) :
+        return !this.isContentActive() ? (null) :
             <div className="pdfBox-ui" onKeyDown={e => [KeyCodes.BACKSPACE, KeyCodes.DELETE].includes(e.keyCode) ? e.stopPropagation() : true}
-                onPointerDown={e => e.stopPropagation()} style={{ display: this.active() ? "flex" : "none" }}>
+                onPointerDown={e => e.stopPropagation()} style={{ display: this.isContentActive() ? "flex" : "none" }}>
                 <div className="pdfBox-overlayCont" onPointerDown={(e) => e.stopPropagation()} style={{ left: `${this._searching ? 0 : 100}%` }}>
                     <button className="pdfBox-overlayButton" title={searchTitle} />
                     <input className="pdfBox-searchBar" placeholder="Search" ref={this._searchRef} onChange={this.searchStringChanged}
@@ -203,7 +203,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
                     {this._pageControls ? pageBtns : (null)}
                 </div>
                 <button className="pdfBox-sidebarBtn" title="Toggle Sidebar"
-                    style={{ right: this.sidebarWidth() + 7, display: !this.active() ? "none" : undefined }}
+                    style={{ right: this.sidebarWidth() + 7, display: !this.isContentActive() ? "none" : undefined }}
                     onPointerDown={e => e.stopPropagation()} onClick={e => this.toggleSidebar()} >
                     <FontAwesomeIcon icon={"chevron-left"} size="sm" />
                 </button>
@@ -221,7 +221,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
     }
 
     @computed get renderTitleBox() {
-        const classname = "pdfBox" + (this.active() ? "-interactive" : "");
+        const classname = "pdfBox" + (this.isContentActive() ? "-interactive" : "");
         return <div className={classname} >
             <div className="pdfBox-title-outer">
                 <strong className="pdfBox-title" >{this.props.Document.title}</strong>
@@ -240,7 +240,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
             <PDFViewer {...this.props}
                 pdf={this._pdf!}
                 url={this.pdfUrl!.url.pathname}
-                active={this.active}
+                isContentActive={this.isContentActive}
                 anchorMenuClick={this._sidebarRef.current?.anchorMenuClick}
                 loaded={!Doc.NativeAspect(this.dataDoc) ? this.loaded : undefined}
                 setPdfViewer={this.setPdfViewer}
@@ -259,7 +259,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
                 sidebarAddDocument={this.sidebarAddDocument}
                 moveDocument={this.moveDocument}
                 removeDocument={this.removeDocument}
-                active={this.active}
+                isContentActive={this.isContentActive}
             />
             {this.settingsPanel()}
         </div>;
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 21ab0a2e0..57c88d411 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -713,8 +713,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
 
     whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isChildActive = isActive));
     // For dragging documents into the presentation trail
-    addDocumentFilter = (doc: Doc | Doc[]) => {
-        const docs = doc instanceof Doc ? [doc] : doc;
+    addDocumentFilter = (docs: Doc[]) => {
         docs.forEach((doc, i) => {
             if (doc.presentationTargetDoc) return true;
             if (doc.type === DocumentType.LABEL) {
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 48fc0834f..b4e7c6243 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -19,7 +19,7 @@ import { CurrentUserUtils } from "../../util/CurrentUserUtils";
 import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
 import { CollectionStackedTimeline } from "../collections/CollectionStackedTimeline";
 import { ContextMenu } from "../ContextMenu";
-import { ViewBoxAnnotatableComponent } from "../DocComponent";
+import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent";
 import { FieldView, FieldViewProps } from './FieldView';
 import "./ScreenshotBox.scss";
 import { VideoBox } from "./VideoBox";
@@ -33,7 +33,7 @@ type ScreenshotDocument = makeInterface<[typeof documentSchema]>;
 const ScreenshotDocument = makeInterface(documentSchema);
 
 @observer
-export class ScreenshotBox extends ViewBoxAnnotatableComponent<FieldViewProps, ScreenshotDocument>(ScreenshotDocument) {
+export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, ScreenshotDocument>(ScreenshotDocument, "annotations") {
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScreenshotBox, fieldKey); }
     private _videoRef = React.createRef<HTMLVideoElement>();
     private _audioRec: any;
@@ -159,7 +159,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<FieldViewProps, S
                         isSelected={this.props.isSelected}
                         isAnnotationOverlay={true}
                         select={emptyFunction}
-                        active={returnFalse}
+                        isContentActive={returnFalse}
                         scaling={returnOne}
                         whenChildContentsActiveChanged={emptyFunction}
                         removeDocument={returnFalse}
@@ -181,7 +181,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<FieldViewProps, S
                         isSelected={this.props.isSelected}
                         isAnnotationOverlay={true}
                         select={emptyFunction}
-                        active={returnFalse}
+                        isContentActive={returnFalse}
                         scaling={returnOne}
                         xMargin={25}
                         yMargin={10}
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
index f1f2cd7d3..0afc61f54 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -15,7 +15,7 @@ import { InteractionUtils } from "../../util/InteractionUtils";
 import { CompileScript, Scripting, ScriptParam } from "../../util/Scripting";
 import { ScriptManager } from "../../util/ScriptManager";
 import { ContextMenu } from "../ContextMenu";
-import { ViewBoxAnnotatableComponent } from "../DocComponent";
+import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent";
 import { EditableView } from "../EditableView";
 import { FieldView, FieldViewProps } from "../nodes/FieldView";
 import { OverlayView } from "../OverlayView";
@@ -29,7 +29,7 @@ type ScriptingDocument = makeInterface<[typeof ScriptingSchema, typeof documentS
 const ScriptingDocument = makeInterface(ScriptingSchema, documentSchema);
 
 @observer
-export class ScriptingBox extends ViewBoxAnnotatableComponent<FieldViewProps, ScriptingDocument>(ScriptingDocument) {
+export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, ScriptingDocument>(ScriptingDocument, "annotations") {
 
     private dropDisposer?: DragManager.DragDropDisposer;
     protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer | undefined;
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 0b0f8afd1..f26a4fdbd 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -19,7 +19,7 @@ import { CollectionFreeFormView } from "../collections/collectionFreeForm/Collec
 import { CollectionStackedTimeline } from "../collections/CollectionStackedTimeline";
 import { ContextMenu } from "../ContextMenu";
 import { ContextMenuProps } from "../ContextMenuItem";
-import { ViewBoxAnnotatableComponent } from "../DocComponent";
+import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent";
 import { DocumentDecorations } from "../DocumentDecorations";
 import { MarqueeAnnotator } from "../MarqueeAnnotator";
 import { StyleProp } from "../StyleProvider";
@@ -32,7 +32,7 @@ type VideoDocument = makeInterface<[typeof documentSchema]>;
 const VideoDocument = makeInterface(documentSchema);
 
 @observer
-export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoDocument>(VideoDocument) {
+export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, VideoDocument>(VideoDocument, "annotations") {
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(VideoBox, fieldKey); }
     static _youtubeIframeCounter: number = 0;
     static Instance: VideoBox;
@@ -63,7 +63,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
     private get transition() { return this._clicking ? "left 0.5s, width 0.5s, height 0.5s" : ""; }
     public get player(): HTMLVideoElement | null { return this._videoRef; }
 
-    constructor(props: Readonly<FieldViewProps>) {
+    constructor(props: Readonly<ViewBoxAnnotatableProps & FieldViewProps>) {
         super(props);
         VideoBox.Instance = this;
     }
@@ -309,7 +309,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
         const interactive = CurrentUserUtils.SelectedTool !== InkTool.None || !this.props.isSelected() ? "" : "-interactive";
         const style = "videoBox-content" + (this._fullScreen ? "-fullScreen" : "") + interactive;
         return !field ? <div key="loading">Loading</div> :
-            <div className="container" key="container" style={{ pointerEvents: this._isAnyChildContentActive || this.active() ? "all" : "none" }}>
+            <div className="container" key="container" style={{ pointerEvents: this._isAnyChildContentActive || this.isContentActive() ? "all" : "none" }}>
                 <div className={`${style}`} style={{ width: "100%", height: "100%", left: "0px" }}>
                     <video key="video" autoPlay={this._screenCapture} ref={this.setVideoRef}
                         style={{ height: "100%", width: "auto", display: "flex", margin: "auto" }}
@@ -323,7 +323,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
                         Not supported.
                     </video>
                     {!this.audiopath || this.audiopath === field.url.href ? (null) :
-                        <audio ref={this.setAudioRef} className={`audiobox-control${this.active() ? "-interactive" : ""}`}>
+                        <audio ref={this.setAudioRef} className={`audiobox-control${this.isContentActive() ? "-interactive" : ""}`}>
                             <source src={this.audiopath} type="audio/mpeg" />
                         Not supported.
                     </audio>}
@@ -420,7 +420,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
         setupMoveUpEvents(this, e,
             action((e: PointerEvent) => {
                 this._clicking = false;
-                if (this.active()) {
+                if (this.isContentActive()) {
                     const local = this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).transformPoint(e.clientX, e.clientY);
                     this.layoutDoc._timelineHeightPercent = Math.max(0, Math.min(100, local[1] / this.props.PanelHeight() * 100));
                 }
@@ -429,7 +429,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
             () => {
                 this.layoutDoc._timelineHeightPercent = this.heightPercent !== 100 ? 100 : VideoBox.heightPercent;
                 setTimeout(action(() => this._clicking = false), 500);
-            }, this.active(), this.active());
+            }, this.isContentActive(), this.isContentActive());
     });
 
     onResetDown = (e: React.PointerEvent) => {
@@ -526,7 +526,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
                 isChildActive={this.isActiveChild}
                 Play={this.Play}
                 Pause={this.Pause}
-                active={this.active}
+                isContentActive={this.isContentActive}
                 playLink={this.playLink}
                 PanelHeight={this.timelineHeight}
             />
@@ -538,7 +538,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
     }
 
     marqueeDown = action((e: React.PointerEvent) => {
-        if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.active(true)) this._marqueeing = [e.clientX, e.clientY];
+        if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true)) this._marqueeing = [e.clientX, e.clientY];
     });
 
     finishMarquee = action(() => {
@@ -572,7 +572,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
                         isAnnotationOverlay={true}
                         annotationLayerHostsContent={true}
                         select={emptyFunction}
-                        active={this.annotationsActive}
+                        isContentActive={this.annotationsActive}
                         scaling={returnOne}
                         docFilters={this.timelineDocFilter}
                         PanelWidth={this.panelWidth}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index e7e28ba2b..8c446cf7a 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -21,7 +21,7 @@ import { undoBatch } from "../../util/UndoManager";
 import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
 import { ContextMenu } from "../ContextMenu";
 import { ContextMenuProps } from "../ContextMenuItem";
-import { ViewBoxAnnotatableComponent } from "../DocComponent";
+import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent";
 import { DocumentDecorations } from "../DocumentDecorations";
 import { LightboxView } from "../LightboxView";
 import { MarqueeAnnotator } from "../MarqueeAnnotator";
@@ -39,7 +39,7 @@ type WebDocument = makeInterface<[typeof documentSchema]>;
 const WebDocument = makeInterface(documentSchema);
 
 @observer
-export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocument>(WebDocument) {
+export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, WebDocument>(WebDocument, "annotations") {
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(WebBox, fieldKey); }
     private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean) => void);
     private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
@@ -391,7 +391,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
 
     @action
     onMarqueeDown = (e: React.PointerEvent) => {
-        if (!e.altKey && e.button === 0 && this.active(true)) {
+        if (!e.altKey && e.button === 0 && this.isContentActive(true)) {
             this._marqueeing = [e.clientX, e.clientY];
             this.props.select(false);
         }
@@ -440,7 +440,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
     sidebarWidth = () => !this.layoutDoc._showSidebar ? 0 : (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth);
 
     @computed get content() {
-        return <div className={"webBox-cont" + (!this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.active() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting ? "-interactive" : "")}
+        return <div className={"webBox-cont" + (!this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.isContentActive() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting ? "-interactive" : "")}
             style={{ width: NumCast(this.layoutDoc[this.fieldKey + "-contentWidth"]) || `${100 / (this.props.scaling?.() || 1)}%`, }}>
             {this.urlContent}
         </div>;
@@ -464,7 +464,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
         const inactiveLayer = this.props.layerProvider?.(this.layoutDoc) === false;
         const scale = this.props.scaling?.() || 1;
         return (
-            <div className="webBox" ref={this._mainCont} style={{ pointerEvents: this.annotationsActive() ? "all" : this.active() || SnappingManager.GetIsDragging() ? undefined : "none" }} >
+            <div className="webBox" ref={this._mainCont} style={{ pointerEvents: this.annotationsActive() ? "all" : this.isContentActive() || SnappingManager.GetIsDragging() ? undefined : "none" }} >
                 <div className={`webBox-container`}
                     style={{ pointerEvents: inactiveLayer ? "none" : undefined }}
                     onContextMenu={this.specificContextMenu}>
@@ -493,7 +493,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
                                 PanelHeight={this.panelHeight}
                                 dropAction={"alias"}
                                 select={emptyFunction}
-                                active={this.active}
+                                isContentActive={this.isContentActive}
                                 ContentScaling={returnOne}
                                 bringToFront={emptyFunction}
                                 whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
@@ -524,7 +524,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
                             mainCont={this._mainCont.current} />}
                 </div >
                 <button className="webBox-overlayButton-sidebar" key="sidebar" title="Toggle Sidebar"
-                    style={{ right: this.sidebarWidth() + 7, display: !this.active() ? "none" : undefined }}
+                    style={{ right: this.sidebarWidth() + 7, display: !this.isContentActive() ? "none" : undefined }}
                     onPointerDown={e => e.stopPropagation()} onClick={e => this.toggleSidebar()} >
                     <FontAwesomeIcon style={{ color: "white" }} icon={"chevron-left"} size="sm" />
                 </button>
@@ -538,7 +538,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
                     sidebarAddDocument={this.sidebarAddDocument}
                     moveDocument={this.moveDocument}
                     removeDocument={this.removeDocument}
-                    active={this.active}
+                    isContentActive={this.isContentActive}
                 />
             </div>);
     }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index bc746f157..28e58f6d8 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -782,7 +782,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
 
     componentDidMount() {
         this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document.  this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
-        this.props.contentsActive?.(this.active);
+        this.props.contentsActive?.(this.isContentActive);
         this._cachedLinks = DocListCast(this.Document.links);
         this._disposers.breakupDictation = reaction(() => DocumentManager.Instance.RecordingEvent, this.breakupDictation);
         this._disposers.autoHeight = reaction(() => this.autoHeight, autoHeight => autoHeight && this.tryUpdateScrollHeight());
@@ -1192,7 +1192,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         if ((e.nativeEvent as any).formattedHandled) {
             console.log("handled");
         }
-        if (!(e.nativeEvent as any).formattedHandled && this.active(true)) {
+        if (!(e.nativeEvent as any).formattedHandled && this.isContentActive(true)) {
             const editor = this._editorView!;
             const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY });
             !this.props.isSelected(true) && editor.dispatch(editor.state.tr.setSelection(new TextSelection(editor.state.doc.resolve(pcords?.pos || 0))));
@@ -1422,7 +1422,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 const proseHeight = this.ProseRef?.scrollHeight || 0;
                 const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight);
                 if (scrollHeight && this.props.renderDepth && !this.props.dontRegisterView) {  // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
-                    const setScrollHeight = () => this.rootDoc[this.fieldKey + "-scrollHeight"] = scrollHeight;
+                    const setScrollHeight = () => {
+                        this.rootDoc[this.fieldKey + "-scrollHeight"] = scrollHeight;
+                    };
                     if (this.rootDoc === this.layoutDoc.doc || this.layoutDoc.resolvedDataDoc) {
                         setScrollHeight();
                     } else setTimeout(setScrollHeight, 10); // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template.  So set a timeout and hope its arrived...
@@ -1447,7 +1449,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     @computed get sidebarHandle() {
         TraceMobx();
         const annotated = DocListCast(this.dataDoc[this.SidebarKey]).filter(d => d?.author).length;
-        return (!annotated && !this.active()) ? (null) : <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown}
+        return (!annotated && !this.isContentActive()) ? (null) : <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown}
             style={{
                 left: `max(0px, calc(100% - ${this.sidebarWidthPercent} ${this.sidebarWidth() ? "- 5px" : "- 10px"}))`,
                 background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.WidgetColor + (annotated ? ":annotated" : ""))
@@ -1467,7 +1469,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 scaleField={this.SidebarKey + "-scale"}
                 isAnnotationOverlay={false}
                 select={emptyFunction}
-                active={this.annotationsActive}
+                isContentActive={this.annotationsActive}
                 scaling={this.sidebarContentScaling}
                 whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                 removeDocument={this.sidebarRemDocument}
@@ -1489,7 +1491,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     render() {
         TraceMobx();
         const selected = this.props.isSelected();
-        const active = this.active();
+        const active = this.isContentActive();
         const scale = this.props.hideOnLeave ? 1 : (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
         const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : "";
         const interactive = (CurrentUserUtils.SelectedTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || this.props.layerProvider?.(this.layoutDoc) !== false);
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index b100701a3..35d4c497d 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -158,7 +158,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
     }
 
     copy = (e: ClipboardEvent) => {
-        if (this.active() && e.clipboardData) {
+        if (this.isContentActive() && e.clipboardData) {
             e.clipboardData.setData("text/plain", this._selectionText);
             e.preventDefault();
         }
@@ -375,10 +375,10 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
         this._downX = e.clientX;
         this._downY = e.clientY;
         if ((this.Document._viewScale || 1) !== 1) return;
-        if ((e.button !== 0 || e.altKey) && this.active(true)) {
+        if ((e.button !== 0 || e.altKey) && this.isContentActive(true)) {
             this._setPreviewCursor?.(e.clientX, e.clientY, true);
         }
-        if (!e.altKey && e.button === 0 && this.props.active(true)) {
+        if (!e.altKey && e.button === 0 && this.props.isContentActive(true)) {
             this.props.select(false);
             this._marqueeing = [e.clientX, e.clientY];
             if (e.target && ((e.target as any).className.includes("endOfContent") || ((e.target as any).parentElement.className !== "textLayer"))) {
@@ -482,7 +482,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
 
     @action
     onZoomWheel = (e: React.WheelEvent) => {
-        if (this.active(true)) {
+        if (this.isContentActive(true)) {
             e.stopPropagation();
             if (e.ctrlKey) {
                 const curScale = Number(this._pdfViewer.currentScaleValue);
@@ -528,7 +528,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
                 PanelWidth={this.panelWidth}
                 dropAction={"alias"}
                 select={emptyFunction}
-                active={this.annotationsActive}
+                isContentActive={this.annotationsActive}
                 ContentScaling={this.contentZoom}
                 bringToFront={emptyFunction}
                 whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
@@ -542,7 +542,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
         </div>;
     }
     @computed get pdfViewerDiv() {
-        return <div className={"pdfViewerDash-text" + (this._textSelecting && (this.props.isSelected() || this.props.active()) ? "-selected" : "")} ref={this._viewer} />;
+        return <div className={"pdfViewerDash-text" + (this._textSelecting && (this.props.isSelected() || this.props.isContentActive()) ? "-selected" : "")} ref={this._viewer} />;
     }
     @computed get contentScaling() { return this.props.ContentScaling?.() || 1; }
     @computed get standinViews() {
diff --git a/src/fields/util.ts b/src/fields/util.ts
index ea91cc057..6c9c9d45c 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -19,7 +19,7 @@ function _readOnlySetter(): never {
     throw new Error("Documents can't be modified in read-only mode");
 }
 
-const tracing = false;
+const tracing = true;
 export function TraceMobx() {
     tracing && trace();
 }
-- 
cgit v1.2.3-70-g09d2


From 589f07ea018368057fe80b136c3fd2153efe0fcb Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 29 Mar 2021 20:36:47 -0400
Subject: fixed text input after changes to active/selected

---
 src/client/util/DragManager.ts                                     | 7 +------
 src/client/views/DocComponent.tsx                                  | 4 ++--
 .../collections/collectionFreeForm/CollectionFreeFormView.tsx      | 2 +-
 src/client/views/nodes/formattedText/FormattedTextBox.tsx          | 4 +---
 src/fields/util.ts                                                 | 2 +-
 5 files changed, 6 insertions(+), 13 deletions(-)

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

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index abf1af669..c1235163b 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -379,12 +379,7 @@ export namespace DragManager {
             if (docsBeingDragged.length) {
                 const pdfBox = dragElement.getElementsByTagName("canvas");
                 const pdfBoxSrc = ele.getElementsByTagName("canvas");
-                Array.from(pdfBox).filter(pb => pb.width && pb.height).map((pb, i) => {
-                    const context = pb.getContext('2d')!;
-                    console.log(getComputedStyle(pb).width);
-                    console.log(getComputedStyle(pdfBoxSrc[i]).width);
-                    context.drawImage(pdfBoxSrc[i], 0, 0);
-                });
+                Array.from(pdfBox).filter(pb => pb.width && pb.height).map((pb, i) => pb.getContext('2d')!.drawImage(pdfBoxSrc[i], 0, 0));
             }
             [dragElement, ...Array.from(dragElement.getElementsByTagName('*'))].forEach(ele =>
                 ele.hasAttribute("style") && ((ele as any).style.pointerEvents = "none"));
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 5c0fe6b97..566e884c5 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -203,10 +203,10 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
 
                     if (effectiveAcl === AclAddonly) {
                         added.map(doc => {
-                            this.props.layerProvider?.(doc, true);
-                            Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
                             doc.context = this.props.Document;
                             if (annotationKey ?? this._annotationKey) Doc.GetProto(doc).annotationOn = this.props.Document;
+                            this.props.layerProvider?.(doc, true);
+                            Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
                         });
                     }
                     else {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index b74bca5d3..cf48a9237 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1043,7 +1043,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             freezeDimensions={this.props.childFreezeDimensions}
             dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             bringToFront={this.bringToFront}
-            isDocumentActive={() => this.props.isContentActive()}
+            isDocumentActive={this.props.isContentActive}
             dontRegisterView={this.props.dontRegisterView}
             pointerEvents={this.backgroundActive || this.props.childPointerEvents ? "all" :
                 (this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? "none" : undefined}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 28e58f6d8..7787dc3a6 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1422,9 +1422,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 const proseHeight = this.ProseRef?.scrollHeight || 0;
                 const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight);
                 if (scrollHeight && this.props.renderDepth && !this.props.dontRegisterView) {  // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
-                    const setScrollHeight = () => {
-                        this.rootDoc[this.fieldKey + "-scrollHeight"] = scrollHeight;
-                    };
+                    const setScrollHeight = () => this.rootDoc[this.fieldKey + "-scrollHeight"] = scrollHeight;
                     if (this.rootDoc === this.layoutDoc.doc || this.layoutDoc.resolvedDataDoc) {
                         setScrollHeight();
                     } else setTimeout(setScrollHeight, 10); // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template.  So set a timeout and hope its arrived...
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 6c9c9d45c..ea91cc057 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -19,7 +19,7 @@ function _readOnlySetter(): never {
     throw new Error("Documents can't be modified in read-only mode");
 }
 
-const tracing = true;
+const tracing = false;
 export function TraceMobx() {
     tracing && trace();
 }
-- 
cgit v1.2.3-70-g09d2


From 96fd7e51d56bdd95a9f54d61090f45cd0dd17e6a Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 29 Mar 2021 22:37:58 -0400
Subject: more progress in fixing & simplifying active/selected stuff

---
 src/client/views/DocComponent.tsx                       |  8 +++-----
 src/client/views/MainView.tsx                           |  3 +++
 src/client/views/SidebarAnnos.tsx                       |  2 --
 src/client/views/StyleProvider.tsx                      | 17 +++++------------
 .../views/collections/CollectionStackedTimeline.tsx     |  8 ++++----
 src/client/views/collections/CollectionStackingView.tsx |  5 ++++-
 src/client/views/collections/CollectionTreeView.tsx     |  1 +
 src/client/views/collections/TabDocView.tsx             |  3 ++-
 src/client/views/collections/TreeView.tsx               |  6 ++++--
 .../collectionFreeForm/CollectionFreeFormView.tsx       |  7 +++++--
 .../collectionMulticolumn/CollectionMulticolumnView.tsx |  1 +
 .../collectionMulticolumn/CollectionMultirowView.tsx    |  1 +
 src/client/views/nodes/AudioBox.tsx                     |  1 -
 .../views/nodes/CollectionFreeFormDocumentView.tsx      |  2 +-
 src/client/views/nodes/ColorBox.tsx                     |  2 +-
 src/client/views/nodes/DocumentView.tsx                 | 10 ++++++----
 src/client/views/nodes/FunctionPlotBox.tsx              |  2 +-
 src/client/views/nodes/ImageBox.tsx                     |  2 +-
 src/client/views/nodes/LinkBox.tsx                      |  2 +-
 src/client/views/nodes/PDFBox.tsx                       |  2 +-
 src/client/views/nodes/PresBox.tsx                      |  2 +-
 src/client/views/nodes/VideoBox.tsx                     |  4 +---
 src/client/views/nodes/WebBox.tsx                       |  3 +--
 .../views/nodes/formattedText/FormattedTextBox.tsx      |  2 +-
 src/client/views/pdf/PDFViewer.tsx                      |  4 ++--
 src/client/views/presentationview/PresElementBox.tsx    |  3 ++-
 26 files changed, 53 insertions(+), 50 deletions(-)

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

diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 566e884c5..74c4e57ab 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -64,7 +64,7 @@ export function ViewBoxBaseComponent<P extends ViewBoxBaseProps, T>(schemaCtor:
 
         lookupField = (field: string) => ScriptCast(this.layoutDoc.lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field, container: this.props.ContainingCollectionDoc }).result;
 
-        active = (outsideReaction?: boolean) => this.props.layerProvider?.(this.props.Document) !== false && (this.props.rootSelected(outsideReaction) || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0 || this.layoutDoc.forceActive);//  && !Doc.SelectedTool();  // bcz: inking state shouldn't affect static tools 
+        isContentActive = (outsideReaction?: boolean) => this.props.layerProvider?.(this.props.Document) !== false && (this.props.rootSelected(outsideReaction) || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0 || this.layoutDoc.forceActive);//  && !Doc.SelectedTool();  // bcz: inking state shouldn't affect static tools 
         protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
     }
     return Component;
@@ -228,11 +228,9 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
         }
 
         whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive));
-        isContentActive = (outsideReaction?: boolean) => (CurrentUserUtils.SelectedTool === InkTool.None &&
-            (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.renderDepth === 0 || this.props.rootSelected(outsideReaction)) ? true : false)
-        annotationsActive = (outsideReaction?: boolean) => (CurrentUserUtils.SelectedTool !== InkTool.None ||
+        isContentActive = (outsideReaction?: boolean) => (CurrentUserUtils.SelectedTool !== InkTool.None ||
             (this.props.layerProvider?.(this.props.Document) !== false && this.props.isContentActive?.()) ||
-            (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.renderDepth === 0) ? true : false)
+            (this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.renderDepth === 0 || this.props.rootSelected(outsideReaction)) ? true : false)
     }
     return Component;
 }
\ No newline at end of file
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 83949eba2..944430aaa 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -253,6 +253,7 @@ export class MainView extends React.Component {
             layerProvider={undefined}
             styleProvider={undefined}
             rootSelected={returnTrue}
+            isContentActive={returnFalse}
             removeDocument={undefined}
             ScreenToLocalTransform={Transform.Identity}
             PanelWidth={this.getPWidth}
@@ -348,6 +349,7 @@ export class MainView extends React.Component {
                         PanelWidth={this.flyoutWidthFunc}
                         PanelHeight={this.getContentsHeight}
                         renderDepth={0}
+                        isContentActive={returnTrue}
                         scriptContext={CollectionDockingView.Instance.props.Document}
                         focus={DocUtils.DefaultFocus}
                         whenChildContentsActiveChanged={emptyFunction}
@@ -381,6 +383,7 @@ export class MainView extends React.Component {
                 focus={DocUtils.DefaultFocus}
                 styleProvider={DefaultStyleProvider}
                 layerProvider={undefined}
+                isContentActive={returnTrue}
                 whenChildContentsActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
                 docFilters={returnEmptyFilter}
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 4514e3ebb..5988653d7 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -22,7 +22,6 @@ interface ExtraProps {
     layoutDoc: Doc;
     rootDoc: Doc;
     dataDoc: Doc;
-    annotationsActive: (outsideReaction: boolean) => boolean;
     whenChildContentsActiveChanged: (isActive: boolean) => void;
     ScreenToLocalTransform: () => Transform;
     sidebarAddDocument: (doc: (Doc | Doc[]), suffix: string) => boolean;
@@ -120,7 +119,6 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
                         scaleField={this.sidebarKey() + "-scale"}
                         isAnnotationOverlay={false}
                         select={emptyFunction}
-                        isContentActive={this.props.annotationsActive}
                         scaling={returnOne}
                         whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
                         childHideDecorationTitle={returnTrue}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index d78446bf6..48689705c 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -54,13 +54,13 @@ function toggleBackground(doc: Doc) {
 }
 
 export function testDocProps(toBeDetermined: any): toBeDetermined is DocumentViewProps {
-    return (toBeDetermined?.active) ? undefined : toBeDetermined;
+    return (toBeDetermined?.isContentActive) ? undefined : toBeDetermined;
 }
 
 //
 // a preliminary implementation of a dash style sheet for setting rendering properties of documents nested within a Tab
 // 
-export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps | DocumentViewProps>, property: string): any {
+export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any {
     const docProps = testDocProps(props) ? props : undefined;
     const selected = property.includes(":selected");
     const isCaption = property.includes(":caption");
@@ -96,18 +96,11 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps |
             if (isCaption) return "rgba(0,0,0 ,0.4)";
             if (Doc.UserDoc().renderStyle === "comic") return "transparent";
             let docColor: Opt<string> = StrCast(doc?._backgroundColor);
-            if (!docProps) {
-                if (MainView.Instance.LastButton === doc) return darkScheme() ? "dimgrey" : "lightgrey";
-                switch (doc?.type) {
-                    case DocumentType.FONTICON: return docColor || "black";
-                    case DocumentType.LINK: return docColor || "lightblue";
-                    default: undefined;
-                }
-            }
+            if (MainView.Instance.LastButton === doc) return darkScheme() ? "dimgrey" : "lightgrey";
             switch (doc?.type) {
                 case DocumentType.PRESELEMENT: docColor = docColor || (darkScheme() ? "" : ""); break;
                 case DocumentType.PRES: docColor = docColor || (darkScheme() ? "#3e3e3e" : "white"); break;
-                case DocumentType.FONTICON: docColor = undefined; break;
+                case DocumentType.FONTICON: docColor = docColor || "black"; break;
                 case DocumentType.RTF: docColor = docColor || (darkScheme() ? "#2d2d2d" : "#f1efeb"); break;
                 case DocumentType.FILTER: docColor = docColor || (darkScheme() ? "#2d2d2d" : "rgba(105, 105, 105, 0.432)"); break;
                 case DocumentType.INK: docColor = doc?.isInkMask ? "rgba(0,0,0,0.7)" : undefined; break;
@@ -115,7 +108,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps |
                 case DocumentType.EQUATION: docColor = docColor || "transparent"; break;
                 case DocumentType.LABEL: docColor = docColor || (doc.annotationOn !== undefined ? "rgba(128, 128, 128, 0.18)" : undefined); break;
                 case DocumentType.BUTTON: docColor = docColor || (darkScheme() ? "#2d2d2d" : "lightgray"); break;
-                case DocumentType.LINK: return "transparent";
+                case DocumentType.LINK: return docColor || "lightblue";
                 case DocumentType.WEB:
                 case DocumentType.PDF:
                 case DocumentType.SCREENSHOT:
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index d6aca6f00..3168ef4ba 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -32,7 +32,6 @@ export type CollectionStackedTimelineProps = {
     playFrom: (seekTimeInSeconds: number, endTime?: number) => void;
     playing: () => boolean;
     setTime: (time: number) => void;
-    isChildActive: () => boolean;
     startTag: string;
     endTag: string;
     mediaPath: string;
@@ -145,7 +144,7 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
                     e.shiftKey && CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this.props.startTag, this.props.endTag, this.currentTime);
                     !wasPlaying && doubleTap && this.props.Play();
                 },
-                this.props.isSelected(true) || this.props.isChildActive(), undefined,
+                this.props.isSelected(true) || this.props.isContentActive(), undefined,
                 () => !wasPlaying && this.props.setTime((clientX - rect.x) / rect.width * this.duration));
         }
     }
@@ -244,6 +243,7 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
                 Document={dictation}
                 PanelHeight={this.dictationHeight}
                 isAnnotationOverlay={true}
+                isDocumentActive={returnFalse}
                 select={emptyFunction}
                 scaling={returnOne}
                 xMargin={25}
@@ -274,7 +274,7 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
         const overlaps: { anchorStartTime: number, anchorEndTime: number, level: number }[] = [];
         const drawAnchors = this.childDocs.map(anchor => ({ level: this.getLevel(anchor, overlaps), anchor }));
         const maxLevel = overlaps.reduce((m, o) => Math.max(m, o.level), 0) + 2;
-        const isActive = this.props.isChildActive() || this.props.isSelected(false);
+        const isActive = this.props.isContentActive() || this.props.isSelected(false);
         return <div className="collectionStackedTimeline" ref={(timeline: HTMLDivElement | null) => this._timeline = timeline}
             onClick={e => isActive && StopEvent(e)} onPointerDown={e => isActive && this.onPointerDownTimeline(e)}>
             {drawAnchors.map(d => {
@@ -323,7 +323,6 @@ interface StackedTimelineAnchorProps {
     toTimeline: (screen_delta: number, width: number) => number;
     playLink: (linkDoc: Doc) => void;
     setTime: (time: number) => void;
-    isChildActive: () => boolean;
     startTag: string;
     endTag: string;
     renderDepth: number;
@@ -395,6 +394,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
                 renderDepth={this.props.renderDepth + 1}
                 LayoutTemplate={undefined}
                 LayoutTemplateString={LabelBox.LayoutString("data")}
+                isDocumentActive={returnFalse}
                 PanelWidth={() => width}
                 PanelHeight={() => height}
                 ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-x, -y)}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 4dab9d94a..fe42d7df0 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -196,7 +196,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
         });
     }
 
-    styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps | FieldViewProps>, property: string) => {
+    styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string) => {
         if (property === StyleProp.Opacity && doc) {
             if (this.props.childOpacity) {
                 return this.props.childOpacity();
@@ -207,6 +207,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
         }
         return this.props.styleProvider?.(doc, props, property);
     }
+    isContentActive = () => this.props.isSelected() || this.props.isContentActive();
     getDisplayDoc(doc: Doc, width: () => number) {
         const dataDoc = (!doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS) ? undefined : this.props.DataDoc;
         const height = () => this.getDocHeight(doc);
@@ -224,6 +225,8 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
             layerProvider={this.props.layerProvider}
             docViewPath={this.props.docViewPath}
             fitWidth={this.props.childFitWidth}
+            isContentActive={returnFalse}
+            isDocumentActive={this.isContentActive}
             LayoutTemplate={this.props.childLayoutTemplate}
             LayoutTemplateString={this.props.childLayoutString}
             freezeDimensions={this.props.childFreezeDimensions}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index f69a3a331..84285b5b5 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -165,6 +165,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
                 DataDoc={undefined}
                 LayoutTemplateString={FormattedTextBox.LayoutString("text")}
                 renderDepth={this.props.renderDepth + 1}
+                isContentActive={returnTrue}
                 rootSelected={returnTrue}
                 //dontRegisterView={true}
                 docViewPath={this.props.docViewPath}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index ec3f3090b..c413208d2 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -309,6 +309,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined}
+                isContentActive={returnFalse}
                 PanelWidth={this.PanelWidth}
                 PanelHeight={this.PanelHeight}
                 layerProvider={this.layerProvider}
@@ -367,7 +368,7 @@ interface TabMinimapViewProps {
 }
 @observer
 export class TabMinimapView extends React.Component<TabMinimapViewProps> {
-    static miniStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps | FieldViewProps>, property: string): any => {
+    static miniStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => {
         if (doc) {
             switch (property.split(":")[0]) {
                 default: return DefaultStyleProvider(doc, props, property);
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index e89c594fd..6add513c4 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -511,7 +511,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             e.preventDefault();
         }
     }
-    titleStyleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps | FieldViewProps>, property: string): any => {
+    titleStyleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps>, property: string): any => {
         if (!doc || doc !== this.doc) return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
 
         switch (property.split(":")[0]) {
@@ -527,7 +527,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             case StyleProp.Decorations: return (null);
         }
     }
-    embeddedStyleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps | FieldViewProps>, property: string): any => {
+    embeddedStyleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps>, property: string): any => {
         if (property.startsWith(StyleProp.Decorations)) return (null);
         return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
     }
@@ -603,6 +603,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 PanelHeight={() => 18}
                 contextMenuItems={this.contextMenuItems}
                 renderDepth={1}
+                isContentActive={returnFalse}
                 focus={returnTrue}
                 whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
                 bringToFront={emptyFunction}
@@ -675,6 +676,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             ScreenToLocalTransform={this.docTransform}
             renderDepth={this.props.renderDepth + 1}
             rootSelected={returnTrue}
+            isContentActive={returnFalse}
             styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider}
             layerProvider={this.props.layerProvider}
             docViewPath={this.props.treeView.props.docViewPath}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index cf48a9237..950fc4a25 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -420,7 +420,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         }
     }
 
-    getClusterColor = (doc: Opt<Doc>, props: Opt<DocumentViewProps | FieldViewProps>, property: string) => {
+    getClusterColor = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => {
         let styleProp = this.props.styleProvider?.(doc, props, property);  // bcz: check 'props'  used to be renderDepth + 1
         if (property !== StyleProp.BackgroundColor) return styleProp;
         const cluster = NumCast(doc?.cluster);
@@ -1005,6 +1005,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         };
     }
 
+    isContentActive = () => this.props.isSelected() || this.props.isContentActive();
+
     getChildDocView(entry: PoolData) {
         const childLayout = entry.pair.layout;
         const childData = entry.pair.data;
@@ -1028,6 +1030,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             docFilters={this.freeformDocFilters}
             docRangeFilters={this.freeformRangeDocFilters}
             searchFilterDocs={this.searchFilterDocs}
+            isContentActive={this.isAnnotationOverlay ? this.props.isContentActive : returnFalse}
+            isDocumentActive={this.isContentActive}
             focus={this.focusDocument}
             addDocTab={this.addDocTab}
             addDocument={this.props.addDocument}
@@ -1043,7 +1047,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             freezeDimensions={this.props.childFreezeDimensions}
             dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             bringToFront={this.bringToFront}
-            isDocumentActive={this.props.isContentActive}
             dontRegisterView={this.props.dontRegisterView}
             pointerEvents={this.backgroundActive || this.props.childPointerEvents ? "all" :
                 (this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? "none" : undefined}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 3fea34037..8b5c02b75 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -223,6 +223,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
             LayoutTemplateString={this.props.childLayoutString}
             freezeDimensions={this.props.childFreezeDimensions}
             renderDepth={this.props.renderDepth + 1}
+            isContentActive={returnFalse}
             PanelWidth={width}
             PanelHeight={height}
             rootSelected={this.rootSelected}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 7bbb9ea71..2c5e40d02 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -232,6 +232,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
             ScreenToLocalTransform={dxf}
             focus={this.props.focus}
             docFilters={this.docFilters}
+            isContentActive={returnFalse}
             docRangeFilters={this.docRangeFilters}
             searchFilterDocs={this.searchFilterDocs}
             ContainingCollectionDoc={this.props.CollectionView?.props.Document}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 970f9bd95..b714ae30f 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -334,7 +334,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             whenChildContentsActiveChanged={this.timelineWhenChildContentsActiveChanged}
             removeDocument={this.removeDocument}
             ScreenToLocalTransform={this.timelineScreenToLocal}
-            isChildActive={this.isActiveChild}
             Play={this.Play}
             Pause={this.Pause}
             isContentActive={this.isContentActive}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index e96fc088e..1fda4cc5e 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -49,7 +49,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     @computed get dataProvider() { return this.props.dataProvider?.(this.props.Document, this.props.replica); }
     @computed get sizeProvider() { return this.props.sizeProvider?.(this.props.Document, this.props.replica); }
 
-    styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps | FieldViewProps>, property: string) => {
+    styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string) => {
         if (property === StyleProp.Opacity && doc === this.layoutDoc) return this.Opacity; // only change the opacity for this specific document, not its children
         return this.props.styleProvider?.(doc, props, property);
     }
diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx
index 59a26f323..3c79d0ec0 100644
--- a/src/client/views/nodes/ColorBox.tsx
+++ b/src/client/views/nodes/ColorBox.tsx
@@ -50,7 +50,7 @@ export class ColorBox extends ViewBoxBaseComponent<FieldViewProps, ColorDocument
 
     render() {
         const scaling = Math.min(this.layoutDoc.fitWidth ? 10000 : this.props.PanelHeight() / this.rootDoc[HeightSym](), this.props.PanelWidth() / this.rootDoc[WidthSym]());
-        return <div className={`colorBox-container${this.active() ? "-interactive" : ""}`}
+        return <div className={`colorBox-container${this.isContentActive() ? "-interactive" : ""}`}
             onPointerDown={e => e.button === 0 && !e.ctrlKey && e.stopPropagation()} onClick={e => e.stopPropagation()}
             style={{ transform: `scale(${scaling})`, width: `${100 * scaling}%`, height: `${100 * scaling}%` }} >
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index e4f1ac8ed..b5c61fba2 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -75,7 +75,7 @@ export interface DocFocusOptions {
 }
 export type DocAfterFocusFunc = (notFocused: boolean) => Promise<ViewAdjustment>;
 export type DocFocusFunc = (doc: Doc, options?: DocFocusOptions) => void;
-export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<DocumentViewProps | FieldViewProps>, property: string) => any;
+export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => any;
 export interface DocComponentView {
     getAnchor?: () => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box)
     scrollFocus?: (doc: Doc, smooth: boolean) => Opt<number>; // returns the duration of the focus
@@ -110,7 +110,7 @@ export interface DocumentViewSharedProps {
     whenChildContentsActiveChanged: (isActive: boolean) => void;
     rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected
     addDocTab: (doc: Doc, where: string) => boolean;
-    filterAddDocument?: (doc: []) => boolean;  // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
+    filterAddDocument?: (doc: Doc[]) => boolean;  // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
     addDocument?: (doc: Doc | Doc[]) => boolean;
     removeDocument?: (doc: Doc | Doc[]) => boolean;
     moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
@@ -132,7 +132,7 @@ export interface DocumentViewProps extends DocumentViewSharedProps {
     hideDecorationTitle?: boolean;  // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings
     treeViewDoc?: Doc;
     isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events
-    isContentActive?: () => boolean | undefined; // whether a document should handle pointer events
+    isContentActive: () => boolean | undefined; // whether a document should handle pointer events
     contentPointerEvents?: string; // pointer events allowed for content of a document view.  eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
     radialMenu?: String[];
     LayoutTemplateString?: string;
@@ -763,6 +763,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     setContentView = (view: { getAnchor?: () => Doc, forward?: () => boolean, back?: () => boolean }) => this._componentView = view;
     @observable contentsActive: () => boolean = returnFalse;
     @action setContentsActive = (setActive: () => boolean) => this.contentsActive = setActive;
+    isContentActive = (outsideReaction?: boolean) => this.props.isContentActive() ? true : false;
     @computed get contents() {
         TraceMobx();
         const audioView = !this.layoutDoc._showAudio ? (null) :
@@ -786,6 +787,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 scaling={this.contentScaling}
                 PanelHeight={this.panelHeight}
                 setHeight={this.setHeight}
+                isContentActive={this.isContentActive}
                 contentsActive={this.setContentsActive}
                 ScreenToLocalTransform={this.screenToLocal}
                 rootSelected={this.rootSelected}
@@ -804,7 +806,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     hideLinkAnchor = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && (doc.hidden = true), true)
     anchorPanelWidth = () => this.props.PanelWidth() || 1;
     anchorPanelHeight = () => this.props.PanelHeight() || 1;
-    anchorStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps | FieldViewProps>, property: string): any => {
+    anchorStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => {
         return property !== StyleProp.LinkSource ? this.props.styleProvider?.(doc, props, property + ":anchor") : this.props.Document; // pass the LinkSource to the LinkAnchorBox
     }
     @computed get directLinks() { TraceMobx(); return LinkManager.Instance.getAllDirectLinks(this.rootDoc); }
diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx
index 4be7d1c37..b00f97236 100644
--- a/src/client/views/nodes/FunctionPlotBox.tsx
+++ b/src/client/views/nodes/FunctionPlotBox.tsx
@@ -80,7 +80,7 @@ export class FunctionPlotBox extends ViewBoxBaseComponent<FieldViewProps, Equati
         TraceMobx();
         return (<div
             style={{
-                pointerEvents: !this.active() ? "all" : undefined,
+                pointerEvents: !this.isContentActive() ? "all" : undefined,
                 width: this.props.PanelWidth(),
                 height: this.props.PanelHeight()
             }}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 0f2e3e65d..630aa88c3 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -358,7 +358,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 focus={this.props.focus}
                 isSelected={this.props.isSelected}
                 select={emptyFunction}
-                isContentActive={this.annotationsActive}
+                isContentActive={this.isContentActive}
                 whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}>
                 {this.contentFunc}
             </CollectionFreeFormView>
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index f542652d0..41085ffff 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -17,7 +17,7 @@ const LinkDocument = makeInterface(documentSchema);
 export class LinkBox extends ViewBoxBaseComponent<FieldViewProps, LinkDocument>(LinkDocument) {
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkBox, fieldKey); }
     render() {
-        return <div className={`linkBox-container${this.active() ? "-interactive" : ""}`}
+        return <div className={`linkBox-container${this.isContentActive() ? "-interactive" : ""}`}
             style={{ background: this.props.styleProvider?.(this.props.Document, this.props, StyleProp.BackgroundColor) }} >
 
             <CollectionTreeView {...this.props}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 3eaa6e0f4..d4cd44a61 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -252,10 +252,10 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             />
             <SidebarAnnos ref={this._sidebarRef}
                 {...this.props}
-                annotationsActive={this.annotationsActive}
                 rootDoc={this.rootDoc}
                 layoutDoc={this.layoutDoc}
                 dataDoc={this.dataDoc}
+                whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                 sidebarAddDocument={this.sidebarAddDocument}
                 moveDocument={this.moveDocument}
                 removeDocument={this.removeDocument}
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 57c88d411..8c5f77550 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -748,7 +748,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc);
     getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight
     panelHeight = () => this.props.PanelHeight() - 40;
-    active = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && this.props.layerProvider?.(this.layoutDoc) !== false) &&
+    isContentActive = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && this.props.layerProvider?.(this.layoutDoc) !== false) &&
         (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
 
     /**
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index f26a4fdbd..414bc9820 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -501,7 +501,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     }
 
     playing = () => this._playing;
-    isActiveChild = () => this._isAnyChildContentActive;
     timelineWhenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive));
     timelineScreenToLocal = () => this.props.ScreenToLocalTransform().scale(this.scaling()).translate(0, -this.heightPercent / 100 * this.props.PanelHeight());
     setAnchorTime = (time: number) => this.player!.currentTime = this.layoutDoc._currentTimecode = time;
@@ -523,7 +522,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 whenChildContentsActiveChanged={this.timelineWhenChildContentsActiveChanged}
                 removeDocument={this.removeDocument}
                 ScreenToLocalTransform={this.timelineScreenToLocal}
-                isChildActive={this.isActiveChild}
                 Play={this.Play}
                 Pause={this.Pause}
                 isContentActive={this.isContentActive}
@@ -572,7 +570,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         isAnnotationOverlay={true}
                         annotationLayerHostsContent={true}
                         select={emptyFunction}
-                        isContentActive={this.annotationsActive}
+                        isContentActive={this.isContentActive}
                         scaling={returnOne}
                         docFilters={this.timelineDocFilter}
                         PanelWidth={this.panelWidth}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 8c446cf7a..c985edb5b 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -464,7 +464,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         const inactiveLayer = this.props.layerProvider?.(this.layoutDoc) === false;
         const scale = this.props.scaling?.() || 1;
         return (
-            <div className="webBox" ref={this._mainCont} style={{ pointerEvents: this.annotationsActive() ? "all" : this.isContentActive() || SnappingManager.GetIsDragging() ? undefined : "none" }} >
+            <div className="webBox" ref={this._mainCont} style={{ pointerEvents: this.isContentActive() ? "all" : this.isContentActive() || SnappingManager.GetIsDragging() ? undefined : "none" }} >
                 <div className={`webBox-container`}
                     style={{ pointerEvents: inactiveLayer ? "none" : undefined }}
                     onContextMenu={this.specificContextMenu}>
@@ -531,7 +531,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 <SidebarAnnos ref={this._sidebarRef}
                     {...this.props}
                     fieldKey={this.annotationKey}
-                    annotationsActive={this.annotationsActive}
                     rootDoc={this.rootDoc}
                     layoutDoc={this.layoutDoc}
                     dataDoc={this.dataDoc}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 7787dc3a6..89aa687cb 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1467,7 +1467,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 scaleField={this.SidebarKey + "-scale"}
                 isAnnotationOverlay={false}
                 select={emptyFunction}
-                isContentActive={this.annotationsActive}
+                isContentActive={this.isContentActive}
                 scaling={this.sidebarContentScaling}
                 whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                 removeDocument={this.sidebarRemDocument}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 35d4c497d..16cf55d1a 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -528,7 +528,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
                 PanelWidth={this.panelWidth}
                 dropAction={"alias"}
                 select={emptyFunction}
-                isContentActive={this.annotationsActive}
+                isContentActive={this.isContentActive}
                 ContentScaling={this.contentZoom}
                 bringToFront={emptyFunction}
                 whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
@@ -555,7 +555,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
     render() {
         TraceMobx();
         return <div className="pdfViewer-content">
-            <div className={`pdfViewerDash${this.annotationsActive() ? "-interactive" : ""}`} ref={this._mainCont}
+            <div className={`pdfViewerDash${this.isContentActive() ? "-interactive" : ""}`} ref={this._mainCont}
                 onScroll={this.onScroll} onWheel={this.onZoomWheel} onPointerDown={this.onPointerDown} onClick={this.onClick}
                 style={{
                     overflowX: this._zoomed !== 1 ? "scroll" : undefined,
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 67e9dfb27..a1fc77a92 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -78,7 +78,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
     // embedWidth = () => this.props.PanelWidth();
     // embedHeight = () => Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - this.collapsedHeight);
     embedWidth = (): number => this.props.PanelWidth() - 35;
-    styleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps | FieldViewProps>, property: string): any => {
+    styleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps>, property: string): any => {
         if (property === StyleProp.Opacity) return 1;
         return this.props.styleProvider?.(doc, props, property);
     }
@@ -98,6 +98,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                     rootSelected={returnTrue}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
+                    isContentActive={this.props.isContentActive}
                     addDocTab={returnFalse}
                     pinToPres={returnFalse}
                     PanelWidth={this.embedWidth}
-- 
cgit v1.2.3-70-g09d2


From 6c689a999e22fc414386e39007ca0929057ff1d8 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 30 Mar 2021 09:37:56 -0400
Subject: fixed a bunch of compile errors.  activated Clear button for recently
 closed tree views.

---
 src/client/documents/Documents.ts                  |  1 +
 src/client/util/CurrentUserUtils.ts                |  2 +-
 src/client/views/GestureOverlay.tsx                |  2 ++
 src/client/views/LightboxView.tsx                  |  4 ++-
 src/client/views/OverlayView.tsx                   |  2 ++
 src/client/views/Palette.tsx                       |  2 ++
 src/client/views/PropertiesView.tsx                |  2 ++
 .../views/collections/CollectionLinearView.tsx     |  4 ++-
 .../views/collections/CollectionSchemaView.tsx     |  2 ++
 .../views/collections/CollectionTreeView.tsx       | 29 ++++++++--------------
 src/client/views/collections/SchemaTable.tsx       | 14 ++++++-----
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  1 -
 src/client/views/nodes/LinkDocPreview.tsx          |  2 ++
 .../views/nodes/formattedText/DashDocView.tsx      |  4 ++-
 src/mobile/AudioUpload.tsx                         |  2 ++
 src/mobile/MobileInterface.tsx                     |  2 ++
 16 files changed, 46 insertions(+), 29 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 81fb204de..88d5cd61f 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -246,6 +246,7 @@ export class DocumentOptions {
     treeViewHideTitle?: boolean; // whether to hide the top document title of a tree view
     treeViewHideHeader?: boolean; // whether to hide the header for a document in a tree view
     treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items.
+    treeViewShowClearButton?: boolean; // whether a clear button should be displayed 
     treeViewOpen?: boolean; // whether this document is expanded in a tree view
     treeViewExpandedView?: string; // which field/thing is displayed when this item is opened in tree view
     treeViewChecked?: ScriptField; // script to call when a tree view checkbox is checked
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 0fb32970a..51bdd715b 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -792,7 +792,7 @@ export class CurrentUserUtils {
         // setup Recently Closed library item
         if (doc.myRecentlyClosedDocs === undefined) {
             doc.myRecentlyClosedDocs = new PrefetchProxy(Docs.Create.TreeDocument([], {
-                title: "Recently Closed",
+                title: "Recently Closed", treeViewShowClearButton: true,
                 treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias",
                 treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, ignoreClick: true,
                 _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 49484d171..491bf18b2 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -870,6 +870,8 @@ export class GestureOverlay extends Touchable {
                 ScreenToLocalTransform={this.screenToLocalTransform}
                 PanelWidth={this.return300}
                 PanelHeight={this.return300}
+                isDocumentActive={returnFalse}
+                isContentActive={returnFalse}
                 renderDepth={0}
                 styleProvider={returnEmptyString}
                 layerProvider={undefined}
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index 8e38d4744..e33b3b35e 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -5,7 +5,7 @@ import "normalize.css";
 import * as React from 'react';
 import { Doc, DocListCast, Opt } from '../../fields/Doc';
 import { Cast, NumCast, StrCast } from '../../fields/Types';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnTrue } from '../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnTrue, returnFalse } from '../../Utils';
 import { DocUtils } from '../documents/Documents';
 import { DocumentManager } from '../util/DocumentManager';
 import { LinkManager } from '../util/LinkManager';
@@ -231,6 +231,8 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                         DataDoc={undefined}
                         addDocument={undefined}
                         fitContentsToDoc={this.fitToBox}
+                        isDocumentActive={returnFalse}
+                        isContentActive={returnTrue}
                         addDocTab={this.addDocTab}
                         pinToPres={TabDocView.PinDoc}
                         rootSelected={returnTrue}
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index e154621d8..af04b967a 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -190,6 +190,8 @@ export class OverlayView extends React.Component {
                     PanelHeight={returnOne}
                     ScreenToLocalTransform={Transform.Identity}
                     renderDepth={1}
+                    isDocumentActive={returnTrue}
+                    isContentActive={returnFalse}
                     whenChildContentsActiveChanged={emptyFunction}
                     focus={DocUtils.DefaultFocus}
                     styleProvider={DefaultStyleProvider}
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 2699fabe5..86ab881bb 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -49,6 +49,8 @@ export default class Palette extends React.Component<PaletteProps> {
                             PanelWidth={() => window.screen.width}
                             PanelHeight={() => window.screen.height}
                             renderDepth={0}
+                            isDocumentActive={returnTrue}
+                            isContentActive={returnFalse}
                             focus={emptyFunction}
                             docViewPath={returnEmptyDoclist}
                             styleProvider={returnEmptyString}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 835e3d9e3..d79ae6426 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -274,6 +274,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     docViewPath={returnEmptyDoclist}
                     freezeDimensions={true}
                     dontCenter={"y"}
+                    isDocumentActive={returnFalse}
+                    isContentActive={returnFalse}
                     NativeWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : undefined}
                     NativeHeight={layoutDoc.type === DocumentType.RTF ? this.rtfHeight : undefined}
                     PanelWidth={panelWidth}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 5c12bd126..07cab829d 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -7,7 +7,7 @@ import { documentSchema } from '../../../fields/documentSchemas';
 import { Id } from '../../../fields/FieldSymbols';
 import { makeInterface } from '../../../fields/Schema';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
-import { emptyFunction, returnTrue, Utils, emptyPath, returnEmptyDoclist } from '../../../Utils';
+import { emptyFunction, returnTrue, Utils, emptyPath, returnEmptyDoclist, returnFalse } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { Transform } from '../../util/Transform';
 import { DocumentLinksButton } from '../nodes/DocumentLinksButton';
@@ -140,6 +140,8 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                             <DocumentView
                                 Document={pair.layout}
                                 DataDoc={pair.data}
+                                isContentActive={returnFalse}
+                                isDocumentActive={returnTrue}
                                 addDocument={this.props.addDocument}
                                 moveDocument={this.props.moveDocument}
                                 addDocTab={this.props.addDocTab}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index d49403d8e..b33c437a9 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -410,6 +410,8 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
                     rootSelected={this.rootSelected}
                     PanelWidth={this.previewWidth}
                     PanelHeight={this.previewHeight}
+                    isContentActive={returnTrue}
+                    isDocumentActive={returnFalse}
                     ScreenToLocalTransform={this.getPreviewTransform}
                     docFilters={this.docFilters}
                     docRangeFilters={this.docRangeFilters}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index d80534ef9..7177edfc4 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -84,19 +84,15 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
         return false;
     });
     @action
-    addDoc = (doc: Doc | Doc[], relativeTo: Opt<Doc>, before?: boolean): boolean => {
+    addDoc = (docs: Doc | Doc[], relativeTo: Opt<Doc>, before?: boolean): boolean => {
         const doAddDoc = (doc: Doc | Doc[]) =>
-            (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) =>
-                flg && Doc.AddDocToList(this.doc[DataSym], this.props.fieldKey, doc, relativeTo, before, false, false, false), true);
-        if (this.doc.resolvedDataDoc instanceof Promise) {
-            this.doc.resolvedDataDoc.then((resolved: any) => doAddDoc(doc));
-        } else if (relativeTo === undefined) {
-            this.props.addDocument?.(doc);
-        } else {
-            doAddDoc(doc);
-            (doc instanceof Doc ? [doc] : doc).forEach(d => d.context = this.props.Document);
-        }
-        return true;
+            (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => {
+                const res = flg && Doc.AddDocToList(this.doc[DataSym], this.props.fieldKey, doc, relativeTo, before);
+                res && (doc.context = this.props.Document);
+                return res;
+            }, true);
+        if (this.doc.resolvedDataDoc instanceof Promise) return false;
+        return relativeTo === undefined ? this.props.addDocument?.(docs) || false : doAddDoc(docs);
     }
     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
@@ -116,7 +112,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
     onTreeDrop = (e: React.DragEvent) => this.onExternalDrop(e, {});
 
     @computed get renderClearButton() {
-        return !this.doc.allowClear ? (null) : <div key="toolbar">
+        return !this.doc.treeViewShowClearButton ? (null) : <div key="toolbar">
             <button className="toolbar-button round-button" title="Empty" onClick={undoBatch(action(() => Doc.GetProto(this.doc)[this.props.fieldKey] = undefined))}>
                 <FontAwesomeIcon icon={"trash"} size="sm" />
             </button>
@@ -193,17 +189,14 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
         </div>;
     }
     @computed get treeViewtruncateTitleWidth() { return NumCast(this.doc.treeViewTruncateTitleWidth, this.panelWidth()); }
-    truncateTitleWidth = () => this.treeViewtruncateTitleWidth;
+    @computed get treeChildren() { return this.props.childDocuments || this.childDocs; }
     @computed get outlineMode() { return this.doc.treeViewType === "outline"; }
     @computed get fileSysMode() { return this.doc.treeViewType === "fileSystem"; }
+    truncateTitleWidth = () => this.treeViewtruncateTitleWidth;
     onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick);
     whenChildContentsActiveChanged = (isActive: boolean) => { this.props.whenChildContentsActiveChanged(this._isChildActive = isActive); };
     active = (outsideReaction: boolean | undefined) => this.props.isContentActive(outsideReaction) || this._isChildActive;
     panelWidth = () => this.props.PanelWidth() - 20; // bcz: 20 is the 10 + 10 for the left and right padding.
-    @computed get treeChildren() {
-        TraceMobx();
-        return this.props.childDocuments || this.childDocs;
-    }
     @computed get treeViewElements() {
         TraceMobx();
         const dropAction = StrCast(this.doc.childDropAction) as dropActionType;
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index c91942c05..0c69ee030 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -15,7 +15,7 @@ import { ComputedField } from "../../../fields/ScriptField";
 import { Cast, FieldValue, NumCast, StrCast } from "../../../fields/Types";
 import { ImageField } from "../../../fields/URLField";
 import { GetEffectiveAcl } from "../../../fields/util";
-import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse } from "../../../Utils";
+import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from "../../../Utils";
 import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { CompileScript, Transformer, ts } from "../../util/Scripting";
@@ -559,15 +559,15 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
             onPointerDown={this.props.onPointerDown} onClick={this.props.onClick} onWheel={e => this.props.active(true) && e.stopPropagation()}
             onDrop={e => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} >
             {this.reactTable}
-            {this.props.Document._chromeHidden ? undefined : <div className="collectionSchemaView-addRow" onClick={() => this.createRow()}>+ new</div>}
+            {this.props.Document._chromeHidden ? undefined : <div className="collectionSchemaView-addRow" onClick={this.createRow}>+ new</div>}
             {!this._showDoc ? (null) :
-                <div className="collectionSchemaView-documentPreview"
+                <div className="collectionSchemaView-documentPreview" ref="overlay"
                     style={{
                         position: "absolute", width: 150, height: 150,
                         background: "dimGray", display: "block", top: 0, left: 0,
                         transform: `translate(${this._showDocPos[0]}px, ${this._showDocPos[1] - 180}px)`
-                    }}
-                    ref="overlay"><DocumentView
+                    }} >
+                    <DocumentView
                         Document={this._showDoc}
                         DataDoc={this._showDataDoc}
                         styleProvider={DefaultStyleProvider}
@@ -576,7 +576,9 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                         freezeDimensions={true}
                         focus={DocUtils.DefaultFocus}
                         renderDepth={this.props.renderDepth}
-                        rootSelected={() => false}
+                        rootSelected={returnFalse}
+                        isContentActive={returnTrue}
+                        isDocumentActive={returnFalse}
                         PanelWidth={() => 150}
                         PanelHeight={() => 150}
                         ScreenToLocalTransform={this.getPreviewTransform}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 950fc4a25..512ec81f8 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -36,7 +36,6 @@ import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveIn
 import { LightboxView } from "../../LightboxView";
 import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
 import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment, ViewSpecPrefix } from "../../nodes/DocumentView";
-import { FieldViewProps } from "../../nodes/FieldView";
 import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
 import { pageSchema } from "../../nodes/ImageBox";
 import { PresBox } from "../../nodes/PresBox";
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index d1cf25e50..45e3c8382 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -164,6 +164,8 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                             layerProvider={this.props.docProps?.layerProvider}
                             docViewPath={returnEmptyDoclist}
                             ScreenToLocalTransform={Transform.Identity}
+                            isDocumentActive={returnFalse}
+                            isContentActive={returnFalse}
                             addDocument={returnFalse}
                             removeDocument={returnFalse}
                             addDocTab={returnFalse}
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index b143cb91e..8915d7c47 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -2,7 +2,7 @@ import { IReactionDisposer, reaction, observable, action } from "mobx";
 import { NodeSelection } from "prosemirror-state";
 import { Doc, HeightSym, WidthSym } from "../../../../fields/Doc";
 import { Cast, StrCast } from "../../../../fields/Types";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, Utils } from "../../../../Utils";
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, Utils, returnTransparent } from "../../../../Utils";
 import { DocServer } from "../../../DocServer";
 import { Docs, DocUtils } from "../../../documents/Documents";
 import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
@@ -166,6 +166,8 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
                     addDocument={returnFalse}
                     rootSelected={this._textBox.props.isSelected}
                     removeDocument={this.removeDoc}
+                    isDocumentActive={returnFalse}
+                    isContentActive={this._textBox.props.isContentActive}
                     layerProvider={this._textBox.props.layerProvider}
                     styleProvider={this._textBox.props.styleProvider}
                     docViewPath={this._textBox.props.docViewPath}
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index f0e581088..71ddda866 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -93,6 +93,8 @@ export class AudioUpload extends React.Component {
                         PanelWidth={() => 600}
                         PanelHeight={() => 400}
                         renderDepth={0}
+                        isDocumentActive={returnTrue}
+                        isContentActive={returnFalse}
                         focus={emptyFunction}
                         layerProvider={undefined}
                         styleProvider={() => "rgba(0,0,0,0)"}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 22b8561d8..404e828ea 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -210,6 +210,8 @@ export class MobileInterface extends React.Component {
                     PanelWidth={this.returnWidth}
                     PanelHeight={this.returnHeight}
                     renderDepth={0}
+                    isDocumentActive={returnTrue}
+                    isContentActive={returnFalse}
                     focus={DocUtils.DefaultFocus}
                     styleProvider={this.whitebackground}
                     layerProvider={undefined}
-- 
cgit v1.2.3-70-g09d2


From 8b92374feed3152cf4eaf4e82735897565d8b2dc Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 30 Mar 2021 20:55:48 -0400
Subject: some code cleanup.  Fixes for webbox and pdfbox to allow draggin out
 of annotation sidebar.

---
 src/client/util/DocumentManager.ts                 |  1 -
 src/client/views/DocumentDecorations.tsx           |  6 +--
 src/client/views/SidebarAnnos.tsx                  |  2 +-
 .../views/collections/CollectionDockingView.tsx    |  4 +-
 .../views/collections/CollectionTreeView.tsx       |  1 -
 src/client/views/collections/TreeView.tsx          | 43 +++++++++++-----------
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  6 ++-
 src/client/views/nodes/DocumentView.tsx            | 14 +++----
 src/client/views/nodes/PDFBox.tsx                  | 20 ++++++++--
 src/client/views/nodes/WebBox.tsx                  | 26 ++++++++++---
 10 files changed, 73 insertions(+), 50 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 8b37c9a6e..304215a8f 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -208,7 +208,6 @@ export class DocumentManager {
                                 // we didn't find the target, so it must have moved out of the context.  Go back to just creating it.
                                 if (closeContextIfNotFound) targetDocContextView.props.removeDocument?.(targetDocContextView.rootDoc);
                                 if (targetDoc.layout) { // there will no layout for a TEXTANCHOR type document
-                                    // Doc.SetInPlace(targetDoc, "annotationOn", undefined, false);
                                     createViewFunc(Doc.BrushDoc(targetDoc), finished); //  create a new view of the target
                                 }
                             } else {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index a492d5796..ce7ff1bbd 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -191,7 +191,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
                     X: Math.cos(angle) * (ink.X - pair.X) - Math.sin(angle) * (ink.Y - pair.Y) + pair.X,
                     Y: Math.sin(angle) * (ink.X - pair.X) + Math.cos(angle) * (ink.Y - pair.Y) + pair.Y
                 })) || [];
-                Doc.SetInPlace(pair.doc, "data", new InkField(newPoints), true);
+                Doc.GetProto(pair.doc).data = new InkField(newPoints);
 
                 pair.doc._width = ((xs) => (Math.max(...xs) - Math.min(...xs)))(newPoints.map(p => p.X) || [0]);
                 pair.doc._height = ((ys) => (Math.max(...ys) - Math.min(...ys)))(newPoints.map(p => p.Y) || [0]);
@@ -375,11 +375,11 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
         //need to change points for resize, or else rotation/control points will fail.
         this._inkDragDocs.map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] }))
             .forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => {
-                Doc.SetInPlace(doc, "data", new InkField(inkPts.map(ipt =>  // (new x — oldx) + newWidth * (oldxpoint /oldWidth)
+                Doc.GetProto(doc).data = new InkField(inkPts.map(ipt =>  // (new x — oldx) + newWidth * (oldxpoint /oldWidth)
                     ({
                         X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width,
                         Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height
-                    }))), true);
+                    })));
                 Doc.SetNativeWidth(doc, undefined);
                 Doc.SetNativeHeight(doc, undefined);
             });
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 5988653d7..b5bdf4ca8 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -46,7 +46,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
     anchorMenuClick = (anchor: Doc) => {
         const startup = StrListCast(this.props.rootDoc.docFilters).map(filter => filter.split(":")[0]).join(" ");
         const target = Docs.Create.TextDocument(startup, {
-            title: "anno",
+            title: "-note-",
             annotationOn: this.props.rootDoc, _width: 200, _height: 50, _fitWidth: true, _autoHeight: true, _fontSize: StrCast(Doc.UserDoc().fontSize),
             _fontFamily: StrCast(Doc.UserDoc().fontFamily)
         });
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 7e89cf55d..52d3e91b9 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -353,7 +353,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
         if (clone) {
             const cloned = (await Doc.MakeClone(doc));
             Array.from(cloned.map.entries()).map(entry => json = json.replace(entry[0], entry[1][Id]));
-            Doc.SetInPlace(cloned.clone, "dockingConfig", json, true);
+            Doc.GetProto(cloned.clone).dockingConfig = json;
             return cloned.clone;
         }
         const matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g);
@@ -363,7 +363,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
             const origtabdocs = DocListCast(origtab.data);
             const newtab = origtabdocs.length ? Doc.MakeCopy(origtab, true) : Doc.MakeAlias(origtab);
             const newtabdocs = origtabdocs.map(origtabdoc => Doc.MakeAlias(origtabdoc));
-            newtabdocs.length && Doc.SetInPlace(newtab, "data", new List<Doc>(newtabdocs), true);
+            newtabdocs.length && (Doc.GetProto(newtab).data = new List<Doc>(newtabdocs));
             json = json.replace(origtab[Id], newtab[Id]);
             return newtab;
         });
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index eb767e878..7243fc172 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -116,7 +116,6 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
 
     @undoBatch
     makeTextCollection = (childDocs: Doc[]) => {
-        Doc.SetInPlace(this.doc, "editTitle", undefined, false);
         this.addDoc(TreeView.makeTextBullet(), childDocs.length ? childDocs[0] : undefined, true);
     }
 
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index a06eeb738..a4f17296a 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -78,13 +78,13 @@ export class TreeView extends React.Component<TreeViewProps> {
     static _editTitleOnLoad: Opt<{ id: string, parent: TreeView | CollectionTreeView | undefined }>;
     static _openTitleScript: Opt<ScriptField | undefined>;
     static _openLevelScript: Opt<ScriptField | undefined>;
-    private _editTitleScript: (() => ScriptField) | undefined;
-    private _openScript: (() => ScriptField) | undefined;
-    private _header?: React.RefObject<HTMLDivElement> = React.createRef();
-    private _treedropDisposer?: DragManager.DragDropDisposer;
+    private _header: React.RefObject<HTMLDivElement> = React.createRef();;
     private _tref = React.createRef<HTMLDivElement>();
     private _docRef: Opt<DocumentView>;
     private _selDisposer: Opt<IReactionDisposer>;
+    private _editTitleScript: (() => ScriptField) | undefined;
+    private _openScript: (() => ScriptField) | undefined;
+    private _treedropDisposer?: DragManager.DragDropDisposer
 
     set treeViewOpen(c: boolean) {
         if (this.props.treeViewPreventOpen) this._overrideTreeViewOpen = c;
@@ -98,21 +98,21 @@ export class TreeView extends React.Component<TreeViewProps> {
     get defaultExpandedView() { return this.props.treeView.props.treeViewExpandedView || (StrCast(this.doc.treeViewDefaultExpandedView, this.props.treeView.fileSysMode ? (this.doc.isFolder ? "data" : "aliases") : Doc.UserDoc().noviceMode || this.props.treeView.outlineMode ? "layout" : "fields")); }
     get treeViewDefaultExpandedView() { return this.treeViewLockExpandedView ? this.defaultExpandedView : (this.childDocs && !this.props.treeView.fileSysMode ? this.fieldKey : this.defaultExpandedView); }
 
-    @computed get doc() { TraceMobx(); return this.props.document; }
+    @computed get doc() { return this.props.document; }
     @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && !this.doc.treeViewPreventOpen && Doc.GetT(this.doc, "treeViewOpen", "boolean", true)) || this._overrideTreeViewOpen; }
     @computed get treeViewExpandedView() { return StrCast(this.doc.treeViewExpandedView, this.treeViewDefaultExpandedView); }
     @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containerCollection.maxEmbedHeight, 200); }
     @computed get dataDoc() { return this.doc[DataSym]; }
     @computed get layoutDoc() { return Doc.Layout(this.doc); }
-    @computed get fieldKey() { TraceMobx(); const splits = StrCast(Doc.LayoutField(this.doc)).split("fieldKey={\'"); return splits.length > 1 ? splits[1].split("\'")[0] : "data"; }
-    @computed get childDocs() { TraceMobx(); return this.childDocList(this.fieldKey); }
+    @computed get fieldKey() { return Doc.LayoutFieldKey(this.doc); }
+    @computed get childDocs() { return this.childDocList(this.fieldKey); }
     @computed get childLinks() { return this.childDocList("links"); }
     @computed get childAliases() { return this.childDocList("aliases"); }
     @computed get childAnnos() { return this.childDocList(this.fieldKey + "-annotations"); }
-    @computed get selected() { return SelectionManager.Views().length && SelectionManager.Views()[0].props.Document === this.props.document; }
+    @computed get selected() { return SelectionManager.Views().lastElement()?.props.Document === this.props.document; }
 
     childDocList(field: string) {
-        const layout = Doc.LayoutField(this.doc) instanceof Doc ? Doc.LayoutField(this.doc) as Doc : undefined;
+        const layout = Cast(Doc.LayoutField(this.doc), Doc, null);
         return (this.props.dataDoc ? DocListCastOrNull(this.props.dataDoc[field]) : undefined) || // if there's a data doc for an expanded template, use it's data field
             (layout ? DocListCastOrNull(layout[field]) : undefined) || // else if there's a layout doc, display it's fields
             DocListCastOrNull(this.doc[field]); // otherwise use the document's data field
@@ -177,7 +177,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     onPointerEnter = (e: React.PointerEvent): void => {
         this.props.isContentActive(true) && Doc.BrushDoc(this.dataDoc);
         if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
-            this._header!.current!.className = "treeView-header";
+            this._header.current!.className = "treeView-header";
             document.removeEventListener("pointermove", this.onDragMove, true);
             document.removeEventListener("pointerup", this.onDragUp, true);
             document.addEventListener("pointermove", this.onDragMove, true);
@@ -186,8 +186,8 @@ export class TreeView extends React.Component<TreeViewProps> {
     }
     onPointerLeave = (e: React.PointerEvent): void => {
         Doc.UnBrushDoc(this.dataDoc);
-        if (this._header?.current?.className !== "treeView-header-editing") {
-            this._header!.current!.className = "treeView-header";
+        if (this._header.current?.className !== "treeView-header-editing") {
+            this._header.current!.className = "treeView-header";
         }
         document.removeEventListener("pointerup", this.onDragUp, true);
         document.removeEventListener("pointermove", this.onDragMove, true);
@@ -195,13 +195,13 @@ export class TreeView extends React.Component<TreeViewProps> {
     onDragMove = (e: PointerEvent): void => {
         Doc.UnBrushDoc(this.dataDoc);
         const pt = [e.clientX, e.clientY];
-        const rect = this._header!.current!.getBoundingClientRect();
+        const rect = this._header.current!.getBoundingClientRect();
         const before = pt[1] < rect.top + rect.height / 2;
         const inside = pt[0] > Math.min(rect.left + 75, rect.left + rect.width * .75) || (!before && this.treeViewOpen && this.childDocList.length);
-        this._header!.current!.className = "treeView-header";
-        if (inside) this._header!.current!.className += " treeView-header-inside";
-        else if (before) this._header!.current!.className += " treeView-header-above";
-        else if (!before) this._header!.current!.className += " treeView-header-below";
+        this._header.current!.className = "treeView-header";
+        if (inside) this._header.current!.className += " treeView-header-inside";
+        else if (before) this._header.current!.className += " treeView-header-above";
+        else if (!before) this._header.current!.className += " treeView-header-below";
         e.stopPropagation();
     }
 
@@ -238,7 +238,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     @undoBatch
     treeDrop = (e: Event, de: DragManager.DropEvent) => {
         const pt = [de.x, de.y];
-        const rect = this._header!.current!.getBoundingClientRect();
+        const rect = this._header.current!.getBoundingClientRect();
         const before = pt[1] < rect.top + rect.height / 2;
         const inside = this.props.treeView.fileSysMode && !this.doc.isFolder ? false : pt[0] > Math.min(rect.left + 75, rect.left + rect.width * .75) || (!before && this.treeViewOpen && this.childDocList.length);
         if (de.complete.linkDragData) {
@@ -365,7 +365,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         TraceMobx();
         const expandKey = this.treeViewExpandedView;
         if (["links", "annotations", "aliases", this.fieldKey].includes(expandKey)) {
-            const key = expandKey === "annotations" ? this.fieldKey + "-annotations" : expandKey;
+            const key = (expandKey === "annotations" ? `${this.fieldKey}-` : "") + expandKey;
             const remDoc = (doc: Doc | Doc[]) => this.remove(doc, key);
             const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => {
                 // if there's a sort ordering specified that can be modified on drop (eg, zorder can be modified, alphabetical can't),
@@ -373,10 +373,9 @@ export class TreeView extends React.Component<TreeViewProps> {
                 const ordering = StrCast(this.doc.treeViewSortCriterion);
                 if (ordering === "Z") {
                     const docs = TreeView.sortDocs(this.childDocs || ([] as Doc[]), ordering);
-                    doc.zIndex = addBefore ? (before ? NumCast(addBefore.zIndex) - 0.5 : NumCast(addBefore.zIndex) + 0.5) : 1000;
+                    doc.zIndex = addBefore ? NumCast(addBefore.zIndex) + (before ? -0.5 : 0.5) : 1000;
                     docs.push(doc);
-                    docs.sort((a, b) => NumCast(a.zIndex) > NumCast(b.zIndex) ? 1 : -1);
-                    docs.forEach((d, i) => d.zIndex = i);
+                    docs.sort((a, b) => NumCast(a.zIndex) > NumCast(b.zIndex) ? 1 : -1).forEach((d, i) => d.zIndex = i);
                 }
                 const added = Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
                 added && (doc.context = this.doc.context);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 512ec81f8..0f8a438cd 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -622,8 +622,10 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
 
     onClick = (e: React.MouseEvent) => {
         if ((Math.abs(e.pageX - this._downX) < 3 && Math.abs(e.pageY - this._downY) < 3)) {
-            if (e.shiftKey && Date.now() - this._lastTap < 300) { // reset zoom of freeform view to 1-to-1 on a shift + double click 
-                this.zoomSmoothlyAboutPt(this.getTransform().transformPoint(e.clientX, e.clientY), 1);
+            if (e.shiftKey) {
+                if (Date.now() - this._lastTap < 300) { // reset zoom of freeform view to 1-to-1 on a shift + double click 
+                    this.zoomSmoothlyAboutPt(this.getTransform().transformPoint(e.clientX, e.clientY), 1);
+                }
                 e.stopPropagation();
                 e.preventDefault();
             }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index d3a6ab9ac..442b36bfe 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -457,21 +457,17 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     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
-                const shiftKey = e.shiftKey;
-                const clientX = e.clientX;
-                const clientY = e.clientY;
                 const func = () => this.onClickHandler.script.run({
                     this: this.layoutDoc,
                     self: this.rootDoc,
                     scriptContext: this.props.scriptContext,
                     thisContainer: this.props.ContainingCollectionDoc,
                     documentView: this.props.DocumentView(),
-                    clientX: clientX,
-                    clientY: clientY,
-                    shiftKey
-                }, console.log);
-                const clickFunc = () => this.props.Document.dontUndo ? func() :
-                    UndoManager.RunInBatch(() => func().result?.select === true ? this.props.select(false) : "", "on click");
+                    clientX: e.clientX,
+                    clientY: e.clientY,
+                    shiftKey: e.shiftKey
+                }, console.log).result?.select === true ? this.props.select(false) : "";
+                const clickFunc = () => this.props.Document.dontUndo ? func() : UndoManager.RunInBatch(func, "on click");
                 if (this.onDoubleClickHandler) {
                     this._timeout = setTimeout(() => { this._timeout = undefined; clickFunc(); }, 350);
                 } else clickFunc();
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 03999e5fb..d55156057 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -9,7 +9,7 @@ import { makeInterface } from "../../../fields/Schema";
 import { Cast, NumCast, StrCast } from '../../../fields/Types';
 import { PdfField } from "../../../fields/URLField";
 import { TraceMobx } from '../../../fields/util';
-import { Utils } from '../../../Utils';
+import { Utils, setupMoveUpEvents, emptyFunction } from '../../../Utils';
 import { Docs } from '../../documents/Documents';
 import { KeyCodes } from '../../util/KeyCodes';
 import { undoBatch } from '../../util/UndoManager';
@@ -150,6 +150,20 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         if (!this.layoutDoc._showSidebar) this.toggleSidebar();
         return this.addDocument(doc, sidebarKey);
     }
+    sidebarBtnDown = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, (e, down, delta) => {
+            const localDelta = this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).transformDirection(delta[0], delta[1]);
+            const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]);
+            const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth);
+            const ratio = (curNativeWidth + localDelta[0] / (this.props.scaling?.() || 1)) / nativeWidth;
+            if (ratio >= 1) {
+                this.layoutDoc.nativeWidth = nativeWidth * ratio;
+                this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0];
+                this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth;
+            }
+            return false;
+        }, emptyFunction, this.toggleSidebar);
+    }
     toggleSidebar = action(() => {
         const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]);
         const ratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? 250 : 0) + nativeWidth) / nativeWidth;
@@ -203,8 +217,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     {this._pageControls ? pageBtns : (null)}
                 </div>
                 <button className="pdfBox-sidebarBtn" title="Toggle Sidebar"
-                    style={{ right: this.sidebarWidth() + 7, display: !this.isContentActive() ? "none" : undefined }}
-                    onPointerDown={e => e.stopPropagation()} onClick={e => this.toggleSidebar()} >
+                    style={{ display: !this.isContentActive() ? "none" : undefined }}
+                    onPointerDown={this.sidebarBtnDown} >
                     <FontAwesomeIcon icon={"chevron-left"} size="sm" />
                 </button>
             </div>;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index c961ad991..ab178c60b 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -12,7 +12,7 @@ import { makeInterface, listSpec } from "../../../fields/Schema";
 import { Cast, NumCast, StrCast } from "../../../fields/Types";
 import { WebField } from "../../../fields/URLField";
 import { TraceMobx } from "../../../fields/util";
-import { emptyFunction, getWordAtPoint, OmitKeys, returnOne, smoothScroll, Utils } from "../../../Utils";
+import { emptyFunction, getWordAtPoint, OmitKeys, returnOne, smoothScroll, Utils, setupMoveUpEvents } from "../../../Utils";
 import { Docs } from "../../documents/Documents";
 import { DocumentType } from '../../documents/DocumentTypes';
 import { CurrentUserUtils } from "../../util/CurrentUserUtils";
@@ -429,6 +429,20 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         if (!this.layoutDoc._showSidebar) this.toggleSidebar();
         return this.addDocument(doc, sidebarKey);
     }
+    sidebarBtnDown = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, (e, down, delta) => {
+            const localDelta = this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).transformDirection(delta[0], delta[1]);
+            const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]);
+            const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth);
+            const ratio = (curNativeWidth + localDelta[0] / (this.props.scaling?.() || 1)) / nativeWidth;
+            if (ratio >= 1) {
+                this.layoutDoc.nativeWidth = nativeWidth * ratio;
+                this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0];
+                this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth;
+            }
+            return false;
+        }, emptyFunction, this.toggleSidebar);
+    }
     toggleSidebar = action(() => {
         const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]);
         const ratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? 250 : 0) + nativeWidth) / nativeWidth;
@@ -523,11 +537,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                             annotationLayer={this._annotationLayer.current}
                             mainCont={this._mainCont.current} />}
                 </div >
-                <button className="webBox-overlayButton-sidebar" key="sidebar" title="Toggle Sidebar"
-                    style={{ right: this.sidebarWidth() + 7, display: !this.isContentActive() ? "none" : undefined }}
-                    onPointerDown={e => e.stopPropagation()} onClick={e => this.toggleSidebar()} >
-                    <FontAwesomeIcon style={{ color: "white" }} icon={"chevron-left"} size="sm" />
-                </button>
                 <SidebarAnnos ref={this._sidebarRef}
                     {...this.props}
                     fieldKey={this.annotationKey}
@@ -539,6 +548,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     removeDocument={this.removeDocument}
                     isContentActive={this.isContentActive}
                 />
+                <button className="webBox-overlayButton-sidebar" key="sidebar" title="Toggle Sidebar"
+                    style={{ display: !this.isContentActive() ? "none" : undefined }}
+                    onPointerDown={this.sidebarBtnDown} >
+                    <FontAwesomeIcon style={{ color: "white" }} icon={"chevron-left"} size="sm" />
+                </button>
             </div>);
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From c6765df5396540cd446ff63c6e8fe90f367a92df Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 2 Apr 2021 20:46:11 -0400
Subject: from last

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

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

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 0f8a438cd..c623ce653 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1446,7 +1446,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             getTransform={this.getTransform}
             isAnnotationOverlay={this.isAnnotationOverlay}>
             <div ref={this._marqueeRef}>
-                {this.layoutDoc["_backgroundGrid-show"] && (!SnappingManager.GetIsDragging() || !Doc.UserDoc().showSnapLines) ? this.backgroundGrid : (null)}
+                {this.layoutDoc["_backgroundGrid-show"] ? this.backgroundGrid : (null)}
                 <CollectionFreeFormViewPannableContents
                     isAnnotationOverlay={this.isAnnotationOverlay}
                     transform={this.contentTransform}
-- 
cgit v1.2.3-70-g09d2

