From 0546ecf205b7d2b76f341a7157beebf95fb888a8 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 1 Aug 2021 22:43:46 -0400
Subject: made url server references relative.

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

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

diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index a5d27f038..0d9b64d24 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -303,7 +303,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                     } else {
                         const path = window.location.origin + "/doc/";
                         if (text.startsWith(path)) {
-                            const docid = text.replace(Utils.prepend("/doc/"), "").split("?")[0];
+                            const docid = text.replace(Doc.globalServerPath(), "").split("?")[0];
                             DocServer.GetRefField(docid).then(f => {
                                 if (f instanceof Doc) {
                                     if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView
-- 
cgit v1.2.3-70-g09d2


From 0e8aef275346b4ba3bc1bb91fda17a335c307bf1 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 3 Aug 2021 13:09:48 -0400
Subject: fixed using viewSpecs when following links to set filters/viewType
 properly.

---
 src/client/util/DocumentManager.ts                      |  2 +-
 src/client/views/collections/CollectionSubView.tsx      |  6 +++---
 .../collectionFreeForm/CollectionFreeFormView.tsx       | 17 ++++++++++++-----
 src/client/views/nodes/DocumentView.tsx                 | 14 ++++++++------
 4 files changed, 24 insertions(+), 15 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 5b092258a..9c6100249 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -163,7 +163,7 @@ export class DocumentManager {
         const targetDocContext = contextDoc || annotatedDoc;
         const targetDocContextView = targetDocContext && getFirstDocView(targetDocContext);
         const focusView = !docView && targetDoc.type === DocumentType.MARKER && annoContainerView ? annoContainerView : docView;
-        if (!docView && annoContainerView && !focusView) {
+        if (!docView && annoContainerView) {
             annoContainerView.focus(targetDoc);  // this allows something like a PDF view to remove its doc filters to expose the target so that it can be found in the retry code below
         }
         if (focusView) {
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 0d9b64d24..3b143aeef 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -82,13 +82,13 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
             return Cast(this.dataField, listSpec(Doc));
         }
         docFilters = () => {
-            return [...this.props.docFilters(), ...Cast(this.props.Document._docFilters, listSpec("string"), [])];
+            return (this.props.docFilters?.() ?? Cast(this.props.Document._docFilters, listSpec("string"), []));
         }
         docRangeFilters = () => {
-            return [...this.props.docRangeFilters(), ...Cast(this.props.Document._docRangeFilters, listSpec("string"), [])];
+            return (this.props.docRangeFilters?.() ?? Cast(this.props.Document._docRangeFilters, listSpec("string"), []));
         }
         searchFilterDocs = () => {
-            return [...this.props.searchFilterDocs(), ...DocListCast(this.props.Document._searchFilterDocs)];
+            return this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs);
         }
         @computed.struct get childDocs() {
             TraceMobx();
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 143d8e070..ecc93285e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -159,8 +159,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         this.layoutDoc._viewScale = vals.scale;
     }
     freeformData = (force?: boolean) => this.fitToContent || force ? this.fitToContentVals : undefined;
-    freeformDocFilters = () => this._focusFilters || this.docFilters();
-    freeformRangeDocFilters = () => this._focusRangeFilters || this.docRangeFilters();
+    freeformDocFilters = () => this._focusFilters;
+    freeformRangeDocFilters = () => this._focusRangeFilters;
     reverseNativeScaling = () => this.fitToContent ? true : false;
     panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document._panX);
     panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document._panY);
@@ -1197,14 +1197,21 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         if (preview) {
             this._focusFilters = StrListCast(Doc.GetProto(anchor).docFilters);
             this._focusRangeFilters = StrListCast(Doc.GetProto(anchor).docRangeFilters);
-        } else if (anchor.pivotField !== undefined) {
-            this.layoutDoc._docFilters = new List<string>(StrListCast(anchor.docFilters));
-            this.layoutDoc._docRangeFilters = new List<string>(StrListCast(anchor.docRangeFilters));
+        } else {
+            if (anchor.docFilters) {
+                this.layoutDoc._docFilters = new List<string>(StrListCast(anchor.docFilters));
+            }
+            if (anchor.docRangeFilters) {
+                this.layoutDoc._docRangeFilters = new List<string>(StrListCast(anchor.docRangeFilters));
+            }
         }
         return 0;
     }
 
     getAnchor = () => {
+        if (this.props.Document.annotationOn) {
+            return this.rootDoc;
+        }
         const anchor = Docs.Create.TextanchorDocument({ title: StrCast(this.layoutDoc._viewType), annotationOn: this.rootDoc });
         const proto = Doc.GetProto(anchor);
         proto[ViewSpecPrefix + "_viewType"] = this.layoutDoc._viewType;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f716eb7b1..c218b805e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -64,7 +64,7 @@ export enum ViewAdjustment {
     doNothing = 0
 }
 
-export const ViewSpecPrefix = "_VIEW";  // field prefix for anchor fields that are immediately copied over to the target document when link is followed.  Other anchor properties will be copied over in the specific setViewSpec() method on their view (which allows for seting preview values instead of writing to the document)
+export const ViewSpecPrefix = "viewSpec";  // field prefix for anchor fields that are immediately copied over to the target document when link is followed.  Other anchor properties will be copied over in the specific setViewSpec() method on their view (which allows for seting preview values instead of writing to the document)
 
 export interface DocFocusOptions {
     originalTarget?: Doc; // set in JumpToDocument, used by TabDocView to determine whether to fit contents to tab
@@ -105,9 +105,9 @@ export interface DocumentViewSharedProps {
     styleProvider: Opt<StyleProviderFunc>;
     focus: DocFocusFunc;
     fitWidth?: () => boolean;
-    docFilters: () => string[];
-    docRangeFilters: () => string[];
-    searchFilterDocs: () => Doc[];
+    docFilters?: () => Opt<string[]>;
+    docRangeFilters?: () => Opt<string[]>;
+    searchFilterDocs?: () => Opt<Doc[]>;
     whenChildContentsActiveChanged: (isActive: boolean) => void;
     rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected
     addDocTab: (doc: Doc, where: string) => boolean;
@@ -421,7 +421,9 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     focus = (anchor: Doc, options?: DocFocusOptions) => {
         LightboxView.SetCookie(StrCast(anchor["cookies-set"]));
         // copying over _VIEW fields immediately allows the view type to switch to create the right _componentView
-        Array.from(Object.keys(Doc.GetProto(anchor))).filter(key => key.startsWith(ViewSpecPrefix)).forEach(spec => this.layoutDoc[spec.replace(ViewSpecPrefix, "")] = ((field) => field instanceof ObjectField ? ObjectField.MakeCopy(field) : field)(anchor[spec]));
+        Array.from(Object.keys(Doc.GetProto(anchor))).filter(key => key.startsWith(ViewSpecPrefix)).forEach(spec => {
+            this.layoutDoc[spec.replace(ViewSpecPrefix, "")] = ((field) => field instanceof ObjectField ? ObjectField.MakeCopy(field) : field)(anchor[spec]);
+        });
         // after  a timeout, the right _componentView should have been created, so call it to update its view spec values
         setTimeout(() => this._componentView?.setViewSpec?.(anchor, LinkDocPreview.LinkInfo ? true : false));
         const focusSpeed = this._componentView?.scrollFocus?.(anchor, !LinkDocPreview.LinkInfo); // bcz: smooth parameter should really be passed into focus() instead of inferred here      
@@ -837,7 +839,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         if (this.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return null;
         if (this.layoutDoc.presBox || this.rootDoc.type === DocumentType.LINK || this.props.dontRegisterView) return (null);
         // need to use allLinks for RTF since embedded linked text anchors are not rendered with DocumentViews.  All other documents render their anchors with nested DocumentViews so we just need to render the directLinks here
-        const filtered = DocUtils.FilterDocs(this.rootDoc.type === DocumentType.RTF ? this.allLinks : this.directLinks, this.props.docFilters(), []).filter(d => !d.hidden);
+        const filtered = DocUtils.FilterDocs(this.rootDoc.type === DocumentType.RTF ? this.allLinks : this.directLinks, this.props.docFilters?.() ?? [], []).filter(d => !d.hidden);
         return filtered.map((link, i) =>
             <div className="documentView-anchorCont" key={i + 1}>
                 <DocumentView {...this.props}
-- 
cgit v1.2.3-70-g09d2


From 70f98c6d4d3e457a05e7c84260bf33580ee0166a Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 4 Aug 2021 10:34:25 -0400
Subject: restructured filters again so that filter icons show whether a
 document has a filter or inherits one.  following a link with a view spec
 overrides only locally set filters (not inherited ones).

---
 src/client/views/.DS_Store                         | Bin 10244 -> 10244 bytes
 .../views/collections/CollectionSchemaView.tsx     |   4 +--
 .../views/collections/CollectionStackingView.tsx   |   4 +--
 src/client/views/collections/CollectionSubView.tsx |  29 ++++++++++++---------
 .../views/collections/CollectionTimeView.tsx       |  12 +++------
 src/client/views/collections/CollectionView.tsx    |  14 +++++++---
 src/client/views/collections/TabDocView.tsx        |   9 ++++---
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   8 ++----
 .../CollectionMulticolumnView.tsx                  |   4 +--
 .../CollectionMultirowView.tsx                     |   4 +--
 .../collectionSchema/CollectionSchemaView.tsx      |   4 +--
 src/client/views/nodes/DocumentView.tsx            |   6 ++---
 12 files changed, 50 insertions(+), 48 deletions(-)

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

diff --git a/src/client/views/.DS_Store b/src/client/views/.DS_Store
index 33e624ef4..e4ac87aad 100644
Binary files a/src/client/views/.DS_Store and b/src/client/views/.DS_Store differ
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index e1e04915a..380f82813 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -413,8 +413,8 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
                     isContentActive={returnTrue}
                     isDocumentActive={returnFalse}
                     ScreenToLocalTransform={this.getPreviewTransform}
-                    docFilters={this.docFilters}
-                    docRangeFilters={this.docRangeFilters}
+                    docFilters={this.childDocFilters}
+                    docRangeFilters={this.childDocRangeFilters}
                     searchFilterDocs={this.searchFilterDocs}
                     styleProvider={DefaultStyleProvider}
                     layerProvider={undefined}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 7aa8dfd56..b9bc83d49 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -239,10 +239,10 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
             onDoubleClick={this.onChildDoubleClickHandler}
             ScreenToLocalTransform={stackedDocTransform}
             focus={this.focusDocument}
-            docFilters={this.docFilters}
+            docFilters={this.childDocFilters}
             hideDecorationTitle={this.props.childHideDecorationTitle?.()}
             hideTitle={this.props.childHideTitle?.()}
-            docRangeFilters={this.docRangeFilters}
+            docRangeFilters={this.childDocRangeFilters}
             searchFilterDocs={this.searchFilterDocs}
             ContainingCollectionDoc={this.props.CollectionView?.props.Document}
             ContainingCollectionView={this.props.CollectionView}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 3b143aeef..e5f266acf 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -8,7 +8,7 @@ import { ScriptField } from "../../../fields/ScriptField";
 import { WebField } from "../../../fields/URLField";
 import { Cast, ScriptCast, NumCast, StrCast } from "../../../fields/Types";
 import { GestureUtils } from "../../../pen-gestures/GestureUtils";
-import { Utils, returnFalse } from "../../../Utils";
+import { Utils, returnFalse, returnEmptyFilter } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 import { Networking } from "../../Network";
 import { ImageUtils } from "../../util/Import & Export/ImageUtils";
@@ -22,6 +22,7 @@ import ReactLoading from 'react-loading';
 
 export interface SubCollectionViewProps extends CollectionViewProps {
     CollectionView: Opt<CollectionView>;
+    SetSubView: (subView: any) => void;
 }
 
 export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: X) {
@@ -30,6 +31,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
         private gestureDisposer?: GestureUtils.GestureEventDisposer;
         protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
         protected _mainCont?: HTMLDivElement;
+        @observable _focusFilters: Opt<string[]>; // docFilters that are overridden when previewing a link to an anchor which has docFilters set on it
+        @observable _focusRangeFilters: Opt<string[]>; // docRangeFilters that are overridden when previewing a link to an anchor which has docRangeFilters set on it
         protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view
             this.dropDisposer?.();
             this.gestureDisposer?.();
@@ -45,6 +48,10 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
             this.createDashEventsTarget(ele);
         }
 
+        componentDidMount() {
+            this.props.SetSubView(this);
+        }
+
         componentWillUnmount() {
             this.gestureDisposer?.();
             this._multiTouchDisposer?.();
@@ -81,15 +88,13 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
         get childDocList() {
             return Cast(this.dataField, listSpec(Doc));
         }
-        docFilters = () => {
-            return (this.props.docFilters?.() ?? Cast(this.props.Document._docFilters, listSpec("string"), []));
-        }
-        docRangeFilters = () => {
-            return (this.props.docRangeFilters?.() ?? Cast(this.props.Document._docRangeFilters, listSpec("string"), []));
-        }
-        searchFilterDocs = () => {
-            return this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs);
-        }
+        collectionFilters = () => this._focusFilters ?? Cast(this.props.Document._docFilters, listSpec("string"), []);
+        collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
+        childDocFilters = () => [...this.props.docFilters(), ...this.collectionFilters()];
+        childDocRangeFilters = () => [...(this.props.docRangeFilters?.() || []), ...this.collectionRangeDocFilters()];
+        IsFiltered = () => this.collectionFilters().length || this.collectionRangeDocFilters().length ? "hasFilter" :
+            this.props.docFilters().length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined;
+        searchFilterDocs = () => this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs);
         @computed.struct get childDocs() {
             TraceMobx();
             let rawdocs: (Doc | Promise<Doc>)[] = [];
@@ -108,8 +113,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
             const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
             const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
 
-            const docFilters = this.docFilters();
-            const docRangeFilters = this.docRangeFilters();
+            const docFilters = this.childDocFilters();
+            const docRangeFilters = this.childDocRangeFilters();
             const searchDocs = this.searchFilterDocs();
             if (this.props.Document.dontRegisterView || (!docFilters.length && !docRangeFilters.length && !searchDocs.length)) {
                 return childDocs.filter(cd => !cd.cookies); // remove any documents that require a cookie if there are no filters to provide one
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 08b5e6bac..292dfd77c 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -32,9 +32,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
     @observable _collapsed: boolean = false;
     @observable _childClickedScript: Opt<ScriptField>;
     @observable _viewDefDivClick: Opt<ScriptField>;
-    @observable _focusDocFilters: Opt<string[]>; // fields that get overridden by a focus anchor
     @observable _focusPivotField: Opt<string>;
-    @observable _focusRangeFilters: Opt<string[]>;
 
     getAnchor = () => {
         const anchor = Docs.Create.HTMLAnchorDocument([], {
@@ -72,9 +70,9 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
     @action
     setViewSpec = (anchor: Doc, preview: boolean) => {
         if (preview) {   // if in preview, then override document's fields with view spec
+            this._focusFilters = StrListCast(Doc.GetProto(anchor).docFilters);
+            this._focusRangeFilters = StrListCast(Doc.GetProto(anchor).docRangeFilters);
             this._focusPivotField = StrCast(anchor.pivotField);
-            this._focusDocFilters = StrListCast(anchor.docFilters);
-            this._focusRangeFilters = StrListCast(anchor.docRangeFilters);
         } else if (anchor.pivotField !== undefined) {  // otherwise set document's fields based on anchor view spec
             this.layoutDoc._prevFilterIndex = 1;
             this.layoutDoc._pivotField = StrCast(anchor.pivotField);
@@ -84,8 +82,6 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
         return 0;
     }
 
-    pivotDocFilters = () => this._focusDocFilters || this.props.docFilters();
-    pivotDocRangeFilters = () => this._focusRangeFilters || this.props.docRangeFilters();
     layoutEngine = () => this._layoutEngine;
     toggleVisibility = action(() => this._collapsed = !this._collapsed);
 
@@ -139,10 +135,8 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
         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 }}
+                engineProps={{ pivotField: this.pivotField, docFilters: this.childDocFilters, docRangeFilters: this.childDocRangeFilters }}
                 fitContentsToDoc={returnTrue}
-                docFilters={this.pivotDocFilters}
-                docRangeFilters={this.pivotDocRangeFilters}
                 childClickScript={this._childClickedScript}
                 viewDefDivClick={this._viewDefDivClick}
                 childFreezeDimensions={true}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index e225c4a11..2718cbbbf 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,4 +1,4 @@
-import { computed, observable, runInAction } from 'mobx';
+import { computed, observable, runInAction, action } 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
@@ -236,13 +236,19 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
     * Shows the filter icon if it's a user-created collection which isn't a dashboard and has some docFilters applied on it or on the current dashboard.
     */
     @computed get showFilterIcon() {
-        return this.props.Document.viewType !== CollectionViewType.Docking && !Doc.IsSystem(this.props.Document) && ((StrListCast(this.props.Document._docFilters).length || StrListCast(this.props.Document._docRangeFilters).length || StrListCast(CurrentUserUtils.ActiveDashboard._docFilters).length || StrListCast(CurrentUserUtils.ActiveDashboard._docRangeFilters).length));
+        return this.props.Document.viewType !== CollectionViewType.Docking && !Doc.IsSystem(this.props.Document) && this._subView?.IsFiltered()
     }
 
+    @observable _subView: any = undefined;
+
     render() {
         TraceMobx();
         const props: SubCollectionViewProps = {
             ...this.props,
+            SetSubView: action((subView: any) => {
+                console.log("Setting sub", subView);
+                return this._subView = subView
+            }),
             addDocument: this.addDocument,
             moveDocument: this.moveDocument,
             removeDocument: this.removeDocument,
@@ -260,8 +266,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             {this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
             {this.showFilterIcon ?
                 <FontAwesomeIcon icon={"filter"} size="lg"
-                    style={{ position: 'absolute', top: '1%', right: '1%', cursor: "pointer", padding: 1, color: '#18c718bd', zIndex: 1 }}
-                    onPointerDown={e => { runInAction(() => CurrentUserUtils.propertiesWidth = 250); e.stopPropagation(); }}
+                    style={{ position: 'absolute', top: '1%', right: '1%', cursor: "pointer", padding: 1, color: this.showFilterIcon === "hasFilter" ? '#18c718bd' : "orange", zIndex: 1 }}
+                    onPointerDown={action(e => { this.props.select(false); CurrentUserUtils.propertiesWidth = 250; e.stopPropagation(); })}
                 />
                 : (null)}
         </div>);
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index a24f1eb7a..623e0f58d 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -363,8 +363,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 PanelHeight={this.PanelHeight}
                 layerProvider={this.layerProvider}
                 styleProvider={DefaultStyleProvider}
-                docFilters={CollectionDockingView.Instance.docFilters}
-                docRangeFilters={CollectionDockingView.Instance.docRangeFilters}
+                docFilters={CollectionDockingView.Instance.childDocFilters}
+                docRangeFilters={CollectionDockingView.Instance.childDocRangeFilters}
                 searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
                 addDocument={undefined}
                 removeDocument={undefined}
@@ -468,6 +468,7 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
             <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.props.background() }}>
                 <CollectionFreeFormView
                     Document={this.props.document}
+                    SetSubView={() => this}
                     CollectionView={undefined}
                     ContainingCollectionView={undefined}
                     ContainingCollectionDoc={undefined}
@@ -496,8 +497,8 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                     layerProvider={undefined}
                     addDocTab={this.props.addDocTab}
                     pinToPres={TabDocView.PinDoc}
-                    docFilters={CollectionDockingView.Instance.docFilters}
-                    docRangeFilters={CollectionDockingView.Instance.docRangeFilters}
+                    docFilters={CollectionDockingView.Instance.childDocFilters}
+                    docRangeFilters={CollectionDockingView.Instance.childDocRangeFilters}
                     searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
                     fitContentsToDoc={returnTrue}
                 />
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index ecc93285e..ba6222605 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -110,8 +110,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
     @observable _timelineRef = React.createRef<Timeline>();
     @observable _marqueeRef = React.createRef<HTMLDivElement>();
     @observable _keyframeEditing = false;
-    @observable _focusFilters: Opt<string[]>; // docFilters that are overridden when previewing a link to an anchor which has docFilters set on it
-    @observable _focusRangeFilters: Opt<string[]>; // docRangeFilters that are overridden when previewing a link to an anchor which has docRangeFilters set on it
     @observable ChildDrag: DocumentView | undefined; // child document view being dragged.  needed to update drop areas of groups when a group item is dragged.
 
     @computed get views() { return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); }
@@ -159,8 +157,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         this.layoutDoc._viewScale = vals.scale;
     }
     freeformData = (force?: boolean) => this.fitToContent || force ? this.fitToContentVals : undefined;
-    freeformDocFilters = () => this._focusFilters;
-    freeformRangeDocFilters = () => this._focusRangeFilters;
     reverseNativeScaling = () => this.fitToContent ? true : false;
     panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document._panX);
     panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document._panY);
@@ -1030,8 +1026,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             ScreenToLocalTransform={childLayout.z ? this.getTransformOverlay : this.getTransform}
             PanelWidth={childLayout[WidthSym]}
             PanelHeight={childLayout[HeightSym]}
-            docFilters={this.freeformDocFilters}
-            docRangeFilters={this.freeformRangeDocFilters}
+            docFilters={this.childDocFilters}
+            docRangeFilters={this.childDocRangeFilters}
             searchFilterDocs={this.searchFilterDocs}
             isContentActive={this.isAnnotationOverlay ? this.props.isContentActive : returnFalse}
             isDocumentActive={this.props.childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index f3a39a262..65c345547 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -237,8 +237,8 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
             onDoubleClick={this.onChildDoubleClickHandler}
             ScreenToLocalTransform={dxf}
             focus={this.props.focus}
-            docFilters={this.docFilters}
-            docRangeFilters={this.docRangeFilters}
+            docFilters={this.childDocFilters}
+            docRangeFilters={this.childDocRangeFilters}
             searchFilterDocs={this.searchFilterDocs}
             ContainingCollectionDoc={this.props.CollectionView?.props.Document}
             ContainingCollectionView={this.props.CollectionView}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 29cb3511a..30836854a 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -236,9 +236,9 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
             onDoubleClick={this.onChildDoubleClickHandler}
             ScreenToLocalTransform={dxf}
             focus={this.props.focus}
-            docFilters={this.docFilters}
+            docFilters={this.childDocFilters}
             isContentActive={returnFalse}
-            docRangeFilters={this.docRangeFilters}
+            docRangeFilters={this.childDocRangeFilters}
             searchFilterDocs={this.searchFilterDocs}
             ContainingCollectionDoc={this.props.CollectionView?.props.Document}
             ContainingCollectionView={this.props.CollectionView}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 585cda729..fed64b620 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -413,8 +413,8 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
                     isContentActive={returnTrue}
                     isDocumentActive={returnFalse}
                     ScreenToLocalTransform={this.getPreviewTransform}
-                    docFilters={this.docFilters}
-                    docRangeFilters={this.docRangeFilters}
+                    docFilters={this.childDocFilters}
+                    docRangeFilters={this.childDocRangeFilters}
                     searchFilterDocs={this.searchFilterDocs}
                     styleProvider={DefaultStyleProvider}
                     layerProvider={undefined}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c218b805e..bea219831 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -105,9 +105,9 @@ export interface DocumentViewSharedProps {
     styleProvider: Opt<StyleProviderFunc>;
     focus: DocFocusFunc;
     fitWidth?: () => boolean;
-    docFilters?: () => Opt<string[]>;
-    docRangeFilters?: () => Opt<string[]>;
-    searchFilterDocs?: () => Opt<Doc[]>;
+    docFilters: () => string[];
+    docRangeFilters: () => string[];
+    searchFilterDocs: () => Doc[];
     whenChildContentsActiveChanged: (isActive: boolean) => void;
     rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected
     addDocTab: (doc: Doc, where: string) => boolean;
-- 
cgit v1.2.3-70-g09d2


From 3c78da4d7724ca411486083176e394b18177231d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 4 Aug 2021 13:55:36 -0400
Subject: from last

---
 src/client/views/collections/CollectionSubView.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index e5f266acf..a9b5ce465 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -22,7 +22,7 @@ import ReactLoading from 'react-loading';
 
 export interface SubCollectionViewProps extends CollectionViewProps {
     CollectionView: Opt<CollectionView>;
-    SetSubView: (subView: any) => void;
+    SetSubView?: (subView: any) => void;
 }
 
 export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: X) {
@@ -49,7 +49,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
         }
 
         componentDidMount() {
-            this.props.SetSubView(this);
+            this.props.SetSubView?.(this);
         }
 
         componentWillUnmount() {
-- 
cgit v1.2.3-70-g09d2


From d756ffd3daa24270361648454062e98f190ae964 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 6 Aug 2021 10:34:57 -0400
Subject: fixed webboxes so that you can link to an annotation and it will
 restore the url as well.   a bunch of warnings cleanup.

---
 src/client/util/DocumentManager.ts                        |  6 ++----
 src/client/views/DocumentButtonBar.tsx                    |  2 +-
 src/client/views/InkStrokeProperties.ts                   |  2 +-
 src/client/views/collections/CollectionSubView.tsx        |  2 +-
 src/client/views/collections/CollectionView.tsx           |  2 +-
 src/client/views/collections/TabDocView.tsx               |  4 ++--
 src/client/views/linking/LinkPopup.tsx                    |  1 -
 src/client/views/nodes/DocumentLinksButton.tsx            |  4 ++--
 src/client/views/nodes/PDFBox.tsx                         |  2 +-
 src/client/views/nodes/WebBox.tsx                         | 15 ++++++++++-----
 src/client/views/nodes/formattedText/FormattedTextBox.tsx |  1 -
 src/fields/Doc.ts                                         |  2 +-
 12 files changed, 22 insertions(+), 21 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 27ae0447a..cb0ee411c 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -163,7 +163,8 @@ export class DocumentManager {
         const contextDocs = docContext ? await DocListCastAsync(docContext.data) : undefined;
         const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc) || Doc.AreProtosEqual(doc, annotatedDoc)) ? docContext : undefined;
         const targetDocContext = contextDoc || annotatedDoc;
-        var targetDocContextView = targetDocContext && getFirstDocView(targetDocContext);
+        const targetDocContextView = (targetDocContext && getFirstDocView(targetDocContext)) ||
+            (wasHidden && annoContainerView);// if we have an annotation container and the target was hidden, then try again because we just un-hid the document above
         const focusView = !docView && targetDoc.type === DocumentType.MARKER && annoContainerView ? annoContainerView : docView;
         if (!docView && annoContainerView) {
             annoContainerView.focus(targetDoc);  // this allows something like a PDF view to remove its doc filters to expose the target so that it can be found in the retry code below
@@ -181,9 +182,6 @@ export class DocumentManager {
             if (!targetDocContext) { // we don't have a view and there's no context specified ... create a new view of the target using the dockFunc or default
                 createViewFunc(Doc.BrushDoc(targetDoc), finished); // bcz: should we use this?: Doc.MakeAlias(targetDoc)));
             } else {  // otherwise try to get a view of the context of the target
-                if (annoContainerView && wasHidden) { // if we have an annotation container and the target was hidden, then try again because we just un-hid the document above
-                    targetDocContextView = annoContainerView;
-                }
                 if (targetDocContextView) { // we found a context view and aren't forced to create a new one ... focus on the context first..
                     targetDocContext._viewTransition = "transform 500ms";
                     targetDocContextView.props.focus(targetDocContextView.rootDoc, {
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index df1e6899d..5f09a322c 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -355,7 +355,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
             <div className="documentButtonBar-button">
                 <DocumentLinksButton View={this.view0} AlwaysOn={true} InMenu={true} StartLink={true} />
             </div>
-            {(DocumentLinksButton.StartLink || Doc.UserDoc()["documentLinksButton-fullMenu"]) && DocumentLinksButton.StartLink != doc ? <div className="documentButtonBar-button">
+            {(DocumentLinksButton.StartLink || Doc.UserDoc()["documentLinksButton-fullMenu"]) && DocumentLinksButton.StartLink !== doc ? <div className="documentButtonBar-button">
                 <DocumentLinksButton View={this.view0} AlwaysOn={true} InMenu={true} StartLink={false} />
             </div> : (null)}
             {/*!Doc.UserDoc()["documentLinksButton-fullMenu"] ? (null) : <div className="documentButtonBar-button">
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index 76ca5b5ec..6444e4451 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -283,7 +283,7 @@ export class InkStrokeProperties {
      */
     @action
     rotatePoint = (target: PointData, origin: PointData, angle: number) => {
-        let rotatedTarget = { X: target.X - origin.X, Y: target.Y - origin.Y };
+        const rotatedTarget = { X: target.X - origin.X, Y: target.Y - origin.Y };
         const newX = Math.cos(angle) * rotatedTarget.X - Math.sin(angle) * rotatedTarget.Y;
         const newY = Math.sin(angle) * rotatedTarget.X + Math.cos(angle) * rotatedTarget.Y;
         rotatedTarget.X = newX + origin.X;
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index a9b5ce465..227635c9b 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -93,7 +93,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
         childDocFilters = () => [...this.props.docFilters(), ...this.collectionFilters()];
         childDocRangeFilters = () => [...(this.props.docRangeFilters?.() || []), ...this.collectionRangeDocFilters()];
         IsFiltered = () => this.collectionFilters().length || this.collectionRangeDocFilters().length ? "hasFilter" :
-            this.props.docFilters().length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined;
+            this.props.docFilters().length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined
         searchFilterDocs = () => this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs);
         @computed.struct get childDocs() {
             TraceMobx();
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 2ae06d2f4..e65ebf075 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -236,7 +236,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
     * Shows the filter icon if it's a user-created collection which isn't a dashboard and has some docFilters applied on it or on the current dashboard.
     */
     @computed get showFilterIcon() {
-        return this.props.Document.viewType !== CollectionViewType.Docking && !Doc.IsSystem(this.props.Document) && this._subView?.IsFiltered()
+        return this.props.Document.viewType !== CollectionViewType.Docking && !Doc.IsSystem(this.props.Document) && this._subView?.IsFiltered();
     }
 
     @observable _subView: any = undefined;
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 1f73793b6..1969d728c 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -172,8 +172,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             const stack: HTMLDivElement = tab.contentItem.parent;
             const header: HTMLDivElement = tab;
             stack.onscroll = action((e: any) => {
-                console.log('scrolling...')
-            })
+                console.log('scrolling...');
+            });
             const moreInfoDrag = document.createElement("div");
             moreInfoDrag.className = "lm_iconWrap";
             tab._disposers.buttonDisposer = reaction(() => this.view, view =>
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index 2c4b718f4..df469c53b 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -54,7 +54,6 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
     @action
     onLinkChange = (e: React.ChangeEvent<HTMLInputElement>) => {
         this.linkURL = e.target.value;
-        console.log(this.linkURL)
     }
 
 
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index b63174e54..7648e866e 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -114,7 +114,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
                     DocumentLinksButton.StartLink = this.props.View.props.Document;
                     DocumentLinksButton.StartLinkView = this.props.View;
                 }
-            };
+            }
         }));
     }
 
@@ -291,7 +291,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
                         (null)
                 }
             </div>
-        )
+        );
     }
 
     render() {
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index b1f2070f8..23236cf20 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -217,7 +217,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     }
     sidebarWidth = () => !this.SidebarShown ? 0 :
         this._previewWidth ? PDFBox.openSidebarWidth :
-            (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth);
+            (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth)
 
     specificContextMenu = (e: React.MouseEvent): void => {
         const funcs: ContextMenuProps[] = [];
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 751d63711..ca281d68f 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -164,7 +164,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     menuControls = () => this.urlEditor; // controls to be added to the top bar when a document of this type is selected
 
     scrollFocus = (doc: Doc, smooth: boolean) => {
-        if (StrCast(doc.data) !== this._url) this.submitURL(StrCast(doc.data));
+        if (StrCast(doc.webUrl) !== this._url) this.submitURL(StrCast(doc.webUrl));
         if (DocListCast(this.props.Document[this.fieldKey + "-sidebar"]).includes(doc) && !this.SidebarShown) {
             this.toggleSidebar(!smooth);
         }
@@ -191,7 +191,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 annotationOn: this.rootDoc,
                 y: NumCast(this.layoutDoc._scrollTop)
             });
-        this.addDocument(anchor);
+        this.addDocumentWrapper(anchor);
         return anchor;
     }
 
@@ -444,9 +444,14 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return view;
     }
 
+    addDocumentWrapper = (doc: Doc | Doc[], annotationKey?: string) => {
+        (doc instanceof Doc ? [doc] : doc).forEach(doc => doc.webUrl = this._url);
+        return this.addDocument(doc, annotationKey);
+    }
+
     sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
         if (!this.layoutDoc._showSidebar) this.toggleSidebar();
-        return this.addDocument(doc, sidebarKey);
+        return this.addDocumentWrapper(doc, sidebarKey);
     }
     sidebarBtnDown = (e: React.PointerEvent) => {
         setupMoveUpEvents(this, e, (e, down, delta) => {
@@ -482,7 +487,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     sidebarWidth = () => !this.SidebarShown ? 0 :
         this._previewWidth ? WebBox.openSidebarWidth :
             (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() /
-            NumCast(this.layoutDoc.nativeWidth);
+            NumCast(this.layoutDoc.nativeWidth)
 
     @computed get content() {
         return <div className={"webBox-cont" + (!this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.isContentActive() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting ? "-interactive" : "")}
@@ -561,7 +566,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                             anchorMenuClick={this.anchorMenuClick}
                             scrollTop={0}
                             down={this._marqueeing} scaling={returnOne}
-                            addDocument={this.addDocument}
+                            addDocument={this.addDocumentWrapper}
                             docView={this.props.docViewPath().lastElement()}
                             finishMarquee={this.finishMarquee}
                             savedAnnotations={this._savedAnnotations}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index e5c36ea71..edd7177de 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -215,7 +215,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         AnchorMenu.Instance.Status = "marquee";
         AnchorMenu.Instance.Highlight = action((color: string, isLinkButton: boolean) => {
             this._editorView?.state && RichTextMenu.Instance.insertHighlight(color, this._editorView.state, this._editorView?.dispatch);
-            console.log("highlight")
             return undefined;
         });
         /**
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 6dcf34a3a..0cbfaf067 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1214,7 +1214,7 @@ export namespace Doc {
             case DocumentType.RTF: return "sticky-note";
             case DocumentType.COL:
                 const folder: IconProp = isOpen ? "folder-open" : "folder";
-                const chevron: IconProp = isOpen ? "chevron-down" : "chevron-right"
+                const chevron: IconProp = isOpen ? "chevron-down" : "chevron-right";
                 return !doc?.isFolder ? folder : chevron;
             case DocumentType.WEB: return "globe-asia";
             case DocumentType.SCREENSHOT: return "photo-video";
-- 
cgit v1.2.3-70-g09d2


From dbdcff75d76fb54a0e085cc0958a07ded32d0b45 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 9 Aug 2021 18:14:00 -0400
Subject: fixed bug where shared list field items weren't being received as
 Documents so they didn't update -- eg add a private item to a list, then try
 to make it public

---
 src/client/DocServer.ts                            |  2 +-
 src/client/views/collections/CollectionSubView.tsx |  4 ++--
 src/fields/List.ts                                 | 19 +++++++------------
 3 files changed, 10 insertions(+), 15 deletions(-)

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

diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index f4e3a22cf..e498a7cca 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -398,7 +398,7 @@ export namespace DocServer {
                             (_cache[field.id] as any).then((f: any) => fieldMap[field.id] = f);
                         } else if (field) {
                             proms.push(_cache[field.id] as any);
-                            fieldMap[field.id] = field;
+                            fieldMap[field.id] = DocServer.GetCachedRefField(field.id) || field;
                         }
                     }
                 });
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 227635c9b..2f07c0241 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -80,8 +80,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
         get childLayoutPairs(): { layout: Doc; data: Doc; }[] {
             const { Document, DataDoc } = this.props;
             const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.isAnnotationOverlay ? DataDoc : undefined, doc)).
-                filter(pair => {  // filter out any documents that have a proto that we don't have permissions to (which we determine by not having any keys
-                    return pair.layout && /*!pair.layout.hidden &&*/ (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate));// Object.keys(pair.layout.proto).length));
+                filter(pair => {  // filter out any documents that have a proto that we don't have permissions to
+                    return pair.layout && (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate));
                 });
             return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types
         }
diff --git a/src/fields/List.ts b/src/fields/List.ts
index 215dff34b..93a8d1d60 100644
--- a/src/fields/List.ts
+++ b/src/fields/List.ts
@@ -1,4 +1,4 @@
-import { action, observable, runInAction } from "mobx";
+import { action, observable } from "mobx";
 import { alias, list, serializable } from "serializr";
 import { DocServer } from "../client/DocServer";
 import { Scripting } from "../client/util/Scripting";
@@ -264,24 +264,19 @@ class ListImpl<T extends Field> extends ObjectField {
     // this requests all ProxyFields at the same time to avoid the overhead
     // of separate network requests and separate updates to the React dom.
     private __realFields() {
-        const waiting = this.__fields.filter(f => f instanceof ProxyField && f.promisedValue());
-        const promised = waiting.map(f => f instanceof ProxyField ? f.promisedValue() : "");
+        const promised = this.__fields.filter(f => f instanceof ProxyField && f.promisedValue()).map(f => ({ field: f as any, promisedFieldId: (f instanceof ProxyField) ? f.promisedValue() : "" }));
         // if we find any ProxyFields that don't have a current value, then
         // start the server request for all of them
         if (promised.length) {
-            const promise = DocServer.GetRefFields(promised);
+            const batchPromise = DocServer.GetRefFields(promised.map(p => p.promisedFieldId));
             // as soon as we get the fields from the server, set all the list values in one
             // action to generate one React dom update.
-            promise.then(fields => runInAction(() => {
-                waiting.map((w, i) => w instanceof ProxyField && w.setValue(fields[promised[i]]));
-            }));
+            batchPromise.then(pfields => promised.forEach(p => p.field.setValue(pfields[p.promisedFieldId])));
             // we also have to mark all lists items with this promise so that any calls to them
-            // will await the batch request.
-            // This counts on the handler for 'promise' in the call above being invoked before the
+            // will await the batch request and return the requested field value.
+            // This assumes the handler for 'promise' in the call above being invoked before the
             // handler for 'promise' in the lines below.
-            waiting.map((w, i) => {
-                w instanceof ProxyField && w.setPromise(promise.then(fields => fields[promised[i]]));
-            });
+            promised.forEach(p => p.field.setPromise(batchPromise.then(pfields => pfields[p.promisedFieldId])));
         }
         return this.__fields.map(toRealField);
     }
-- 
cgit v1.2.3-70-g09d2


From a38501569769c00dc1c25fb57d09ca88f3951c3d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 24 Aug 2021 12:21:01 -0400
Subject: from last

---
 src/client/views/collections/CollectionSubView.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 2f07c0241..c7629acbe 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,6 +1,6 @@
 import { action, computed, IReactionDisposer, reaction, observable, runInAction } from "mobx";
 import CursorField from "../../../fields/CursorField";
-import { Doc, Opt, Field, DocListCast, AclPrivate } from "../../../fields/Doc";
+import { Doc, Opt, Field, DocListCast, AclPrivate, StrListCast } from "../../../fields/Doc";
 import { Id, ToString } from "../../../fields/FieldSymbols";
 import { List } from "../../../fields/List";
 import { listSpec } from "../../../fields/Schema";
@@ -88,7 +88,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
         get childDocList() {
             return Cast(this.dataField, listSpec(Doc));
         }
-        collectionFilters = () => this._focusFilters ?? Cast(this.props.Document._docFilters, listSpec("string"), []);
+        collectionFilters = () => this._focusFilters ?? StrListCast(this.props.Document._docFilters);
         collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
         childDocFilters = () => [...this.props.docFilters(), ...this.collectionFilters()];
         childDocRangeFilters = () => [...(this.props.docRangeFilters?.() || []), ...this.collectionRangeDocFilters()];
-- 
cgit v1.2.3-70-g09d2


From 66dd6788fbf46cd827d80eb97810e4d2af24eb26 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 24 Aug 2021 14:52:35 -0400
Subject: suppressed filter icon for annotations that are filtered based on
 transparency.  fixed drawing ink on webbox's.

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

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

diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index c7629acbe..55b1e4031 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -93,7 +93,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
         childDocFilters = () => [...this.props.docFilters(), ...this.collectionFilters()];
         childDocRangeFilters = () => [...(this.props.docRangeFilters?.() || []), ...this.collectionRangeDocFilters()];
         IsFiltered = () => this.collectionFilters().length || this.collectionRangeDocFilters().length ? "hasFilter" :
-            this.props.docFilters().length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined
+            this.props.docFilters().filter(f => !f.includes("__value__")).length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined
         searchFilterDocs = () => this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs);
         @computed.struct get childDocs() {
             TraceMobx();
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 94697464a..cdc79678a 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -534,7 +534,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 moveDocument={this.moveDocument}
                 addDocument={this.sidebarAddDocument}
                 childPointerEvents={true}
-                pointerEvents={this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none"} />;
+                pointerEvents={CurrentUserUtils.SelectedTool !== InkTool.None || this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none"} />;
         return (
             <div className="webBox" ref={this._mainCont} style={{ pointerEvents: this.isContentActive() ? "all" : this.isContentActive() || SnappingManager.GetIsDragging() ? undefined : "none" }} >
                 <div className={`webBox-container`} style={{ pointerEvents }} onContextMenu={this.specificContextMenu}>
-- 
cgit v1.2.3-70-g09d2


From fe818efd80e649b841009b69841b176cee4c5c8c Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 25 Aug 2021 11:53:49 -0400
Subject: cleaned up and fixed tests for nonrecursive doc filters as used in
 PDF/Web to separate transparent from non-transparent docs into layers.

---
 src/Utils.ts                                       | 12 +++++-
 src/client/views/collections/CollectionSubView.tsx | 48 ++++++++++++----------
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  4 +-
 src/client/views/nodes/WebBox.tsx                  | 14 ++++---
 src/client/views/pdf/PDFViewer.tsx                 | 14 ++++---
 src/fields/Doc.ts                                  |  2 +-
 6 files changed, 58 insertions(+), 36 deletions(-)

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

diff --git a/src/Utils.ts b/src/Utils.ts
index f90296121..5d86c755a 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -115,13 +115,21 @@ export namespace Utils {
         return { r: r, g: g, b: b, a: a };
     }
 
+    const isTransparentFunctionHack = "isTransparent(__value__)";
+    const noRecursionHack = "__noRecursion";
+    export function IsRecursiveFilter(val: string) {
+        return !val.includes(noRecursionHack);
+    }
+    export function HasTransparencyFilter(val: string) {
+        return val.includes(isTransparentFunctionHack);
+    }
     export function IsTransparentFilter() {
         // bcz: isTransparent(__value__) is a hack.  it would be nice to have acual functions be parsed, but now Doc.matchFieldValue is hardwired to recognize just this one
-        return ["backgroundColor:isTransparent(__value__):check"];
+        return `backgroundColor:${isTransparentFunctionHack},${noRecursionHack}:check`;// bcz: hack.  noRecursion should probably be either another ':' delimited field, or it should be a modifier to the comparision (eg., check, x, etc) field
     }
     export function IsOpaqueFilter() {
         // bcz: isTransparent(__value__) is a hack.  it would be nice to have acual functions be parsed, but now Doc.matchFieldValue is hardwired to recognize just this one
-        return ["backgroundColor:isTransparent(__value__):x"];
+        return `backgroundColor:${isTransparentFunctionHack},${noRecursionHack}:x`;// bcz: hack.  noRecursion should probably be either another ':' delimited field, or it should be a modifier to the comparision (eg., check, x, etc) field
     }
 
 
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 55b1e4031..1f4c35daa 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -90,10 +90,11 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
         }
         collectionFilters = () => this._focusFilters ?? StrListCast(this.props.Document._docFilters);
         collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
-        childDocFilters = () => [...this.props.docFilters(), ...this.collectionFilters()];
+        childDocFilters = () => [...(this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()];
+        unrecursiveDocFilters = () => [...(this.props.docFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])];
         childDocRangeFilters = () => [...(this.props.docRangeFilters?.() || []), ...this.collectionRangeDocFilters()];
         IsFiltered = () => this.collectionFilters().length || this.collectionRangeDocFilters().length ? "hasFilter" :
-            this.props.docFilters().filter(f => !f.includes("__value__")).length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined
+            this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)).length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined
         searchFilterDocs = () => this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs);
         @computed.struct get childDocs() {
             TraceMobx();
@@ -113,10 +114,10 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
             const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
             const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
 
-            const docFilters = this.childDocFilters();
+            const childDocFilters = this.childDocFilters();
             const docRangeFilters = this.childDocRangeFilters();
             const searchDocs = this.searchFilterDocs();
-            if (this.props.Document.dontRegisterView || (!docFilters.length && !docRangeFilters.length && !searchDocs.length)) {
+            if (this.props.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !docRangeFilters.length && !searchDocs.length)) {
                 return childDocs.filter(cd => !cd.cookies); // remove any documents that require a cookie if there are no filters to provide one
             }
 
@@ -127,24 +128,27 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
             const docsforFilter: Doc[] = [];
             childDocs.forEach((d) => {
                 // if (DocUtils.Excluded(d, docFilters)) return;
-                let notFiltered = d.z || Doc.IsSystem(d) || ((!searchDocs.length || searchDocs.includes(d)) && (DocUtils.FilterDocs([d], docFilters, docRangeFilters, viewSpecScript, this.props.Document).length > 0));
-                const fieldKey = Doc.LayoutFieldKey(d);
-                const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView");
-                const data = d[annos ? fieldKey + "-annotations" : fieldKey];
-                if (data !== undefined) {
-                    let subDocs = DocListCast(data);
-                    if (subDocs.length > 0) {
-                        let newarray: Doc[] = [];
-                        notFiltered = notFiltered || (!searchDocs.length && DocUtils.FilterDocs(subDocs, docFilters, docRangeFilters, viewSpecScript, d).length);
-                        while (subDocs.length > 0 && !notFiltered) {
-                            newarray = [];
-                            subDocs.forEach((t) => {
-                                const fieldKey = Doc.LayoutFieldKey(t);
-                                const annos = !Field.toString(Doc.LayoutField(t) as Field).includes("CollectionView");
-                                notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!docFilters.length && !docRangeFilters.length) || DocUtils.FilterDocs([t], docFilters, docRangeFilters, viewSpecScript, d).length));
-                                DocListCast(t[annos ? fieldKey + "-annotations" : fieldKey]).forEach((newdoc) => newarray.push(newdoc));
-                            });
-                            subDocs = newarray;
+                let notFiltered = d.z || Doc.IsSystem(d) || (DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), docRangeFilters, viewSpecScript, this.props.Document).length > 0);
+                if (notFiltered) {
+                    notFiltered = ((!searchDocs.length || searchDocs.includes(d)) && (DocUtils.FilterDocs([d], childDocFilters, docRangeFilters, viewSpecScript, this.props.Document).length > 0));
+                    const fieldKey = Doc.LayoutFieldKey(d);
+                    const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView");
+                    const data = d[annos ? fieldKey + "-annotations" : fieldKey];
+                    if (data !== undefined) {
+                        let subDocs = DocListCast(data);
+                        if (subDocs.length > 0) {
+                            let newarray: Doc[] = [];
+                            notFiltered = notFiltered || (!searchDocs.length && DocUtils.FilterDocs(subDocs, childDocFilters, docRangeFilters, viewSpecScript, d).length);
+                            while (subDocs.length > 0 && !notFiltered) {
+                                newarray = [];
+                                subDocs.forEach((t) => {
+                                    const fieldKey = Doc.LayoutFieldKey(t);
+                                    const annos = !Field.toString(Doc.LayoutField(t) as Field).includes("CollectionView");
+                                    notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !docRangeFilters.length) || DocUtils.FilterDocs([t], childDocFilters, docRangeFilters, viewSpecScript, d).length));
+                                    DocListCast(t[annos ? fieldKey + "-annotations" : fieldKey]).forEach((newdoc) => newarray.push(newdoc));
+                                });
+                                subDocs = newarray;
+                            }
                         }
                     }
                 }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index d09d9b9d7..b5d9ebd9f 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -74,6 +74,8 @@ export type collectionFreeformViewProps = {
     scaleField?: string;
     noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale)
     engineProps?: any;
+    dontRenderDocuments?: boolean; // used for annotation overlays which need to distribute documents into different freeformviews with different mixBlendModes depending on whether they are trnasparent or not.  
+    // However, this screws up interactions since only the top layer gets events.  so we render the freeformview a 3rd time with all documents in order to get interaction events (eg., marquee) but we don't actually want to display the documents.
 };
 
 @observer
@@ -1452,7 +1454,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             getContainerTransform={this.getContainerTransform}
             getTransform={this.getTransform}
             isAnnotationOverlay={this.isAnnotationOverlay}>
-            <div ref={this._marqueeRef}>
+            <div ref={this._marqueeRef} style={{ display: this.props.dontRenderDocuments ? "none" : undefined }}>
                 {this.layoutDoc["_backgroundGrid-show"] ? this.backgroundGrid : (null)}
                 <CollectionFreeFormViewPannableContents
                     isAnnotationOverlay={this.isAnnotationOverlay}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index cdc79678a..ae6b90e41 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -13,7 +13,7 @@ import { ComputedField } from "../../../fields/ScriptField";
 import { Cast, NumCast, StrCast } from "../../../fields/Types";
 import { WebField } from "../../../fields/URLField";
 import { TraceMobx } from "../../../fields/util";
-import { emptyFunction, getWordAtPoint, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, smoothScroll, Utils } from "../../../Utils";
+import { emptyFunction, getWordAtPoint, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, smoothScroll, Utils, returnEmptyString, returnEmptyFilter } from "../../../Utils";
 import { Docs } from "../../documents/Documents";
 import { DocumentType } from '../../documents/DocumentTypes';
 import { CurrentUserUtils } from "../../util/CurrentUserUtils";
@@ -508,11 +508,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document);
     scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop));
     anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
+    transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
+    opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
     render() {
         const pointerEvents = this.props.layerProvider?.(this.layoutDoc) === false ? "none" : undefined;
         const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
         const scale = previewScale * (this.props.scaling?.() || 1);
-        const renderAnnotations = (docFilters: () => string[]) =>
+        const renderAnnotations = (docFilters?: () => string[]) =>
             <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
                 renderDepth={this.props.renderDepth + 1}
                 isAnnotationOverlay={true}
@@ -524,7 +526,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 ScreenToLocalTransform={this.scrollXf}
                 scaling={returnOne}
                 dropAction={"alias"}
-                docFilters={docFilters}
+                docFilters={docFilters || this.props.docFilters}
+                dontRenderDocuments={docFilters ? false : true}
                 select={emptyFunction}
                 isContentActive={returnFalse}
                 ContentScaling={returnOne}
@@ -553,9 +556,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         <div className={"webBox-innerContent"} style={{ height: NumCast(this.scrollHeight, 50), pointerEvents }}>
                             {this.content}
                             <div style={{ mixBlendMode: "multiply" }}>
-                                {renderAnnotations(Utils.IsTransparentFilter)}
+                                {renderAnnotations(this.transparentFilter)}
                             </div>
-                            {renderAnnotations(Utils.IsOpaqueFilter)}
+                            {renderAnnotations(this.opaqueFilter)}
+                            {renderAnnotations()}
                             {this.annotationLayer}
                         </div>
                     </div>
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 0261d24d9..734d9127c 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -9,7 +9,7 @@ import { createSchema } from "../../../fields/Schema";
 import { Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
 import { PdfField } from "../../../fields/URLField";
 import { TraceMobx } from "../../../fields/util";
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, OmitKeys, smoothScroll, Utils, returnFalse } from "../../../Utils";
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, OmitKeys, smoothScroll, Utils, returnFalse, returnEmptyString, returnEmptyFilter } from "../../../Utils";
 import { DocUtils } from "../../documents/Documents";
 import { Networking } from "../../Network";
 import { CurrentUserUtils } from "../../util/CurrentUserUtils";
@@ -506,8 +506,10 @@ export class PDFViewer extends React.Component<IViewerProps> {
     overlayTransform = () => this.scrollXf().scale(1 / this._zoomed);
     panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0);
     panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document);
+    transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
+    opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
     @computed get overlayLayer() {
-        const renderAnnotations = (docFilters: () => string[]) =>
+        const renderAnnotations = (docFilters?: () => string[]) =>
             <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
                 isAnnotationOverlay={true}
                 isContentActive={returnFalse}
@@ -519,7 +521,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 select={emptyFunction}
                 ContentScaling={this.contentZoom}
                 bringToFront={emptyFunction}
-                docFilters={docFilters}
+                docFilters={docFilters || this.props.docFilters}
+                dontRenderDocuments={docFilters ? false : true}
                 CollectionView={undefined}
                 ScreenToLocalTransform={this.overlayTransform}
                 renderDepth={this.props.renderDepth + 1}
@@ -531,7 +534,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                     mixBlendMode: "multiply",
                     transform: `scale(${this._zoomed})`
                 }}>
-                {renderAnnotations(Utils.IsTransparentFilter)}
+                {renderAnnotations(this.transparentFilter)}
             </div>
             <div className={`pdfViewerDash-overlay${CurrentUserUtils.SelectedTool !== InkTool.None || SnappingManager.GetIsDragging() ? "-inking" : ""}`}
                 style={{
@@ -539,7 +542,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
                     mixBlendMode: this.allAnnotations.some(anno => anno.mixBlendMode) ? "hard-light" : undefined,
                     transform: `scale(${this._zoomed})`
                 }}>
-                {renderAnnotations(Utils.IsOpaqueFilter)}
+                {renderAnnotations(this.opaqueFilter)}
+                {renderAnnotations()}
             </div>
         </div>;
     }
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index f6efefdf9..17f41fac8 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1088,7 +1088,7 @@ export namespace Doc {
     }
 
     export function matchFieldValue(doc: Doc, key: string, value: any): boolean {
-        if (value === "isTransparent(__value__)") {
+        if (Utils.HasTransparencyFilter(value)) {
             const isTransparent = (color: string) => color !== "" && (Color(color).alpha() !== 1);
             return isTransparent(StrCast(doc[key]));
         }
-- 
cgit v1.2.3-70-g09d2


From 2d8b3c6b73da1b7685903697525a277fd53340a5 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 26 Aug 2021 00:32:47 -0400
Subject: a lot of changes to move isContentActive into DocumentView

---
 src/Utils.ts                                       |  2 +-
 src/client/views/DocComponent.tsx                  | 23 ++++++++----------
 src/client/views/collections/CollectionSubView.tsx |  3 +--
 src/client/views/collections/CollectionView.tsx    |  8 ++++++-
 src/client/views/collections/TabDocView.tsx        |  3 ++-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 10 ++++----
 src/client/views/nodes/AudioBox.tsx                |  8 +++----
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  6 +++--
 src/client/views/nodes/ComparisonBox.tsx           | 17 ++++++++++----
 src/client/views/nodes/DocumentView.tsx            | 15 ++++++++----
 src/client/views/nodes/ImageBox.tsx                |  3 +--
 src/client/views/nodes/PDFBox.tsx                  | 11 ++++-----
 src/client/views/nodes/VideoBox.tsx                | 27 +++++++++++-----------
 src/client/views/nodes/WebBox.tsx                  | 12 ++++------
 .../views/nodes/formattedText/FormattedTextBox.tsx | 10 ++++----
 src/client/views/pdf/AnchorMenu.tsx                |  1 -
 src/client/views/pdf/PDFViewer.tsx                 |  3 +--
 src/fields/Doc.ts                                  |  3 +++
 18 files changed, 91 insertions(+), 74 deletions(-)

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

diff --git a/src/Utils.ts b/src/Utils.ts
index 102ac520b..de3b13f63 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -116,7 +116,7 @@ export namespace Utils {
     }
 
     const isTransparentFunctionHack = "isTransparent(__value__)";
-    const noRecursionHack = "__noRecursion";
+    export const noRecursionHack = "__noRecursion";
     export function IsRecursiveFilter(val: string) {
         return !val.includes(noRecursionHack);
     }
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index d9cc29bed..33dff9da5 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -1,17 +1,17 @@
-import { Doc, Opt, DataSym, AclReadonly, AclAugment, AclPrivate, AclEdit, AclSym, DocListCast, AclAdmin, AclSelfEdit } from '../../fields/Doc';
-import { Touchable } from './Touchable';
-import { computed, action, observable } from 'mobx';
-import { Cast, BoolCast, ScriptCast } from '../../fields/Types';
+import { action, computed, observable } from 'mobx';
+import { DateField } from '../../fields/DateField';
+import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, AclSym, DataSym, Doc, DocListCast, Opt } from '../../fields/Doc';
 import { InkTool } from '../../fields/InkField';
-import { InteractionUtils } from '../util/InteractionUtils';
 import { List } from '../../fields/List';
-import { DateField } from '../../fields/DateField';
 import { ScriptField } from '../../fields/ScriptField';
-import { GetEffectiveAcl, SharingPermissions, distributeAcls, denormalizeEmail, inheritParentAcls } from '../../fields/util';
-import { CurrentUserUtils } from '../util/CurrentUserUtils';
-import { DocUtils } from '../documents/Documents';
+import { Cast, ScriptCast } from '../../fields/Types';
+import { denormalizeEmail, distributeAcls, GetEffectiveAcl, inheritParentAcls, SharingPermissions } from '../../fields/util';
 import { returnFalse } from '../../Utils';
+import { DocUtils } from '../documents/Documents';
+import { CurrentUserUtils } from '../util/CurrentUserUtils';
+import { InteractionUtils } from '../util/InteractionUtils';
 import { UndoManager } from '../util/UndoManager';
+import { Touchable } from './Touchable';
 
 
 ///  DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView)
@@ -107,6 +107,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
         // key where data is stored
         @computed get fieldKey() { return this.props.fieldKey; }
 
+        isAnyChildContentActive = () => this._isAnyChildContentActive;
 
         lookupField = (field: string) => ScriptCast((this.layoutDoc as any).lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field }).result;
 
@@ -229,10 +230,6 @@ 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.isContentActive?.() || this.props.Document.forceActive ||
-                this.props.isSelected(outsideReaction) || this._isAnyChildContentActive ||
-                this.props.rootSelected(outsideReaction)) ? true : false)
     }
     return Component;
 }
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 1f4c35daa..b70df93da 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -23,6 +23,7 @@ import ReactLoading from 'react-loading';
 export interface SubCollectionViewProps extends CollectionViewProps {
     CollectionView: Opt<CollectionView>;
     SetSubView?: (subView: any) => void;
+    isAnyChildContentActive: () => boolean;
 }
 
 export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: X) {
@@ -490,7 +491,5 @@ import { FormattedTextBox, GoogleRef } from "../nodes/formattedText/FormattedTex
 import { CollectionView, CollectionViewType, CollectionViewProps } from "./CollectionView";
 import { SelectionManager } from "../../util/SelectionManager";
 import { OverlayView } from "../OverlayView";
-import { Hypothesis } from "../../util/HypothesisUtils";
 import { GetEffectiveAcl, TraceMobx } from "../../../fields/util";
-import { FilterBox } from "../nodes/FilterBox";
 
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index a821aeeea..229e93b9e 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -37,6 +37,7 @@ import { CollectionTreeView } from "./CollectionTreeView";
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import './CollectionView.scss';
 import { returnEmptyString } from '../../../Utils';
+import { InkTool } from '../../../fields/InkField';
 export const COLLECTION_BORDER_WIDTH = 2;
 const path = require('path');
 
@@ -119,7 +120,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
         // 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"} />;
-        this.isContentActive();
+        //this.isContentActive();
     }
 
     screenToLocalTransform = () => this.props.renderDepth ? this.props.ScreenToLocalTransform() : this.props.ScreenToLocalTransform().scale(this.props.PanelWidth() / this.bodyPanelWidth());
@@ -253,6 +254,9 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
 
     @observable _subView: any = undefined;
 
+    isContentActive = (outsideReaction?: boolean) => {
+        return this.props.isContentActive() ? true : false;
+    }
     render() {
         TraceMobx();
         const props: SubCollectionViewProps = {
@@ -262,6 +266,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             moveDocument: this.moveDocument,
             removeDocument: this.removeDocument,
             isContentActive: this.isContentActive,
+            isAnyChildContentActive: this.isAnyChildContentActive,
+            whenChildContentsActiveChanged: this.whenChildContentsActiveChanged,
             PanelWidth: this.bodyPanelWidth,
             PanelHeight: this.props.PanelHeight,
             ScreenToLocalTransform: this.screenToLocalTransform,
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index e24fcf372..117dba4de 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -480,7 +480,8 @@ 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}
-                    isContentActive={returnTrue}
+                    isContentActive={returnFalse}
+                    isAnyChildContentActive={returnFalse}
                     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 b5d9ebd9f..fb949a36d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,6 +1,7 @@
 import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { computedFn } from "mobx-utils";
+import { DateField } from "../../../../fields/DateField";
 import { Doc, HeightSym, Opt, StrListCast, WidthSym } from "../../../../fields/Doc";
 import { collectionSchema, documentSchema } from "../../../../fields/documentSchemas";
 import { Id } from "../../../../fields/FieldSymbols";
@@ -17,6 +18,7 @@ import { aggregateBounds, emptyFunction, intersectRect, returnFalse, setupMoveUp
 import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
 import { DocServer } from "../../../DocServer";
 import { Docs, DocUtils } from "../../../documents/Documents";
+import { DocumentType } from "../../../documents/DocumentTypes";
 import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
 import { DocumentManager } from "../../../util/DocumentManager";
 import { DragManager, dropActionType } from "../../../util/DragManager";
@@ -48,8 +50,7 @@ import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCurso
 import "./CollectionFreeFormView.scss";
 import { MarqueeView } from "./MarqueeView";
 import React = require("react");
-import { DocumentType } from "../../../documents/DocumentTypes";
-import { DateField } from "../../../../fields/DateField";
+import Color = require("color");
 
 export const panZoomSchema = createSchema({
     _panX: "number",
@@ -117,7 +118,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?.isContentActive() || this.props.isContentActive()); }
+    @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && 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 },
@@ -170,6 +171,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
     getContainerTransform = () => this.cachedGetContainerTransform.copy();
     getTransformOverlay = () => this.getContainerTransform().translate(1, 1);
     getActiveDocuments = () => this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout);
+    isAnyChildContentActive = () => this.props.isAnyChildContentActive();
     addLiveTextBox = (newBox: Doc) => {
         FormattedTextBox.SelectOnLoad = newBox[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed
         this.addDocument(newBox);
@@ -1033,7 +1035,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             docFilters={this.childDocFilters}
             docRangeFilters={this.childDocRangeFilters}
             searchFilterDocs={this.searchFilterDocs}
-            isContentActive={this.isAnnotationOverlay ? this.props.isContentActive : returnFalse}
+            isContentActive={returnFalse}
             isDocumentActive={this.props.childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
             focus={this.focusDocument}
             addDocTab={this.addDocTab}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 82bad971d..faaa887c4 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -267,7 +267,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     // returns the html audio element
     @computed get audio() {
-        return <audio ref={this.setRef} className={`audiobox-control${this.isContentActive() ? "-interactive" : ""}`}>
+        return <audio ref={this.setRef} className={`audiobox-control${this.props.isContentActive() ? "-interactive" : ""}`}>
             <source src={this.path} type="audio/mpeg" />
             Not supported.
         </audio>;
@@ -328,6 +328,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             focus={DocUtils.DefaultFocus}
             bringToFront={emptyFunction}
             CollectionView={undefined}
+            isAnyChildContentActive={this.isAnyChildContentActive}
             duration={this.duration}
             playFrom={this.playFrom}
             setTime={this.setAnchorTime}
@@ -337,7 +338,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             ScreenToLocalTransform={this.timelineScreenToLocal}
             Play={this.Play}
             Pause={this.Pause}
-            isContentActive={this.isContentActive}
             playLink={this.playLink}
             PanelWidth={this.timelineWidth}
             PanelHeight={this.timelineHeight}
@@ -345,7 +345,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     }
 
     render() {
-        const interactive = SnappingManager.GetIsDragging() || this.isContentActive() ? "-interactive" : "";
+        const interactive = SnappingManager.GetIsDragging() || this.props.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<ViewBoxAnnotatableProp
                             RECORD
                         </button>}
                 </div> :
-                <div className="audiobox-controls" style={{ pointerEvents: this._isAnyChildContentActive || this.isContentActive() ? "all" : "none" }} >
+                <div className="audiobox-controls" style={{ pointerEvents: this._isAnyChildContentActive || this.props.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/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 092823603..9cc4b1f9a 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -17,8 +17,8 @@ import { InkingStroke } from "../InkingStroke";
 import { StyleProp } from "../StyleProvider";
 import "./CollectionFreeFormDocumentView.scss";
 import { DocumentView, DocumentViewProps } from "./DocumentView";
-import { FieldViewProps } from "./FieldView";
 import React = require("react");
+import Color = require("color");
 
 export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
     dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined;
@@ -164,6 +164,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
             PanelWidth: this.panelWidth,
             PanelHeight: this.panelHeight,
         };
+        const background = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
+        const mixBlendMode = StrCast(this.layoutDoc.mixBlendMode) as any || (background && Color(background).alpha() !== 1 ? "multiply" : undefined);
         return <div className={"collectionFreeFormDocumentView-container"}
             style={{
                 outline: this.Highlight ? "orange solid 2px" : "",
@@ -172,7 +174,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 transform: this.transform,
                 transition: this.props.dataTransition ? this.props.dataTransition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.dataTransition),
                 zIndex: this.ZInd,
-                mixBlendMode: StrCast(this.layoutDoc.mixBlendMode) as any,
+                mixBlendMode,
                 display: this.ZInd === -99 ? "none" : undefined
             }} >
             <DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} />
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 153176afc..6708a08ee 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -1,17 +1,18 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, observable } from 'mobx';
 import { observer } from "mobx-react";
-import { Doc } from '../../../fields/Doc';
+import { Doc, Opt } from '../../../fields/Doc';
 import { documentSchema } from '../../../fields/documentSchemas';
 import { createSchema, makeInterface } from '../../../fields/Schema';
 import { Cast, NumCast, StrCast } from '../../../fields/Types';
-import { emptyFunction, OmitKeys, setupMoveUpEvents } from '../../../Utils';
+import { emptyFunction, OmitKeys, returnFalse, setupMoveUpEvents } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { undoBatch } from '../../util/UndoManager';
 import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { StyleProp } from '../StyleProvider';
 import "./ComparisonBox.scss";
-import { DocumentView } from './DocumentView';
+import { DocumentView, DocumentViewProps } from './DocumentView';
 import { FieldView, FieldViewProps } from './FieldView';
 import React = require("react");
 
@@ -71,6 +72,11 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
         delete this.dataDoc[fieldKey];
     }
 
+    docStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => {
+        if (property === StyleProp.PointerEvents) return "none";
+        return this.props.styleProvider?.(doc, props, property);
+    }
+
     render() {
         const clipWidth = NumCast(this.layoutDoc._clipWidth) + "%";
         const clearButton = (which: string) => {
@@ -84,6 +90,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
             const whichDoc = Cast(this.dataDoc[`compareBox-${which}`], Doc, null);
             return whichDoc ? <>
                 <DocumentView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
+                    isContentActive={returnFalse}
+                    isDocumentActive={returnFalse}
+                    styleProvider={this.docStyleProvider}
                     Document={whichDoc}
                     DataDoc={undefined}
                     pointerEvents={"none"} />
@@ -102,7 +111,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
         };
 
         return (
-            <div className={`comparisonBox${this.isContentActive() || SnappingManager.GetIsDragging() ? "-interactive" : ""}` /* change className to easily disable/enable pointer events in CSS */}>
+            <div className={`comparisonBox${this.props.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/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index bb259da3e..11fb5cdb3 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -84,6 +84,7 @@ export interface DocComponentView {
     reverseNativeScaling?: () => boolean; // DocumentView's setup screenToLocal based on the doc having a nativeWidth/Height.  However, some content views (e.g., FreeFormView w/ fitToBox set) may ignore the native dimensions so this flags the DocumentView to not do Nativre scaling.
     shrinkWrap?: () => void;  // requests a document to display all of its contents with no white space.  currently only implemented (needed?) for freeform views
     menuControls?: () => JSX.Element; // controls to display in the top menu bar when the document is selected.
+    isAnyChildContentActive?: () => boolean; // is any child content of the document active
     getKeyFrameEditing?: () => boolean; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown)
     setKeyFrameEditing?: (set: boolean) => void; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown)
     playFrom?: (time: number, endTime?: number) => void;
@@ -182,7 +183,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     private _dropDisposer?: DragManager.DragDropDisposer;
     private _holdDisposer?: InteractionUtils.MultiTouchEventDisposer;
     protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
-    _componentView: Opt<DocComponentView>; // needs to be accessed from DocumentView wrapper class
+    @observable _componentView: Opt<DocComponentView>; // needs to be accessed from DocumentView wrapper class
 
     private get topMost() { return this.props.renderDepth === 0 && !LightboxView.LightboxDoc; }
     public get displayName() { return "DocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive
@@ -778,8 +779,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     contentScaling = () => this.ContentScale;
     onClickFunc = () => this.onClickHandler;
     setHeight = (height: number) => this.layoutDoc._height = height;
-    setContentView = (view: { getAnchor?: () => Doc, forward?: () => boolean, back?: () => boolean }) => this._componentView = view;
-    isContentActive = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || this.props.isContentActive() ? true : false;
+    setContentView = action((view: { getAnchor?: () => Doc, forward?: () => boolean, back?: () => boolean }) => this._componentView = view);
+    isContentActive = (outsideReaction?: boolean) => {
+        return CurrentUserUtils.SelectedTool !== InkTool.None ||
+            this.props.Document.forceActive ||
+            this.props.isSelected(outsideReaction) ||
+            this._componentView?.isAnyChildContentActive?.() ||
+            this.props.isContentActive() ? true : false;
+    }
     @computed get contents() {
         TraceMobx();
         const audioView = !this.layoutDoc._showAudio ? (null) :
@@ -794,7 +801,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             </div>;
         return <div className="documentView-contentsView"
             style={{
-                pointerEvents: (this.props.contentPointerEvents as any) || (CurrentUserUtils.SelectedTool !== InkTool.None || SnappingManager.GetIsDragging() || this.isContentActive() ? "all" : "none"),
+                pointerEvents: (this.props.contentPointerEvents as any) || (this.isContentActive() ? "all" : "none"),
                 height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
             }}>
             <DocumentContentsView key={1} {...this.props}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index c4e74ebd2..b392ddb95 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -332,7 +332,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         return <div className="imageBox-annotationLayer" style={{ height: this.props.PanelHeight() }} ref={this._annotationLayer} />;
     }
     marqueeDown = (e: React.PointerEvent) => {
-        if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
+        if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
             setupMoveUpEvents(this, e, action(e => {
                 MarqueeAnnotator.clearAnnotations(this._savedAnnotations)
                 this._marqueeing = [e.clientX, e.clientY];
@@ -368,7 +368,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 ScreenToLocalTransform={this.screenToLocalTransform}
                 scaling={returnOne}
                 select={emptyFunction}
-                isContentActive={this.isContentActive}
                 whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                 removeDocument={this.removeDocument}
                 moveDocument={this.moveDocument}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 23236cf20..341fa5919 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -177,9 +177,9 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         </>;
         const searchTitle = `${!this._searching ? "Open" : "Close"} Search Bar`;
         const curPage = this.Document._curPage || 1;
-        return !this.isContentActive() ? (null) :
+        return !this.props.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.isContentActive() ? "flex" : "none" }}>
+                onPointerDown={e => e.stopPropagation()} style={{ display: this.props.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}
@@ -209,7 +209,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     {this._pageControls ? pageBtns : (null)}
                 </div>
                 <button className="pdfBox-sidebarBtn" title="Toggle Sidebar"
-                    style={{ display: !this.isContentActive() ? "none" : undefined }}
+                    style={{ display: !this.props.isContentActive() ? "none" : undefined }}
                     onPointerDown={this.sidebarBtnDown} >
                     <FontAwesomeIcon icon={"chevron-left"} size="sm" />
                 </button>
@@ -229,7 +229,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     }
 
     @computed get renderTitleBox() {
-        const classname = "pdfBox" + (this.isContentActive() ? "-interactive" : "");
+        const classname = "pdfBox" + (this.props.isContentActive() ? "-interactive" : "");
         return <div className={classname} >
             <div className="pdfBox-title-outer">
                 <strong className="pdfBox-title" >{this.props.Document.title}</strong>
@@ -268,7 +268,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     dataDoc={this.dataDoc}
                     pdf={this._pdf!}
                     url={this.pdfUrl!.url.pathname}
-                    isContentActive={this.isContentActive}
+                    isContentActive={this.props.isContentActive}
                     anchorMenuClick={this.anchorMenuClick}
                     loaded={!Doc.NativeAspect(this.dataDoc) ? this.loaded : undefined}
                     setPdfViewer={this.setPdfViewer}
@@ -291,7 +291,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 sidebarAddDocument={this.sidebarAddDocument}
                 moveDocument={this.moveDocument}
                 removeDocument={this.removeDocument}
-                isContentActive={this.isContentActive}
             />
             {this.settingsPanel()}
         </div>;
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index d4df30b48..484dec7e2 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -307,7 +307,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         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.isContentActive() ? "all" : "none" }}>
+            <div className="container" key="container" style={{ mixBlendMode: "multiply", pointerEvents: this.props.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" }}
@@ -321,7 +321,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         Not supported.
                     </video>
                     {!this.audiopath || this.audiopath === field.url.href ? (null) :
-                        <audio ref={this.setAudioRef} className={`audiobox-control${this.isContentActive() ? "-interactive" : ""}`}>
+                        <audio ref={this.setAudioRef} className={`audiobox-control${this.props.isContentActive() ? "-interactive" : ""}`}>
                             <source src={this.audiopath} type="audio/mpeg" />
                         Not supported.
                     </audio>}
@@ -378,30 +378,30 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     private get uIButtons() {
         const curTime = (this.layoutDoc._currentTimecode || 0);
         const nonNativeControls = [
-            <Tooltip title={<div className="dash-tooltip">{"playback"}</div>} placement="bottom">
-                <div className="videoBox-play" key="play" onPointerDown={this.onPlayDown} >
+            <Tooltip title={<div className="dash-tooltip">{"playback"}</div>} key="play" placement="bottom">
+                <div className="videoBox-play" onPointerDown={this.onPlayDown} >
                     <FontAwesomeIcon icon={this._playing ? "pause" : "play"} size="lg" />
                 </div>
             </Tooltip>,
-            <Tooltip title={<div className="dash-tooltip">{"timecode"}</div>} placement="bottom">
+            <Tooltip title={<div className="dash-tooltip">{"timecode"}</div>} key="time" placement="bottom">
                 <div className="videoBox-time" onPointerDown={this.onResetDown} >
                     <span>{formatTime(curTime)}</span>
                     <span style={{ fontSize: 8 }}>{" " + Math.floor((curTime - Math.trunc(curTime)) * 100).toString().padStart(2, "0")}</span>
                 </div>
             </Tooltip>,
-            <Tooltip title={<div className="dash-tooltip">{"view full screen"}</div>} placement="bottom">
+            <Tooltip title={<div className="dash-tooltip">{"view full screen"}</div>} key="full" placement="bottom">
                 <div className="videoBox-full" onPointerDown={this.FullScreen}>
                     <FontAwesomeIcon icon="expand" size="lg" />
                 </div>
             </Tooltip>];
         return <div className="videoBox-ui">
             {[...(VideoBox._nativeControls ? [] : nonNativeControls),
-            <Tooltip title={<div className="dash-tooltip">{"snapshot current frame"}</div>} placement="bottom">
+            <Tooltip title={<div className="dash-tooltip">{"snapshot current frame"}</div>} key="snap" placement="bottom">
                 <div className="videoBox-snapshot" onPointerDown={this.onSnapshotDown} >
                     <FontAwesomeIcon icon="camera" size="lg" />
                 </div>
             </Tooltip>,
-            <Tooltip title={<div className="dash-tooltip">{"show annotation timeline"}</div>} placement="bottom">
+            <Tooltip title={<div className="dash-tooltip">{"show annotation timeline"}</div>} key="timeline" placement="bottom">
                 <div className="videoBox-timelineButton" onPointerDown={this.onTimelineHdlDown}>
                     <FontAwesomeIcon icon="eye" size="lg" />
                 </div>
@@ -429,7 +429,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         setupMoveUpEvents(this, e,
             action((e: PointerEvent) => {
                 this._clicking = false;
-                if (this.isContentActive()) {
+                if (this.props.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));
                 }
@@ -438,7 +438,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             () => {
                 this.layoutDoc._timelineHeightPercent = this.heightPercent !== 100 ? 100 : VideoBox.heightPercent;
                 setTimeout(action(() => this._clicking = false), 500);
-            }, this.isContentActive(), this.isContentActive());
+            }, this.props.isContentActive(), this.props.isContentActive());
     });
 
     onResetDown = (e: React.PointerEvent) => {
@@ -529,12 +529,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 playFrom={this.playFrom}
                 setTime={this.setAnchorTime}
                 playing={this.playing}
+                isAnyChildContentActive={this.isAnyChildContentActive}
                 whenChildContentsActiveChanged={this.timelineWhenChildContentsActiveChanged}
                 removeDocument={this.removeDocument}
                 ScreenToLocalTransform={this.timelineScreenToLocal}
                 Play={this.Play}
                 Pause={this.Pause}
-                isContentActive={this.isContentActive}
                 playLink={this.playLink}
                 PanelHeight={this.timelineHeight}
             />
@@ -546,7 +546,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     }
 
     marqueeDown = (e: React.PointerEvent) => {
-        if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
+        if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
             setupMoveUpEvents(this, e, action(e => {
                 MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
                 this._marqueeing = [e.clientX, e.clientY];
@@ -570,7 +570,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     }
     marqueeFitScaling = () => (this.props.scaling?.() || 1) * this.heightPercent / 100;
     marqueeOffset = () => [this.panelWidth() / 2 * (1 - this.heightPercent / 100) / (this.heightPercent / 100), 0];
-    timelineDocFilter = () => ["_timelineLabel:true:x"];
+    timelineDocFilter = () => [`_timelineLabel:true,${Utils.noRecursionHack}:x`];
     render() {
         const borderRad = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BorderRounding);
         const borderRadius = borderRad?.includes("px") ? `${Number(borderRad.split("px")[0]) / this.scaling()}px` : borderRad;
@@ -592,7 +592,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         ScreenToLocalTransform={this.screenToLocalTransform}
                         docFilters={this.timelineDocFilter}
                         select={emptyFunction}
-                        isContentActive={this.isContentActive}
                         scaling={returnOne}
                         whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                         removeDocument={this.removeDocument}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index ae6b90e41..b484ce302 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -401,7 +401,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     @action
     onMarqueeDown = (e: React.PointerEvent) => {
-        if (!e.altKey && e.button === 0 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
+        if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
             setupMoveUpEvents(this, e, action(e => {
                 MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
                 this._marqueeing = [e.clientX, e.clientY];
@@ -484,7 +484,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             NumCast(this.layoutDoc.nativeWidth)
 
     @computed get content() {
-        return <div className={"webBox-cont" + (!this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.isContentActive() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting ? "-interactive" : "")}
+        return <div className={"webBox-cont" + (!this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.props.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>;
@@ -529,7 +529,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 docFilters={docFilters || this.props.docFilters}
                 dontRenderDocuments={docFilters ? false : true}
                 select={emptyFunction}
-                isContentActive={returnFalse}
                 ContentScaling={returnOne}
                 bringToFront={emptyFunction}
                 whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
@@ -539,7 +538,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 childPointerEvents={true}
                 pointerEvents={CurrentUserUtils.SelectedTool !== InkTool.None || this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none"} />;
         return (
-            <div className="webBox" ref={this._mainCont} style={{ pointerEvents: this.isContentActive() ? "all" : this.isContentActive() || SnappingManager.GetIsDragging() ? undefined : "none" }} >
+            <div className="webBox" ref={this._mainCont} style={{ pointerEvents: this.props.isContentActive() ? "all" : this.props.isContentActive() || SnappingManager.GetIsDragging() ? undefined : "none" }} >
                 <div className={`webBox-container`} style={{ pointerEvents }} onContextMenu={this.specificContextMenu}>
                     <base target="_blank" />
                     <div className={"webBox-outerContent"} ref={this._outerRef}
@@ -559,7 +558,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                                 {renderAnnotations(this.transparentFilter)}
                             </div>
                             {renderAnnotations(this.opaqueFilter)}
-                            {renderAnnotations()}
+                            {SnappingManager.GetIsDragging() ? (null) : renderAnnotations()}
                             {this.annotationLayer}
                         </div>
                     </div>
@@ -588,10 +587,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     sidebarAddDocument={this.sidebarAddDocument}
                     moveDocument={this.moveDocument}
                     removeDocument={this.removeDocument}
-                    isContentActive={this.isContentActive}
                 />
                 <button className="webBox-overlayButton-sidebar" key="sidebar" title="Toggle Sidebar"
-                    style={{ display: !this.isContentActive() ? "none" : undefined }}
+                    style={{ display: !this.props.isContentActive() ? "none" : undefined }}
                     onPointerDown={this.sidebarBtnDown} >
                     <FontAwesomeIcon style={{ color: "white" }} icon={"chevron-left"} size="sm" />
                 </button>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index d1027dfd7..4b1d76d00 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1211,7 +1211,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         if ((e.nativeEvent as any).formattedHandled) {
             console.log("handled");
         }
-        if (!(e.nativeEvent as any).formattedHandled && this.isContentActive(true)) {
+        if (!(e.nativeEvent as any).formattedHandled && this.props.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))));
@@ -1481,7 +1481,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.isContentActive()) ? (null) : <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown}
+        return (!annotated && !this.props.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" : ""))
@@ -1504,7 +1504,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     sidebarAddDocument={this.sidebarAddDocument}
                     moveDocument={this.moveDocument}
                     removeDocument={this.removeDocument}
-                    isContentActive={this.isContentActive}
                 /> :
                 <ComponentTag
                     {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
@@ -1517,7 +1516,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     scaleField={this.SidebarKey + "-scale"}
                     isAnnotationOverlay={false}
                     select={emptyFunction}
-                    isContentActive={this.isContentActive}
                     scaling={this.sidebarContentScaling}
                     whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                     removeDocument={this.sidebarRemDocument}
@@ -1539,7 +1537,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     render() {
         TraceMobx();
         const selected = this.props.isSelected();
-        const active = this.isContentActive();
+        const active = this.props.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);
@@ -1551,7 +1549,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         const selPaddingClass = selected && !this.layoutDoc._singleLine && margins >= 10 ? "-selected" : "";
         return (
             <div className="formattedTextBox-cont"
-                onWheel={e => this.isContentActive() && e.stopPropagation()}
+                onWheel={e => this.props.isContentActive() && e.stopPropagation()}
                 style={{
                     transform: this.props.dontScale ? undefined : `scale(${scale})`,
                     transformOrigin: this.props.dontScale ? undefined : "top left",
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 75e3f81fb..42bec38da 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -69,7 +69,6 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
         this._disposer = reaction(() => SelectionManager.Views(),
             selected => {
                 this._showLinkPopup = false;
-                console.log("unmount");
                 AnchorMenu.Instance.fadeOut(true)
             });
     }
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 734d9127c..bc35d2126 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -512,7 +512,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
         const renderAnnotations = (docFilters?: () => string[]) =>
             <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
                 isAnnotationOverlay={true}
-                isContentActive={returnFalse}
                 fieldKey={this.props.fieldKey + "-annotations"}
                 setPreviewCursor={this.setPreviewCursor}
                 PanelHeight={this.panelHeight}
@@ -543,7 +542,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                     transform: `scale(${this._zoomed})`
                 }}>
                 {renderAnnotations(this.opaqueFilter)}
-                {renderAnnotations()}
+                {SnappingManager.GetIsDragging() ? (null) : renderAnnotations()}
             </div>
         </div>;
     }
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 17f41fac8..b09ff93d0 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1092,6 +1092,9 @@ export namespace Doc {
             const isTransparent = (color: string) => color !== "" && (Color(color).alpha() !== 1);
             return isTransparent(StrCast(doc[key]));
         }
+        if (typeof value === "string") {
+            value = value.replace(`,${Utils.noRecursionHack}`, "");
+        }
         const fieldVal = doc[key];
         if (Cast(fieldVal, listSpec("string"), []).length) {
             const vals = Cast(fieldVal, listSpec("string"), []);
-- 
cgit v1.2.3-70-g09d2


From 9d177851ecaaea1a89ac9b7de1cec16368603eaa Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 9 Sep 2021 22:49:13 -0400
Subject: added SelectionManager.Docs() to avoid having to dereference props to
 get at the seelcted Doc.  this was causing a cycle in menu items when
 selected.  fixed sizing of filterBox.  enabled showing titles for VID,COL,and
 IMG in addition to RTF.

---
 src/client/util/CurrentUserUtils.ts                |  2 +-
 src/client/util/HypothesisUtils.ts                 |  2 +-
 src/client/util/SelectionManager.ts                | 12 ++--
 src/client/views/GlobalKeyHandler.ts               |  4 +-
 src/client/views/PropertiesView.tsx                |  2 +-
 src/client/views/StyleProvider.tsx                 |  2 +-
 src/client/views/collections/CollectionMenu.tsx    | 21 +++----
 src/client/views/collections/CollectionSubView.tsx |  8 +--
 .../collectionLinear/CollectionLinearView.tsx      | 19 +++---
 src/client/views/nodes/DocumentView.tsx            |  5 +-
 src/client/views/nodes/FilterBox.tsx               | 11 ++--
 src/client/views/nodes/button/FontIconBox.tsx      | 68 ++++++++++------------
 .../views/nodes/formattedText/RichTextMenu.tsx     | 20 +++----
 13 files changed, 81 insertions(+), 95 deletions(-)

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

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 8435825c9..60bb375c8 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1616,7 +1616,7 @@ Scripting.addGlobal(function dynamicOffScreenDocs(dashboard: Doc) {
     return [];
 });
 Scripting.addGlobal(function selectedDocumentType(docType?: DocumentType, colType?: CollectionViewType, checkParent?: boolean) {
-    let selected = SelectionManager.Views().length ? SelectionManager.Views()[0].rootDoc : undefined;
+    let selected = SelectionManager.Docs().length ? SelectionManager.Docs()[0] : undefined;
     if (selected && checkParent) {
         const parentDoc: Doc = Cast(selected.context, Doc, null);
         selected = parentDoc;
diff --git a/src/client/util/HypothesisUtils.ts b/src/client/util/HypothesisUtils.ts
index 635673025..e910a9118 100644
--- a/src/client/util/HypothesisUtils.ts
+++ b/src/client/util/HypothesisUtils.ts
@@ -29,7 +29,7 @@ export namespace Hypothesis {
      * Search for a WebDocument whose url field matches the given uri, return undefined if not found
      */
     export const findWebDoc = async (uri: string) => {
-        const currentDoc = SelectionManager.Views().length && SelectionManager.Views()[0].props.Document;
+        const currentDoc = SelectionManager.Docs().lastElement();
         if (currentDoc && Cast(currentDoc.data, WebField)?.url.href === uri) return currentDoc; // always check first whether the currently selected doc is the annotation's source, only use Search otherwise
 
         const results: Doc[] = [];
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 0cfaebbf2..bac13373c 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -11,7 +11,7 @@ export namespace SelectionManager {
     class Manager {
 
         @observable IsDragging: boolean = false;
-        SelectedViews: ObservableMap<DocumentView, boolean> = new ObservableMap();
+        SelectedViews: ObservableMap<DocumentView, Doc> = new ObservableMap();
         @observable SelectedSchemaDocument: Doc | undefined;
         @observable SelectedSchemaCollection: CollectionSchemaView | undefined;
 
@@ -28,19 +28,18 @@ export namespace SelectionManager {
                     this.DeselectAll();
                 }
 
-                manager.SelectedViews.set(docView, true);
+                manager.SelectedViews.set(docView, docView.rootDoc);
                 docView.props.whenChildContentsActiveChanged(true);
             } else if (!ctrlPressed && Array.from(manager.SelectedViews.entries()).length > 1) {
                 Array.from(manager.SelectedViews.keys()).map(dv => dv !== docView && dv.props.whenChildContentsActiveChanged(false));
                 manager.SelectedSchemaDocument = undefined;
                 manager.SelectedSchemaCollection = undefined;
                 manager.SelectedViews.clear();
-                manager.SelectedViews.set(docView, true);
+                manager.SelectedViews.set(docView, docView.rootDoc);
             }
         }
         @action
         DeselectView(docView: DocumentView): void {
-
             if (manager.SelectedViews.get(docView)) {
                 manager.SelectedViews.delete(docView);
                 docView.props.whenChildContentsActiveChanged(false);
@@ -92,7 +91,7 @@ export namespace SelectionManager {
     }
 
     export function Views(): Array<DocumentView> {
-        return Array.from(manager.SelectedViews.keys()).filter(dv => dv.props.Document._viewType !== CollectionViewType.Docking);
+        return Array.from(manager.SelectedViews.keys()).filter(dv => manager.SelectedViews.get(dv)?._viewType !== CollectionViewType.Docking);
     }
     export function SelectedSchemaDoc(): Doc | undefined {
         return manager.SelectedSchemaDocument;
@@ -100,4 +99,7 @@ export namespace SelectionManager {
     export function SelectedSchemaCollection(): CollectionSchemaView | undefined {
         return manager.SelectedSchemaCollection;
     }
+    export function Docs(): Doc[] {
+        return Array.from(manager.SelectedViews.values()).filter(doc => doc?._viewType !== CollectionViewType.Docking);
+    }
 }
\ No newline at end of file
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 0127d3080..f66c9c788 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -229,8 +229,8 @@ export class KeyManager {
                 }
                 break;
             case "o":
-                const target = SelectionManager.Views()[0];
-                target && CollectionDockingView.OpenFullScreen(target.props.Document);
+                const target = SelectionManager.Docs().lastElement();
+                target && CollectionDockingView.OpenFullScreen(target);
                 break;
             case "r":
                 preventDefault = false;
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 09e12443b..ab9022a84 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -366,7 +366,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return <Tooltip title={<div className="dash-tooltip">{"Show more permissions"}</div>}>
             <div className="expansion-button" onPointerDown={() => {
                 if (this.selectedDocumentView || this.selectedDoc) {
-                    SharingManager.Instance.open(this.selectedDocumentView?.props.Document === this.selectedDocumentView ? this.selectedDocumentView : undefined, this.selectedDoc);
+                    SharingManager.Instance.open(this.selectedDocumentView?.props.Document === this.selectedDoc ? this.selectedDocumentView : undefined, this.selectedDoc);
                 }
             }}>
                 <FontAwesomeIcon className="expansion-button-icon" icon="ellipsis-h" color="black" size="sm" />
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 3413179ed..3c88a4830 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -96,7 +96,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
         case StyleProp.ShowTitle: return (doc && !doc.presentationTargetDoc &&
             StrCast(doc._showTitle,
                 props?.showTitle?.() ||
-                (!Doc.IsSystem(doc) && doc.type === DocumentType.RTF ?
+                (!Doc.IsSystem(doc) && [DocumentType.COL, DocumentType.RTF, DocumentType.IMG, DocumentType.VID].includes(doc.type as any) ?
                     (doc.author === Doc.CurrentUserEmail ? StrCast(Doc.UserDoc().showTitle) :
                         "author;creationDate") : "")) || "");
         case StyleProp.Color:
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index ce5846502..aefa1ec3d 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -62,7 +62,7 @@ export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> {
 
     componentDidMount() {
         reaction(() => SelectionManager.Views().length && SelectionManager.Views()[0],
-            (doc) => doc && this.SetSelection(doc));
+            view => view && this.SetSelection(view));
     }
 
     @action
@@ -441,10 +441,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         </div>);
     }
 
-    @computed get selectedDocumentView() {
-        return SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined;
-    }
-    @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
+    @computed get selectedDocumentView() { return SelectionManager.Views().lastElement(); }
+    @computed get selectedDoc() { return SelectionManager.Docs().lastElement(); }
     @computed get notACollection() {
         if (this.selectedDoc) {
             const layoutField = Doc.LayoutField(this.selectedDoc);
@@ -552,8 +550,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
     @undoBatch
     onAliasButtonMoved = (e: PointerEvent) => {
         const contentDiv = this.selectedDocumentView?.ContentDiv;
-        if (contentDiv) {
-            const dragData = new DragManager.DocumentDragData([this.selectedDocumentView!.props.Document]);
+        if (contentDiv && this.selectedDoc) {
+            const dragData = new DragManager.DocumentDragData([this.selectedDoc]);
             const offset = [e.clientX - contentDiv.getBoundingClientRect().x, e.clientY - contentDiv.getBoundingClientRect().y];
             dragData.defaultDropAction = "alias";
             dragData.canEmbed = true;
@@ -648,11 +646,9 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
         return this.document[this.props.docView.LayoutFieldKey + (this.props.isOverlay ? "-annotations" : "")];
     }
     @computed get childDocs() { return DocListCast(this.dataField); }
-    @computed get selectedDocumentView() { return SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined; }
-    @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
-    @computed get isText() {
-        return this.selectedDoc?.type === DocumentType.RTF || (RichTextMenu.Instance?.view as any) ? true : false;
-    }
+    @computed get selectedDocumentView() { return SelectionManager.Views().lastElement(); }
+    @computed get selectedDoc() { return SelectionManager.Docs().lastElement(); }
+    @computed get isText() { return this.selectedDoc?.type === DocumentType.RTF || (RichTextMenu.Instance?.view as any) ? true : false; }
 
     @undoBatch
     @action
@@ -826,7 +822,6 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
 
             </div>;
     }
-    @observable viewType = this.selectedDoc?._viewType;
 
     render() {
         return !this.props.docView.layoutDoc ? (null) :
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index b70df93da..06d20f015 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -321,12 +321,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                                 }
                             });
                         } else {
-                            let srcUrl: string | undefined;
-                            let srcWeb: Doc | undefined;
-                            if (SelectionManager.Views().length) {
-                                srcWeb = SelectionManager.Views()[0].props.Document;
-                                srcUrl = (srcWeb.data as WebField).url?.href?.match(/http[s]?:\/\/[^/]*/)?.[0];
-                            }
+                            const srcWeb = SelectionManager.Docs().lastElement();
+                            const srcUrl = (srcWeb?.data as WebField).url?.href?.match(/http[s]?:\/\/[^/]*/)?.[0];
                             const reg = new RegExp(Utils.prepend(""), "g");
                             const modHtml = srcUrl ? html.replace(reg, srcUrl) : html;
                             const htmlDoc = Docs.Create.HtmlDocument(modHtml, { ...options, title: "-web page-", _width: 300, _height: 300 });
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index fae92e076..7fe95fef0 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -1,24 +1,24 @@
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Tooltip } from '@material-ui/core';
-import { action, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx';
+import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { Doc, HeightSym, WidthSym, Opt } from '../../../../fields/Doc';
+import { Doc, HeightSym, Opt, WidthSym } from '../../../../fields/Doc';
 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, returnEmptyDoclist, returnFalse, returnTrue, Utils } from '../../../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnTrue, Utils } from '../../../../Utils';
 import { DragManager } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
+import { Colors, Shadows } from '../../global/globalEnums';
 import { DocumentLinksButton } from '../../nodes/DocumentLinksButton';
 import { DocumentView } from '../../nodes/DocumentView';
 import { LinkDescriptionPopup } from '../../nodes/LinkDescriptionPopup';
 import { StyleProp } from '../../StyleProvider';
-import "./CollectionLinearView.scss";
 import { CollectionSubView } from '../CollectionSubView';
 import { CollectionViewType } from '../CollectionView';
-import { Colors, Shadows } from '../../global/globalEnums';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import "./CollectionLinearView.scss";
 
 
 type LinearDocument = makeInterface<[typeof documentSchema,]>;
@@ -115,9 +115,9 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
     }
 
 
-    getDisplayDoc(doc: Doc) {
+    getDisplayDoc = (doc: Doc) => {
         const nested = doc._viewType === CollectionViewType.Linear;
-        const hidden = doc.hidden === true;;
+        const hidden = doc.hidden === true;
 
         let dref: Opt<HTMLDivElement>;
         const docXf = () => this.getTransform(dref);
@@ -142,8 +142,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                 pinToPres={emptyFunction}
                 rootSelected={this.props.isSelected}
                 removeDocument={this.props.removeDocument}
-                // ScreenToLocalTransform={docXf} // bcz: Ugh -- this is what we want, but it breaks things when right-clicking on linear view item since docXf is not a constant value across invalidations
-                ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+                ScreenToLocalTransform={docXf}
                 PanelWidth={nested ? doc[WidthSym] : this.dimension}
                 PanelHeight={nested ? doc[HeightSym] : this.dimension}
                 renderDepth={this.props.renderDepth + 1}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 6f97cdbd8..8b19fb204 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -649,7 +649,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         if (e && this.rootDoc._hideContextMenu && Doc.UserDoc().noviceMode) {
             e.preventDefault();
             e.stopPropagation();
-            !this.props.isSelected(true) && SelectionManager.SelectView(this.props.DocumentView(), false);
+            //!this.props.isSelected(true) && SelectionManager.SelectView(this.props.DocumentView(), false);
         }
         // the touch onContextMenu is button 0, the pointer onContextMenu is button 2
         if (e) {
@@ -952,11 +952,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     hideOnLeave={true}
                     styleProvider={this.captionStyleProvider}
                     dontRegisterView={true}
+                    isContentActive={this.isContentActive}
                     onClick={this.onClickFunc}
                 />
             </div>;
         const targetDoc = (showTitle?.startsWith("_") ? this.layoutDoc : this.rootDoc);
-        const background = StrCast(SharingManager.Instance.users.find(users => users.user.email === this.dataDoc.author)?.sharingDoc.userColor, this.rootDoc.type === DocumentType.RTF ? StrCast(Doc.SharingDoc().userColor) : "rgba(0,0,0,0.4)");
+        const background = StrCast(SharingManager.Instance.users.find(users => users.user.email === this.dataDoc.author)?.sharingDoc.userColor, [DocumentType.RTF, DocumentType.COL].includes(this.rootDoc.type as any) ? StrCast(Doc.SharingDoc().userColor) : "rgba(0,0,0,0.4)");
         const titleView = !showTitle ? (null) :
             <div className={`documentView-titleWrapper${showTitleHover ? "-hover" : ""}`} key="title" style={{
                 position: this.headerMargin ? "relative" : "absolute",
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index 7ad03e055..e9f19bf9e 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -9,7 +9,7 @@ import { List } from "../../../fields/List";
 import { RichTextField } from "../../../fields/RichTextField";
 import { listSpec, makeInterface } from "../../../fields/Schema";
 import { ComputedField, ScriptField } from "../../../fields/ScriptField";
-import { Cast, StrCast } from "../../../fields/Types";
+import { Cast, StrCast, NumCast } from "../../../fields/Types";
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from "../../../Utils";
 import { Docs } from "../../documents/Documents";
 import { DocumentType } from "../../documents/DocumentTypes";
@@ -79,7 +79,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
     * @returns the relevant doc according to the value of FilterBox._filterScope i.e. either the Current Dashboard or the Current Collection
     */
     @computed static get targetDoc() {
-        return SelectionManager.Views().length ? SelectionManager.Views()[0].Document : CurrentUserUtils.ActiveDashboard;
+        return SelectionManager.Docs().length ? SelectionManager.Docs()[0] : CurrentUserUtils.ActiveDashboard;
     }
     @computed static get targetDocChildKey() {
         if (SelectionManager.Views().length) {
@@ -88,10 +88,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
         return "data";
     }
     @computed static get targetDocChildren() {
-        if (SelectionManager.Views().length) {
-            return DocListCast(FilterBox.targetDoc[FilterBox.targetDocChildKey]);
-        }
-        return DocListCast(CurrentUserUtils.ActiveDashboard.data);
+        return DocListCast(FilterBox.targetDoc?.[FilterBox.targetDocChildKey] || CurrentUserUtils.ActiveDashboard.data);
     }
 
     @observable _loaded = false;
@@ -347,7 +344,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
         );
     }
     setTreeHeight = (hgt: number) => {
-        this.layoutDoc._height = hgt + 140; // 50?  need to add all the border sizes together.
+        this.layoutDoc._height = NumCast(this.layoutDoc._autoHeightMargins) + 150; // need to add all the border sizes together.
     }
 
     /**
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index 4475cf347..df7c54f67 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -248,14 +248,15 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon
         let noneSelected: boolean = false;
 
         if (script === 'setView') {
-            const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined;
-            if (selected && StrCast(selected.Document.type) === DocumentType.COL) {
-                text = StrCast(selected.Document._viewType);
-            } else if (selected) {
-                dropdown = false;
-                text = StrCast(selected.Document.type);
-                if (text === DocumentType.RTF) text = "Text";
-                icon = Doc.toIcon(selected.Document);
+            const selected = SelectionManager.Docs().lastElement();
+            if (selected) {
+                if (StrCast(selected.type) === DocumentType.COL) {
+                    text = StrCast(selected._viewType);
+                } else {
+                    dropdown = false;
+                    text = selected.type === DocumentType.RTF ? "Text" : StrCast(selected.type);
+                    icon = Doc.toIcon(selected);
+                }
             } else {
                 dropdown = false;
                 icon = "globe-asia";
@@ -263,13 +264,8 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon
             }
             noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking];
         } else if (script === 'setFont') {
-            const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined;
-            if (selected && StrCast(selected.Document.type) === DocumentType.RTF) {
-                text = StrCast(selected.Document._fontFamily);
-            } else {
-                const fontFamily = StrCast(Doc.UserDoc()._fontFamily);
-                text = fontFamily;
-            }
+            const selected = SelectionManager.Docs().lastElement();
+            text = StrCast((selected?.type === DocumentType.RTF ? selected : Doc.UserDoc())._fontFamily);
             noviceList = ["Roboto", "Times New Roman", "Arial", "Georgia",
                 "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"];
         }
@@ -584,13 +580,13 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon
 
 // toggle: Set overlay status of selected document
 Scripting.addGlobal(function setView(view: string) {
-    const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined;
-    selected ? selected.Document._viewType = view : console.log("[FontIconBox.tsx] changeView failed");
+    const selected = SelectionManager.Docs().lastElement();
+    selected ? selected._viewType = view : console.log("[FontIconBox.tsx] changeView failed");
 });
 
 // toggle: Set overlay status of selected document
 Scripting.addGlobal(function setBackgroundColor(color?: string, checkResult?: boolean) {
-    const selected = SelectionManager.Views().length ? SelectionManager.Views()[0].rootDoc : undefined;
+    const selected = SelectionManager.Docs().lastElement();
     if (checkResult) {
         if (selected) {
             console.log("[Background] (selected): " + StrCast(selected._backgroundColor));
@@ -635,7 +631,7 @@ Scripting.addGlobal(function toggleOverlay(checkResult?: boolean) {
 
 // toggle: Set overlay status of selected document
 Scripting.addGlobal(function setFont(font: string, checkResult?: boolean) {
-    SelectionManager.Views().map(dv => dv.props.Document._fontFamily = font);
+    SelectionManager.Docs().map(doc => doc._fontFamily = font);
     const editorView = RichTextMenu.Instance.TextView?.EditorView;
     editorView?.state && RichTextMenu.Instance.setFontFamily(font, editorView);
     Doc.UserDoc()._fontFamily = font;
@@ -665,7 +661,7 @@ Scripting.addGlobal(function setAlignment(align: "left" | "right" | "center", ch
         if (active === align) return Colors.MEDIUM_BLUE;
         else return "transparent";
     }
-    SelectionManager.Views().map(dv => dv.props.Document.textAlign = align);
+    SelectionManager.Docs().map(doc => doc.textAlign = align);
     switch (align) {
         case "left":
             editorView?.state && RichTextMenu.Instance.alignLeft(editorView, editorView.dispatch);
@@ -703,13 +699,13 @@ Scripting.addGlobal(function setBulletList(mapStyle: "bullet" | "decimal", check
 
 // toggle: Set overlay status of selected document
 Scripting.addGlobal(function setFontColor(color?: string, checkResult?: boolean) {
-    const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined;
+    const selected = SelectionManager.Docs().lastElement();
     const editorView = RichTextMenu.Instance.TextView?.EditorView;
 
     if (checkResult) {
         if (selected) {
-            console.log("[Font color] (selected): " + StrCast(selected.rootDoc._fontColor));
-            return selected.rootDoc._fontColor;
+            console.log("[Font color] (selected): " + StrCast(selected._fontColor));
+            return selected._fontColor;
         } else {
             console.log("[Font color] (global): " + StrCast(Doc.UserDoc()._fontColor));
             return Doc.UserDoc()._fontColor;
@@ -717,7 +713,7 @@ Scripting.addGlobal(function setFontColor(color?: string, checkResult?: boolean)
     }
 
     if (selected) {
-        selected.rootDoc._fontColor = color;
+        selected._fontColor = color;
         if (color) {
             editorView?.state && RichTextMenu.Instance.setColor(color, editorView, editorView?.dispatch);
         }
@@ -727,18 +723,18 @@ Scripting.addGlobal(function setFontColor(color?: string, checkResult?: boolean)
 
 // toggle: Set overlay status of selected document
 Scripting.addGlobal(function setFontHighlight(color?: string, checkResult?: boolean) {
-    const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined;
+    const selected = SelectionManager.Docs().lastElement();
     const editorView = RichTextMenu.Instance.TextView?.EditorView;
 
     if (checkResult) {
         if (selected) {
-            return selected.Document._fontHighlight;
+            return selected._fontHighlight;
         } else {
             return Doc.UserDoc()._fontHighlight;
         }
     }
     if (selected) {
-        selected.rootDoc._fontColor = color;
+        selected._fontColor = color;
         if (color) {
             editorView?.state && RichTextMenu.Instance.setHighlight(color, editorView, editorView?.dispatch);
         }
@@ -769,7 +765,7 @@ Scripting.addGlobal(function toggleBold(checkResult?: boolean) {
         console.log("editorView");
         editorView?.state && RichTextMenu.Instance.toggleBold(editorView, true);
     }
-    SelectionManager.Views().filter(i => StrCast(i.rootDoc.type) === DocumentType.RTF).map(dv => dv.props.Document.bold = !dv.props.Document.bold);
+    SelectionManager.Docs().filter(doc => StrCast(doc.type) === DocumentType.RTF).map(doc => doc.bold = !doc.bold);
     Doc.UserDoc().bold = !Doc.UserDoc().bold;
     return Doc.UserDoc().bold;
 });
@@ -784,7 +780,7 @@ Scripting.addGlobal(function toggleUnderline(checkResult?: boolean) {
         console.log("editorView");
         editorView?.state && RichTextMenu.Instance.toggleUnderline(editorView, true);
     }
-    SelectionManager.Views().filter(i => StrCast(i.rootDoc.type) === DocumentType.RTF).map(dv => dv.props.Document.underline = !dv.props.Document.underline);
+    SelectionManager.Docs().filter(doc => StrCast(doc.type) === DocumentType.RTF).map(doc => doc.underline = !doc.underline);
     Doc.UserDoc().underline = !Doc.UserDoc().underline;
     return Doc.UserDoc().underline;
 });
@@ -799,7 +795,7 @@ Scripting.addGlobal(function toggleItalic(checkResult?: boolean) {
         console.log("editorView");
         editorView?.state && RichTextMenu.Instance.toggleItalic(editorView, true);
     }
-    SelectionManager.Views().filter(i => StrCast(i.rootDoc.type) === DocumentType.RTF).map(dv => dv.props.Document.italic = !dv.props.Document.italic);
+    SelectionManager.Docs().filter(doc => StrCast(doc.type) === DocumentType.RTF).map(doc => doc.italic = !doc.italic);
     Doc.UserDoc().italic = !Doc.UserDoc().italic;
     return Doc.UserDoc().italic;
 });
@@ -841,7 +837,7 @@ Scripting.addGlobal(function setActiveInkTool(tool: string, checkResult?: boolea
 
 Scripting.addGlobal(function setStrokeWidth(width: number, checkResult?: boolean) {
     if (checkResult) {
-        const selected = SelectionManager.Views().length ? SelectionManager.Views()[0].rootDoc : undefined;
+        const selected = SelectionManager.Docs().lastElement();
         if (selected && selected.type === DocumentType.INK) {
             return Number(selected.strokeWidth);
         } else {
@@ -850,13 +846,13 @@ Scripting.addGlobal(function setStrokeWidth(width: number, checkResult?: boolean
         }
     }
     Doc.UserDoc().activeInkWidth = width;
-    SelectionManager.Views().filter(i => StrCast(i.rootDoc.type) === DocumentType.INK).map(i => i.rootDoc.strokeWidth = Number(width));
+    SelectionManager.Docs().filter(doc => StrCast(doc.type) === DocumentType.INK).map(doc => doc.strokeWidth = Number(width));
 });
 
 // toggle: Set overlay status of selected document
 Scripting.addGlobal(function setStrokeColor(color?: string, checkResult?: boolean) {
     if (checkResult) {
-        const selected = SelectionManager.Views().length ? SelectionManager.Views()[0].rootDoc : undefined;
+        const selected = SelectionManager.Docs().lastElement();
         if (selected && selected.type === DocumentType.INK) {
             return selected.color;
         } else {
@@ -865,7 +861,7 @@ Scripting.addGlobal(function setStrokeColor(color?: string, checkResult?: boolea
         }
     }
     SetActiveInkColor(StrCast(color));
-    SelectionManager.Views().filter(i => StrCast(i.rootDoc.type) === DocumentType.INK).map(i => i.rootDoc.color = String(color));
+    SelectionManager.Docs().filter(doc => StrCast(doc.type) === DocumentType.INK).map(doc => doc.color = String(color));
 });
 
 
@@ -873,7 +869,7 @@ Scripting.addGlobal(function setStrokeColor(color?: string, checkResult?: boolea
  *      webSetURL
  **/
 Scripting.addGlobal(function webSetURL(url: string, checkResult?: boolean) {
-    const selected = SelectionManager.Views().length ? SelectionManager.Views()[0].rootDoc : undefined;
+    const selected = SelectionManager.Docs().lastElement();
     console.log("URL: ", url);
     if (checkResult && selected && selected.type === DocumentType.WEB) {
         return Cast(selected.data, WebField, null).url;
@@ -888,7 +884,7 @@ Scripting.addGlobal(function webSetURL(url: string, checkResult?: boolean) {
  *      toggleSchemaPreview
  **/
 Scripting.addGlobal(function toggleSchemaPreview(checkResult?: boolean) {
-    const selected = SelectionManager.Views().length ? SelectionManager.Views()[0].rootDoc : undefined;
+    const selected = SelectionManager.Docs().lastElement();
     console.log(selected && selected.title);
     if (checkResult && selected) {
         const result: boolean = NumCast(selected.schemaPreviewWidth) > 0;
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 3d9d9543d..3919fbf94 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -279,33 +279,33 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
         });
     }
 
-    toggleBold = (view: EditorView, forceBool?:boolean) => {
-        const mark = view.state.schema.mark(view.state.schema.marks.strong, {strong: forceBool});
+    toggleBold = (view: EditorView, forceBool?: boolean) => {
+        const mark = view.state.schema.mark(view.state.schema.marks.strong, { strong: forceBool });
         this.setMark(mark, view.state, view.dispatch, false);
         view.focus();
     }
 
-    toggleUnderline = (view: EditorView, forceBool?:boolean) => {
-        const mark = view.state.schema.mark(view.state.schema.marks.underline, {underline: forceBool});
+    toggleUnderline = (view: EditorView, forceBool?: boolean) => {
+        const mark = view.state.schema.mark(view.state.schema.marks.underline, { underline: forceBool });
         this.setMark(mark, view.state, view.dispatch, false);
         view.focus();
     }
 
-    toggleItalic = (view: EditorView, forceBool?:boolean) => {
-        const mark = view.state.schema.mark(view.state.schema.marks.em, {em: forceBool});
+    toggleItalic = (view: EditorView, forceBool?: boolean) => {
+        const mark = view.state.schema.mark(view.state.schema.marks.em, { em: forceBool });
         this.setMark(mark, view.state, view.dispatch, false);
         view.focus();
     }
 
 
-    setFontSize = (size:number, view: EditorView) => {
+    setFontSize = (size: number, view: EditorView) => {
         const fmark = view.state.schema.marks.pFontSize.create({ fontSize: size });
         this.setMark(fmark, view.state, (tx: any) => view.dispatch(tx.addStoredMark(fmark)), true);
         view.focus();
         this.updateMenu(view, undefined, this.props);
     }
 
-    setFontFamily = (family:string, view: EditorView) => {
+    setFontFamily = (family: string, view: EditorView) => {
         const fmark = view.state.schema.marks.pFontFamily.create({ family: family });
         this.setMark(fmark, view.state, (tx: any) => view.dispatch(tx.addStoredMark(fmark)), true);
         view.focus();
@@ -516,7 +516,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
     get TextView() { return (this.view as any)?.TextView as FormattedTextBox; }
     get TextViewFieldKey() { return this.TextView?.props.fieldKey; }
 
-    
+
 
     @action setActiveHighlight(color: string) { this.activeHighlightColor = color; }
 
@@ -566,7 +566,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps>   {
                         if (linkDoc instanceof Doc) {
                             const anchor1 = await Cast(linkDoc.anchor1, Doc);
                             const anchor2 = await Cast(linkDoc.anchor2, Doc);
-                            const currentDoc = SelectionManager.Views().length && SelectionManager.Views()[0].props.Document;
+                            const currentDoc = SelectionManager.Docs().lastElement();
                             if (currentDoc && anchor1 && anchor2) {
                                 if (Doc.AreProtosEqual(currentDoc, anchor1)) {
                                     return StrCast(anchor2.title);
-- 
cgit v1.2.3-70-g09d2

