From 75194d8218e1747d177ec018e3cf025b8d8906bc Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 12 Mar 2021 11:48:54 -0500
Subject: changed setDocFilter to not take undefined as a modfied & added
 toggle param.  added single click on marquee annotator to create an
 annotation.  extended PDF sidebar to have filter buttons.

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

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

diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 03210d768..1d851e775 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -433,7 +433,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             this.onCheckedClick?.script.run({
                 this: this.doc.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.doc,
                 heading: this.props.containingCollection.title,
-                checked: this.doc.treeViewChecked === "check" ? "x" : this.doc.treeViewChecked === "x" ? undefined : "check",
+                checked: this.doc.treeViewChecked === "check" ? "x" : this.doc.treeViewChecked === "x" ? "remove" : "check",
                 containingTreeView: this.props.treeView.props.Document,
             }, console.log);
         } else {
-- 
cgit v1.2.3-70-g09d2


From 2a17392bd461bfdc669961c5bf8892b7cb6958d6 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 12 Mar 2021 17:49:35 -0500
Subject: trying to make treeViews more efficient by making fewer calls to Get
 document fields getter.

---
 src/client/apis/youtube/YoutubeBox.tsx             |  3 +-
 src/client/documents/Documents.ts                  |  7 ++--
 src/client/util/CurrentUserUtils.ts                |  6 ++-
 src/client/views/DocComponent.tsx                  |  5 ++-
 src/client/views/GestureOverlay.tsx                |  2 +-
 src/client/views/GlobalKeyHandler.ts               |  4 +-
 src/client/views/InkingStroke.tsx                  |  9 +++--
 src/client/views/StyleProvider.tsx                 |  2 +-
 .../views/collections/CollectionDockingView.tsx    |  2 +-
 src/client/views/collections/CollectionMenu.tsx    |  6 +--
 .../views/collections/CollectionTreeView.tsx       |  5 ++-
 src/client/views/collections/CollectionView.tsx    | 16 ++++----
 src/client/views/collections/TreeView.tsx          | 45 ++++++++++------------
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 13 ++++---
 .../collections/collectionFreeForm/MarqueeView.tsx |  2 +-
 src/client/views/nodes/ColorBox.tsx                |  3 +-
 src/client/views/nodes/DocumentLinksButton.tsx     |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  6 +--
 src/client/views/nodes/PresBox.tsx                 |  2 +-
 src/client/views/nodes/ScreenshotBox.tsx           |  3 +-
 src/client/views/nodes/VideoBox.tsx                |  5 ++-
 src/client/views/nodes/WebBox.tsx                  |  3 +-
 .../views/nodes/formattedText/DashDocView.tsx      |  4 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  4 +-
 src/client/views/pdf/Annotation.tsx                |  4 +-
 src/client/views/pdf/PDFViewer.tsx                 |  3 +-
 src/client/views/webcam/DashWebRTCVideo.tsx        |  3 +-
 src/fields/Doc.ts                                  |  3 --
 src/mobile/MobileInterface.tsx                     |  6 +--
 29 files changed, 96 insertions(+), 82 deletions(-)

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

diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index 2a1f55710..c5ff2db68 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -11,6 +11,7 @@ import "../../views/nodes/WebBox.scss";
 import "./YoutubeBox.scss";
 import React = require("react");
 import { InkTool } from '../../../fields/InkField';
+import { CurrentUserUtils } from '../../util/CurrentUserUtils';
 
 interface VideoTemplate {
     thumbnailUrl: string;
@@ -350,7 +351,7 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
 
         const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
 
-        const classname = "webBox-cont" + (this.props.isSelected() && Doc.GetSelectedTool() === InkTool.None && !DocumentDecorations.Instance.Interacting ? "-interactive" : "");
+        const classname = "webBox-cont" + (this.props.isSelected() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? "-interactive" : "");
         return (
             <>
                 <div className={classname}  >
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 2941522c9..e8ecd8362 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -59,6 +59,7 @@ import { DocumentType } from "./DocumentTypes";
 import { EquationBox } from "../views/nodes/EquationBox";
 import { FunctionPlotBox } from "../views/nodes/FunctionPlotBox";
 import { script } from "googleapis/build/src/apis/script";
+import { CurrentUserUtils } from "../util/CurrentUserUtils";
 const path = require('path');
 
 const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", ""));
@@ -663,7 +664,7 @@ export namespace Docs {
             viewDoc["acl-Public"] = dataDoc["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Add;
             viewDoc["acl-Override"] = dataDoc["acl-Override"] = "None";
 
-            !Doc.IsSystem(dataDoc) && ![DocumentType.PDFANNO, DocumentType.LINK, DocumentType.LINKANCHOR, DocumentType.TEXTANCHOR].includes(proto.type as any) &&
+            !Doc.IsSystem(dataDoc) && ![DocumentType.PDFANNO, DocumentType.KVP, DocumentType.LINK, DocumentType.LINKANCHOR, DocumentType.TEXTANCHOR].includes(proto.type as any) &&
                 !dataDoc.isFolder && !protoProps.annotationOn && Doc.AddDocToList(Cast(Doc.UserDoc().myFileOrphans, Doc, null), "data", dataDoc);
 
             return Doc.assign(viewDoc, delegateProps, true);
@@ -1153,7 +1154,7 @@ export namespace DocUtils {
             created = Docs.Create.AudioDocument((field).url.href, resolved);
             layout = AudioBox.LayoutString;
         } else if (field instanceof InkField) {
-            created = Docs.Create.InkDocument(ActiveInkColor(), Doc.GetSelectedTool(), ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), (field).inkData, resolved);
+            created = Docs.Create.InkDocument(ActiveInkColor(), CurrentUserUtils.SelectedTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), (field).inkData, resolved);
             layout = InkingStroke.LayoutString;
         } else if (field instanceof List && field[0] instanceof Doc) {
             created = Docs.Create.StackingDocument(DocListCast(field), resolved);
@@ -1415,4 +1416,4 @@ Scripting.addGlobal(function generateLinkTitle(self: Doc) {
     const anchor2title = self.anchor2 && self.anchor2 !== self ? Cast(self.anchor2, Doc, null).title : "<?>";
     const relation = self.linkRelationship || "to";
     return `${anchor1title} (${relation}) ${anchor2title}`;
-})
\ No newline at end of file
+});
\ No newline at end of file
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index ba1a32785..894f306c9 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1,4 +1,4 @@
-import { computed, observable, reaction } from "mobx";
+import { computed, observable, reaction, action } from "mobx";
 import * as rp from 'request-promise';
 import { DataSym, Doc, DocListCast, DocListCastAsync, AclReadonly } from "../../fields/Doc";
 import { Id } from "../../fields/FieldSymbols";
@@ -33,6 +33,8 @@ import { SearchUtil } from "./SearchUtil";
 import { SelectionManager } from "./SelectionManager";
 import { UndoManager } from "./UndoManager";
 import { SnappingManager } from "./SnappingManager";
+import { InkTool } from "../../fields/InkField";
+import { computedFn } from "mobx-utils";
 
 
 export let resolvedPorts: { server: number, socket: number };
@@ -1213,6 +1215,8 @@ export class CurrentUserUtils {
     public static get MyDashboards() { return Cast(Doc.UserDoc().myDashboards, Doc, null); }
     public static get EmptyPane() { return Cast(Doc.UserDoc().emptyPane, Doc, null); }
     public static get OverlayDocs() { return DocListCast((Doc.UserDoc().myOverlayDocs as Doc)?.data); }
+    public static set SelectedTool(tool: InkTool) { Doc.UserDoc().activeInkTool = tool; }
+    @computed public static get SelectedTool(): InkTool { return StrCast(Doc.UserDoc().activeInkTool, InkTool.None) as InkTool; }
 }
 
 Scripting.addGlobal(function openDragFactory(dragFactory: Doc) {
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 6480c6507..1d4b67deb 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -8,6 +8,7 @@ import { List } from '../../fields/List';
 import { DateField } from '../../fields/DateField';
 import { ScriptField } from '../../fields/ScriptField';
 import { GetEffectiveAcl, SharingPermissions, distributeAcls, denormalizeEmail } from '../../fields/util';
+import { CurrentUserUtils } from '../util/CurrentUserUtils';
 
 
 ///  DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView)
@@ -198,9 +199,9 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
         }
 
         whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive));
-        active = (outsideReaction?: boolean) => ((Doc.GetSelectedTool() === InkTool.None && !this.props.Document._) &&
+        active = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && !this.props.Document._) &&
             (this.props.rootSelected(outsideReaction) || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0 || BoolCast((this.layoutDoc as any).forceActive)) ? true : false)
-        annotationsActive = (outsideReaction?: boolean) => (Doc.GetSelectedTool() !== InkTool.None || (this.props.layerProvider?.(this.props.Document) === false && this.props.active()) ||
+        annotationsActive = (outsideReaction?: boolean) => (CurrentUserUtils.SelectedTool !== InkTool.None || (this.props.layerProvider?.(this.props.Document) === false && this.props.active()) ||
             (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
     }
     return Component;
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index b4051194f..093e01a19 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -491,7 +491,7 @@ export class GestureOverlay extends Touchable {
 
     @action
     onPointerDown = (e: React.PointerEvent) => {
-        if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || (Doc.GetSelectedTool() === InkTool.Highlighter || Doc.GetSelectedTool() === InkTool.Pen)) {
+        if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
             this._points.push({ X: e.clientX, Y: e.clientY });
             setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction);
         }
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 6e467efd7..f387546af 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -28,6 +28,7 @@ import { MainView } from "./MainView";
 import { DocumentLinksButton } from "./nodes/DocumentLinksButton";
 import { AnchorMenu } from "./pdf/AnchorMenu";
 import { SearchBox } from "./search/SearchBox";
+import { CurrentUserUtils } from "../util/CurrentUserUtils";
 
 const modifiers = ["control", "meta", "shift", "alt"];
 type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise<KeyControlInfo>;
@@ -115,8 +116,7 @@ export class KeyManager {
                 DocumentLinksButton.StartLink = undefined;
                 DocumentLinksButton.StartLinkView = undefined;
                 InkStrokeProperties.Instance && (InkStrokeProperties.Instance._controlBtn = false);
-
-                Doc.SetSelectedTool(InkTool.None);
+                CurrentUserUtils.SelectedTool = InkTool.None;
                 var doDeselect = true;
                 if (SnappingManager.GetIsDragging()) {
                     DragManager.AbortDrag();
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 462d78865..46586bf1b 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -17,6 +17,7 @@ import "./InkingStroke.scss";
 import { FieldView, FieldViewProps } from "./nodes/FieldView";
 import React = require("react");
 import { InkStrokeProperties } from "./InkStrokeProperties";
+import { CurrentUserUtils } from "../util/CurrentUserUtils";
 
 type InkDocument = makeInterface<[typeof documentSchema]>;
 const InkDocument = makeInterface(documentSchema);
@@ -242,7 +243,7 @@ export function ActiveDash(): string { return StrCast(ActiveInkPen()?.activeDash
 export function ActiveInkWidth(): string { return StrCast(ActiveInkPen()?.activeInkWidth, "1"); }
 export function ActiveInkBezierApprox(): string { return StrCast(ActiveInkPen()?.activeInkBezier); }
 Scripting.addGlobal(function activateBrush(pen: any, width: any, color: any, fill: any, arrowStart: any, arrowEnd: any, dash: any) {
-    Doc.SetSelectedTool(pen ? InkTool.Highlighter : InkTool.None);
+    CurrentUserUtils.SelectedTool = pen ? InkTool.Highlighter : InkTool.None;
     SetActiveInkWidth(width);
     SetActiveInkColor(color);
     SetActiveFillColor(fill);
@@ -250,9 +251,9 @@ Scripting.addGlobal(function activateBrush(pen: any, width: any, color: any, fil
     SetActiveArrowEnd(arrowEnd);
     SetActiveDash(dash);
 });
-Scripting.addGlobal(function activateEraser(pen: any) { return Doc.SetSelectedTool(pen ? InkTool.Eraser : InkTool.None); });
-Scripting.addGlobal(function activateStamp(pen: any) { return Doc.SetSelectedTool(pen ? InkTool.Stamp : InkTool.None); });
-Scripting.addGlobal(function deactivateInk() { return Doc.SetSelectedTool(InkTool.None); });
+Scripting.addGlobal(function activateEraser(pen: any) { return CurrentUserUtils.SelectedTool = pen ? InkTool.Eraser : InkTool.None; });
+Scripting.addGlobal(function activateStamp(pen: any) { return CurrentUserUtils.SelectedTool = pen ? InkTool.Stamp : InkTool.None; });
+Scripting.addGlobal(function deactivateInk() { return CurrentUserUtils.SelectedTool = InkTool.None; });
 Scripting.addGlobal(function setInkWidth(width: any) { return SetActiveInkWidth(width); });
 Scripting.addGlobal(function setInkColor(color: any) { return SetActiveInkColor(color); });
 Scripting.addGlobal(function setFillColor(fill: any) { return SetActiveFillColor(fill); });
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index e1337abf3..d9ab0d397 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -74,7 +74,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps |
         case StyleProp.DocContents: return undefined;
         case StyleProp.WidgetColor: return isAnnotated ? "lightBlue" : darkScheme() ? "lightgrey" : "dimgrey";
         case StyleProp.Opacity: return Cast(doc?._opacity, "number", Cast(doc?.opacity, "number", null));
-        case StyleProp.HideLinkButton: return isAnchor || props?.dontRegisterView || ((!selected || doc?.type == DocumentType.PDFANNO) && (doc?.isLinkButton || doc?.hideLinkButton));
+        case StyleProp.HideLinkButton: return isAnchor || props?.dontRegisterView || ((!selected || doc?.type === DocumentType.PDFANNO) && (doc?.isLinkButton || doc?.hideLinkButton));
         case StyleProp.ShowTitle: return doc && !doc.presentationTargetDoc && StrCast(doc._showTitle,
             !Doc.IsSystem(doc) && doc.type === DocumentType.RTF ?
                 (doc.author === Doc.CurrentUserEmail ? StrCast(Doc.UserDoc().showTitle) : "author;creationDate") : "") || "";
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 0c8e26e91..7d07439ce 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -337,7 +337,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
             }
         }
         if (!e.nativeEvent.cancelBubble && !InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE) &&
-            Doc.GetSelectedTool() !== InkTool.Highlighter && Doc.GetSelectedTool() !== InkTool.Pen) {
+            ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
             e.stopPropagation();
         }
     }
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 591b4161e..51a67ea7d 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -603,7 +603,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     @action clearKeepPrimitiveMode() { this._selectedPrimitive = this._shapePrims.length; }
     @action primCreated() {
         if (!this._keepPrimitiveMode) { //get out of ink mode after each stroke=
-            Doc.SetSelectedTool(InkTool.None);
+            CurrentUserUtils.SelectedTool = InkTool.None;
             this._selectedPrimitive = this._shapePrims.length;
             SetActiveArrowStart("none");
             SetActiveArrowEnd("none");
@@ -643,7 +643,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
             this._keepPrimitiveMode = keep;
             if (this._selectedPrimitive !== i) {
                 this._selectedPrimitive = i;
-                Doc.SetSelectedTool(InkTool.Pen);
+                CurrentUserUtils.SelectedTool = InkTool.Pen;
                 SetActiveArrowStart(this._head[i]);
                 SetActiveArrowEnd(this._end[i]);
                 SetActiveBezierApprox("300");
@@ -651,7 +651,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
                 GestureOverlay.Instance.InkShape = this._shapePrims[i];
             } else {
                 this._selectedPrimitive = this._shapePrims.length;
-                Doc.SetSelectedTool(InkTool.None);
+                CurrentUserUtils.SelectedTool = InkTool.None;
                 SetActiveArrowStart("");
                 SetActiveArrowEnd("");
                 GestureOverlay.Instance.InkShape = "";
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index a5194827e..525fa8ca1 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -192,7 +192,10 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
             />
         </div>;
     }
-
+    @computed get treeViewtruncateTitleWidth() { return NumCast(this.doc.treeViewTruncateTitleWidth, this.panelWidth()); }
+    truncateTitleWidth = () => this.treeViewtruncateTitleWidth;
+    @computed get outlineMode() { return this.doc.treeViewType === "outline"; }
+    @computed get fileSysMode() { return this.doc.treeViewType === "fileSystem"; }
     onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick);
     whenActiveChanged = (isActive: boolean) => { this.props.whenActiveChanged(this._isChildActive = isActive); };
     active = (outsideReaction: boolean | undefined) => this.props.active(outsideReaction) || this._isChildActive;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index f903128d7..aa45f49c4 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -103,13 +103,15 @@ export class CollectionView extends Touchable<CollectionViewProps> {
         return viewField as any as CollectionViewType;
     }
 
-    active = (outsideReaction?: boolean) => (this.props.isSelected(outsideReaction) ||
-        this.props.rootSelected(outsideReaction) ||
-        (this.props.layerProvider?.(this.props.Document) !== false && (this.props.Document.forceActive || this.props.Document._isGroup)) ||
-        this._isChildActive ||
-        this.props.renderDepth === 0) ?
-        true :
-        false
+    active = (outsideReaction?: boolean) => {
+        return this.props.renderDepth === 0 ||
+            this.props.isSelected(outsideReaction) ||
+            this.props.rootSelected(outsideReaction) ||
+            (this.props.layerProvider?.(this.props.Document) !== false && (this.props.Document.forceActive || this.props.Document._isGroup)) ||
+            this._isChildActive ?
+            true :
+            false;
+    }
 
     whenActiveChanged = (isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive);
 
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 1d851e775..461289733 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -101,12 +101,10 @@ export class TreeView extends React.Component<TreeViewProps> {
     @observable _dref: DocumentView | undefined | null;
     get displayName() { return "TreeView(" + this.props.document.title + ")"; }  // this makes mobx trace() statements more descriptive
     get treeViewLockExpandedView() { return this.doc.treeViewLockExpandedView; }
-    get defaultExpandedView() { return StrCast(this.doc.treeViewDefaultExpandedView, this.fileSysMode ? (this.doc.isFolder ? "data" : "aliases") : Doc.UserDoc().noviceMode || this.outlineMode ? "layout" : "fields"); }
-    get treeViewDefaultExpandedView() { return this.treeViewLockExpandedView ? this.defaultExpandedView : (this.childDocs && !this.fileSysMode ? this.fieldKey : this.defaultExpandedView); }
+    get defaultExpandedView() { return StrCast(this.doc.treeViewDefaultExpandedView, this.props.treeView.fileSysMode ? (this.doc.isFolder ? "data" : "aliases") : Doc.UserDoc().noviceMode || this.props.treeView.outlineMode ? "layout" : "fields"); }
+    get treeViewDefaultExpandedView() { return this.treeViewLockExpandedView ? this.defaultExpandedView : (this.childDocs && !this.props.treeView.fileSysMode ? this.fieldKey : this.defaultExpandedView); }
 
     @computed get doc() { TraceMobx(); return this.props.document; }
-    @computed get outlineMode() { return this.props.treeView.doc.treeViewType === "outline"; }
-    @computed get fileSysMode() { return this.props.treeView.doc.treeViewType === "fileSystem"; }
     @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && !this.doc.treeViewPreventOpen && Doc.GetT(this.doc, "treeViewOpen", "boolean", true)) || this._overrideTreeViewOpen; }
     @computed get treeViewExpandedView() { return StrCast(this.doc.treeViewExpandedView, this.treeViewDefaultExpandedView); }
     @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containingCollection.maxEmbedHeight, 200); }
@@ -252,7 +250,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         const pt = [de.x, de.y];
         const rect = this._header!.current!.getBoundingClientRect();
         const before = pt[1] < rect.top + rect.height / 2;
-        const inside = this.fileSysMode && !this.doc.isFolder ? false : pt[0] > Math.min(rect.left + 75, rect.left + rect.width * .75) || (!before && this.treeViewOpen && this.childDocList.length);
+        const inside = this.props.treeView.fileSysMode && !this.doc.isFolder ? false : pt[0] > Math.min(rect.left + 75, rect.left + rect.width * .75) || (!before && this.treeViewOpen && this.childDocList.length);
         if (de.complete.linkDragData) {
             const sourceDoc = de.complete.linkDragData.linkSourceGetAnchor();
             const destDoc = this.doc;
@@ -404,7 +402,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 onPointerDown={e => { downX = e.clientX; downY = e.clientY; e.stopPropagation(); }}
                 onClick={(e) => {
                     if (this.props.active() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) {
-                        !this.outlineMode && (this.doc[sortKey] = sortings[(curSort + 1) % sortings.length]);
+                        !this.props.treeView.outlineMode && (this.doc[sortKey] = sortings[(curSort + 1) % sortings.length]);
                         e.stopPropagation();
                     }
                 }}>
@@ -446,14 +444,14 @@ export class TreeView extends React.Component<TreeViewProps> {
         TraceMobx();
         const iconType = this.doc.isFolder ? (this.treeViewOpen ? "chevron-down" : "chevron-right") : Doc.toIcon(this.doc);
         const checked = this.onCheckedClick ? (this.doc.treeViewChecked ?? "unchecked") : undefined;
-        return <div className={`bullet${this.outlineMode ? "-outline" : ""}`} key={"bullet"}
+        return <div className={`bullet${this.props.treeView.outlineMode ? "-outline" : ""}`} key={"bullet"}
             title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : "view fields"}
             onClick={this.bulletClick}
-            style={this.outlineMode ? { opacity: this.titleStyleProvider?.(this.doc, this.props.treeView.props, StyleProp.Opacity) } : {
+            style={this.props.treeView.outlineMode ? { opacity: this.titleStyleProvider?.(this.doc, this.props.treeView.props, StyleProp.Opacity) } : {
                 color: StrCast(this.doc.color, checked === "unchecked" ? "white" : "inherit"),
                 opacity: checked === "unchecked" ? undefined : 0.4
             }}>
-            {this.outlineMode ?
+            {this.props.treeView.outlineMode ?
                 !(this.doc.text as RichTextField)?.Text ? (null) :
                     <FontAwesomeIcon size="sm" icon={[this.childDocs?.length && !this.treeViewOpen ? "fas" : "far", "circle"]} /> :
                 <div className="treeView-bulletIcons" >
@@ -476,16 +474,16 @@ export class TreeView extends React.Component<TreeViewProps> {
                 <FontAwesomeIcon key="bars" icon="bars" size="sm" onClick={e => { this.showContextMenu(e); e.stopPropagation(); }} />
                 <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView}
                     onPointerDown={action(() => {
-                        if (this.fileSysMode) {
+                        if (this.props.treeView.fileSysMode) {
                             this.doc.treeViewExpandedView = this.doc.isFolder ? this.fieldKey : this.treeViewExpandedView === "layout" ? "aliases" :
                                 this.treeViewExpandedView === "aliases" && !Doc.UserDoc().noviceMode ? "fields" : "layout";
                         } else if (this.treeViewOpen) {
                             this.doc.treeViewExpandedView = this.treeViewLockExpandedView ? this.doc.treeViewExpandedView :
-                                this.treeViewExpandedView === this.fieldKey ? (Doc.UserDoc().noviceMode || this.outlineMode ? "layout" : "fields") :
+                                this.treeViewExpandedView === this.fieldKey ? (Doc.UserDoc().noviceMode || this.props.treeView.outlineMode ? "layout" : "fields") :
                                     this.treeViewExpandedView === "fields" && this.layoutDoc ? "layout" :
                                         this.treeViewExpandedView === "layout" && DocListCast(this.doc.links).length ? "links" :
                                             (this.treeViewExpandedView === "links" || this.treeViewExpandedView === "layout") && DocListCast(this.doc[this.fieldKey + "-annotations"]).length ? "annotations" :
-                                                this.childDocs ? this.fieldKey : (Doc.UserDoc().noviceMode || this.outlineMode ? "layout" : "fields");
+                                                this.childDocs ? this.fieldKey : (Doc.UserDoc().noviceMode || this.props.treeView.outlineMode ? "layout" : "fields");
                         }
                         this.treeViewOpen = true;
                     })}>
@@ -497,12 +495,11 @@ export class TreeView extends React.Component<TreeViewProps> {
     showContextMenu = (e: React.MouseEvent) => simulateMouseClick(this._docRef?.ContentDiv, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
     contextMenuItems = () => this.doc.isFolder ?
         [{ script: ScriptField.MakeFunction(`scriptContext.makeFolder()`, { scriptContext: "any" })!, label: "New Folder" }] : Doc.IsSystem(this.doc) ? [] :
-            this.fileSysMode && this.doc === Doc.GetProto(this.doc) ?
+            this.props.treeView.fileSysMode && this.doc === Doc.GetProto(this.doc) ?
                 [{ script: ScriptField.MakeFunction(`openOnRight(getAlias(self))`)!, label: "Open Alias" }] :
                 [{ script: ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!, label: "Focus or Open" }]
-    truncateTitleWidth = () => NumCast(this.props.treeView.props.Document.treeViewTruncateTitleWidth, this.props.panelWidth());
     onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick));
-    onChildDoubleClick = () => (!this.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick);
+    onChildDoubleClick = () => (!this.props.treeView.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick);
 
     refocus = () => this.props.treeView.props.focus(this.props.treeView.props.Document);
     ignoreEvent = (e: any) => {
@@ -515,7 +512,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         if (!doc || doc !== this.doc) return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
 
         switch (property.split(":")[0]) {
-            case StyleProp.Opacity: return this.outlineMode ? undefined : 1;
+            case StyleProp.Opacity: return this.props.treeView.outlineMode ? undefined : 1;
             case StyleProp.BackgroundColor: return this.selected ? "#7089bb" : StrCast(doc._backgroundColor, StrCast(doc.backgroundColor));
             case StyleProp.DocContents: return testDocProps(props) && !props?.treeViewDoc ? (null) :
                 <div className="treeView-label" style={{    // just render a title for a tree view label (identified by treeViewDoc being set in 'props')
@@ -532,7 +529,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
     }
     onKeyDown = (e: React.KeyboardEvent) => {
-        if (this.doc.treeViewHideHeader || this.outlineMode) {
+        if (this.doc.treeViewHideHeader || this.props.treeView.outlineMode) {
             e.stopPropagation();
             e.preventDefault();
             switch (e.key) {
@@ -564,11 +561,11 @@ export class TreeView extends React.Component<TreeViewProps> {
                 if (!shift) this.props.indentDocument?.(true);
                 else this.props.outdentDocument?.(true);
             })}
-            OnEmpty={undoBatch(() => this.outlineMode && this.props.removeDoc?.(this.doc))}
-            OnFillDown={val => this.fileSysMode && this.makeFolder()}
+            OnEmpty={undoBatch(() => this.props.treeView.outlineMode && this.props.removeDoc?.(this.doc))}
+            OnFillDown={val => this.props.treeView.fileSysMode && this.makeFolder()}
             SetValue={undoBatch((value: string, shiftKey: boolean, enterKey: boolean) => {
                 Doc.SetInPlace(this.doc, "title", value, false);
-                this.outlineMode && enterKey && this.makeTextCollection();
+                this.props.treeView.outlineMode && enterKey && this.makeTextCollection();
             })}
         />
             : <DocumentView key="title"
@@ -598,8 +595,8 @@ export class TreeView extends React.Component<TreeViewProps> {
                 removeDocument={this.props.removeDoc}
                 ScreenToLocalTransform={this.getTransform}
                 NativeHeight={() => 18}
-                NativeWidth={this.truncateTitleWidth}
-                PanelWidth={this.truncateTitleWidth}
+                NativeWidth={this.props.treeView.truncateTitleWidth}
+                PanelWidth={this.props.treeView.truncateTitleWidth}
                 PanelHeight={() => 18}
                 contextMenuItems={this.contextMenuItems}
                 renderDepth={1}
@@ -705,7 +702,7 @@ export class TreeView extends React.Component<TreeViewProps> {
 
     @computed get renderBorder() {
         const sorting = this.doc[`${this.fieldKey}-sortCriteria`];
-        return <div className={`treeView-border${this.outlineMode ? "outline" : ""}`}
+        return <div className={`treeView-border${this.props.treeView.outlineMode ? "outline" : ""}`}
             style={{ borderColor: sorting === undefined ? undefined : sorting === "up" ? "crimson" : sorting === "down" ? "blue" : "green" }}>
             {!this.treeViewOpen ? (null) : this.renderContent}
         </div>;
@@ -725,7 +722,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         }
         else this._editMaxWidth = "";
 
-        const hideTitle = this.doc.treeViewHideHeader || this.outlineMode;
+        const hideTitle = this.doc.treeViewHideHeader || this.props.treeView.outlineMode;
         return <div className={`treeView-container${this._dref?.contentsActive() ? "-active" : ""}`}
             ref={this.createTreeDropTarget}
             onPointerDown={e => this.props.active(true) && SelectionManager.DeselectAll()}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index ec5cb8a61..019fc9bae 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -455,7 +455,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
 
     @action
     onPointerDown = (e: React.PointerEvent): void => {
-        if (e.nativeEvent.cancelBubble || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) || InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || (Doc.GetSelectedTool() === InkTool.Highlighter || Doc.GetSelectedTool() === InkTool.Pen)) {
+        if (e.nativeEvent.cancelBubble || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) || InteractionUtils.IsType(e, InteractionUtils.PENTYPE) ||
+            ([InkTool.Pen, InkTool.Highlighter].includes(CurrentUserUtils.SelectedTool))) {
             return;
         }
         this._hitCluster = this.pickCluster(this.getTransform().transformPoint(e.clientX, e.clientY));
@@ -465,7 +466,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             document.addEventListener("pointermove", this.onPointerMove);
             document.addEventListener("pointerup", this.onPointerUp);
             // if not using a pen and in no ink mode
-            if (Doc.GetSelectedTool() === InkTool.None) {
+            if (CurrentUserUtils.SelectedTool === InkTool.None) {
                 this._downX = this._lastX = e.pageX;
                 this._downY = this._lastY = e.pageY;
             }
@@ -489,7 +490,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
                     this.addMoveListeners();
                     this.removeEndListeners();
                     this.addEndListeners();
-                    if (Doc.GetSelectedTool() === InkTool.None) {
+                    if (CurrentUserUtils.SelectedTool === InkTool.None) {
                         this._lastX = pt.pageX;
                         this._lastY = pt.pageY;
                         e.preventDefault();
@@ -509,7 +510,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             case GestureUtils.Gestures.Stroke:
                 const points = ge.points;
                 const B = this.getTransform().transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height);
-                const inkDoc = Docs.Create.InkDocument(ActiveInkColor(), Doc.GetSelectedTool(), ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), points,
+                const inkDoc = Docs.Create.InkDocument(ActiveInkColor(), CurrentUserUtils.SelectedTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), points,
                     { title: "ink stroke", x: B.x - Number(ActiveInkWidth()) / 2, y: B.y - Number(ActiveInkWidth()) / 2, _width: B.width + Number(ActiveInkWidth()), _height: B.height + Number(ActiveInkWidth()) });
                 this.addDocument(inkDoc);
                 e.stopPropagation();
@@ -649,7 +650,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) {
             if (this.props.active(true)) e.stopPropagation();
         } else if (!e.cancelBubble) {
-            if (Doc.GetSelectedTool() === InkTool.None) {
+            if (CurrentUserUtils.SelectedTool === InkTool.None) {
                 if (this.tryDragCluster(e, this._hitCluster)) {
                     document.removeEventListener("pointermove", this.onPointerMove);
                     document.removeEventListener("pointerup", this.onPointerUp);
@@ -665,7 +666,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         if (!e.cancelBubble) {
             const myTouches = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true);
             if (myTouches[0]) {
-                if (Doc.GetSelectedTool() === InkTool.None) {
+                if (CurrentUserUtils.SelectedTool === InkTool.None) {
                     if (this.tryDragCluster(e, this._hitCluster)) {
                         e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document'  however it does mark the event as cancelBubble=true which we test for in the move event handlers
                         e.preventDefault();
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index e625b5b4b..9206d3767 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -320,7 +320,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
     onClick = (e: React.MouseEvent): void => {
         if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
             Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
-            if (Doc.GetSelectedTool() === InkTool.None) {
+            if (CurrentUserUtils.SelectedTool === InkTool.None) {
                 if (!(e.nativeEvent as any).marqueeHit) {
                     (e.nativeEvent as any).marqueeHit = true;
                     if (!this.props.trySelectCluster(e.shiftKey)) {
diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx
index 715ec92f8..61cc8b3d1 100644
--- a/src/client/views/nodes/ColorBox.tsx
+++ b/src/client/views/nodes/ColorBox.tsx
@@ -16,6 +16,7 @@ import "./ColorBox.scss";
 import { FieldView, FieldViewProps } from './FieldView';
 import { DocumentType } from "../../documents/DocumentTypes";
 import { RichTextMenu } from "./formattedText/RichTextMenu";
+import { CurrentUserUtils } from "../../util/CurrentUserUtils";
 
 type ColorDocument = makeInterface<[typeof documentSchema]>;
 const ColorDocument = makeInterface(documentSchema);
@@ -30,7 +31,7 @@ export class ColorBox extends ViewBoxBaseComponent<FieldViewProps, ColorDocument
         Doc.UserDoc().backgroundColor = Utils.colorString(color);
         SetActiveInkColor(color.hex);
 
-        if (Doc.GetSelectedTool() === InkTool.None) {
+        if (CurrentUserUtils.SelectedTool === InkTool.None) {
             const selected = SelectionManager.Views();
             selected.map(view => {
                 const targetDoc = view.props.Document.dragFactory instanceof Doc ? view.props.Document.dragFactory :
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 56130ef55..3622be5fc 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -242,7 +242,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
                     results.push(link);
                 }
             } else results.push(link);
-        })
+        });
         return results;
     }
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 55650491f..6592c896f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -489,7 +489,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 
     onPointerDown = (e: React.PointerEvent): void => {
         // continue if the event hasn't been canceled AND we are using a mouse or this has an onClick or onDragStart function (meaning it is a button document)
-        if (!(InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE) || Doc.GetSelectedTool() === InkTool.Highlighter || Doc.GetSelectedTool() === InkTool.Pen)) {
+        if (!(InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool))) {
             if (!InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
                 e.stopPropagation();
                 if (SelectionManager.IsSelected(this.props.DocumentView(), true) && this.props.Document._viewType !== CollectionViewType.Docking) e.preventDefault(); // goldenlayout needs to be able to move its tabs, so can't preventDefault for it
@@ -501,7 +501,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         this._downY = e.clientY;
         if ((!e.nativeEvent.cancelBubble || this.onClickHandler || this.layoutDoc.onDragStart) &&
             // if this is part of a template, let the event go up to the tempalte root unless right/ctrl clicking
-            !((this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0))) {
+            !(this.props.Document.rootDocument && !(e.ctrlKey || e.button > 0))) {
             if ((this.active || this.layoutDoc.onDragStart) &&
                 !e.ctrlKey &&
                 (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) &&
@@ -518,7 +518,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     }
 
     onPointerMove = (e: PointerEvent): void => {
-        if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || Doc.GetSelectedTool() === InkTool.Highlighter || Doc.GetSelectedTool() === InkTool.Pen)) return;
+        if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool))) return;
         if (e.cancelBubble && this.active) {
             document.removeEventListener("pointermove", this.onPointerMove); // stop listening to pointerMove if something else has stopPropagated it (e.g., the MarqueeView)
         }
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index b9480fa74..844afe1e2 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -747,7 +747,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc);
     getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight
     panelHeight = () => this.props.PanelHeight() - 40;
-    active = (outsideReaction?: boolean) => ((Doc.GetSelectedTool() === InkTool.None && this.props.layerProvider?.(this.layoutDoc) !== false) &&
+    active = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && this.props.layerProvider?.(this.layoutDoc) !== false) &&
         (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
 
     /**
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 4956b315d..a14d8ccae 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -17,6 +17,7 @@ import { ContextMenuProps } from "../ContextMenuItem";
 import { ViewBoxBaseComponent } from "../DocComponent";
 import { FieldView, FieldViewProps } from './FieldView';
 import "./ScreenshotBox.scss";
+import { CurrentUserUtils } from "../../util/CurrentUserUtils";
 const path = require('path');
 
 type ScreenshotDocument = makeInterface<[typeof documentSchema]>;
@@ -129,7 +130,7 @@ export class ScreenshotBox extends ViewBoxBaseComponent<FieldViewProps, Screensh
     }
 
     @computed get content() {
-        const interactive = Doc.GetSelectedTool() !== InkTool.None || !this.props.isSelected() ? "" : "-interactive";
+        const interactive = CurrentUserUtils.SelectedTool !== InkTool.None || !this.props.isSelected() ? "" : "-interactive";
         const style = "videoBox-content" + interactive;
         return <video className={`${style}`} key="video" autoPlay={this._screenCapture} ref={this.setVideoRef}
             style={{ width: this._screenCapture ? "100%" : undefined, height: this._screenCapture ? "100%" : undefined }}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 6afc2258a..3e1edb927 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -27,6 +27,7 @@ import { FieldView, FieldViewProps } from './FieldView';
 import { FormattedTextBoxComment } from "./formattedText/FormattedTextBoxComment";
 import { LinkDocPreview } from "./LinkDocPreview";
 import "./VideoBox.scss";
+import { CurrentUserUtils } from "../../util/CurrentUserUtils";
 const path = require('path');
 
 type VideoDocument = makeInterface<[typeof documentSchema]>;
@@ -293,7 +294,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
 
     @computed get content() {
         const field = Cast(this.dataDoc[this.fieldKey], VideoField);
-        const interactive = Doc.GetSelectedTool() !== InkTool.None || !this.props.isSelected() ? "" : "-interactive";
+        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._isChildActive || this.active() ? "all" : "none" }}>
@@ -344,7 +345,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
             this._disposers.youtubeReactionDisposer?.();
             this._disposers.reactionDisposer = reaction(() => this.layoutDoc._currentTimecode, () => !this._playing && this.Seek((this.layoutDoc._currentTimecode || 0)));
             this._disposers.youtubeReactionDisposer = reaction(
-                () => !this.props.Document.isAnnotating && Doc.GetSelectedTool() === InkTool.None && this.props.isSelected(true) && !SnappingManager.GetIsDragging() && !DocumentDecorations.Instance.Interacting,
+                () => !this.props.Document.isAnnotating && CurrentUserUtils.SelectedTool === InkTool.None && this.props.isSelected(true) && !SnappingManager.GetIsDragging() && !DocumentDecorations.Instance.Interacting,
                 (interactive) => iframe.style.pointerEvents = interactive ? "all" : "none", { fireImmediately: true });
         };
         if (typeof (YT) === undefined) setTimeout(() => this.loadYouTube(iframe), 100);
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 156fe64c9..b15865c1f 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -31,6 +31,7 @@ import { LinkDocPreview } from "./LinkDocPreview";
 import "./WebBox.scss";
 import { DocumentType } from '../../documents/DocumentTypes';
 import React = require("react");
+import { CurrentUserUtils } from "../../util/CurrentUserUtils";
 const htmlToText = require("html-to-text");
 
 type WebDocument = makeInterface<[typeof documentSchema]>;
@@ -487,7 +488,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
         const frozen = !this.props.isSelected() || DocumentDecorations.Instance?.Interacting;
         const scale = this.props.scaling?.() || 1;
         return (<>
-            <div className={"webBox-cont" + (this.props.isSelected() && Doc.GetSelectedTool() === InkTool.None && !DocumentDecorations.Instance?.Interacting ? "-interactive" : "")}
+            <div className={"webBox-cont" + (this.props.isSelected() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting ? "-interactive" : "")}
                 style={{
                     width: NumCast(this.layoutDoc[this.fieldKey + "-contentWidth"]) || `${100 / scale}%`,
                     height: `${100 / scale}%`,
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 86a9f4347..0eade44ac 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -71,7 +71,7 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
 
     constructor(props: IDashDocViewInternal) {
         super(props);
-        this._textBox = this.props.tbox as FormattedTextBox;
+        this._textBox = this.props.tbox;
 
         const updateDoc = action((dashDoc: Doc) => {
             this._dashDoc = dashDoc;
@@ -101,7 +101,7 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
                         const aliasedDoc = Doc.MakeAlias(dashDocBase, this.props.docid + this.props.alias);
                         aliasedDoc.layoutKey = "layout";
                         this.props.fieldKey && DocUtils.makeCustomViewClicked(aliasedDoc, Docs.Create.StackingDocument, this.props.fieldKey, undefined);
-                        updateDoc(aliasedDoc)
+                        updateDoc(aliasedDoc);
                     }
                 });
             } else {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 03997713c..985c5d807 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1454,7 +1454,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 noSidebar={true}
                 fieldKey={this.layoutDoc.sidebarViewType === "translation" ? `${this.fieldKey}-translation` : this.SidebarKey} />;
         };
-        return <div className={"formattedTextBox-sidebar" + (Doc.GetSelectedTool() !== InkTool.None ? "-inking" : "")}
+        return <div className={"formattedTextBox-sidebar" + (CurrentUserUtils.SelectedTool !== InkTool.None ? "-inking" : "")}
             style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
             {renderComponent(StrCast(this.layoutDoc.sidebarViewType))}
         </div>;
@@ -1465,7 +1465,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         const active = this.active();
         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 = (Doc.GetSelectedTool() === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || this.props.layerProvider?.(this.layoutDoc) !== false);
+        const interactive = (CurrentUserUtils.SelectedTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || this.props.layerProvider?.(this.layoutDoc) !== false);
         if (!selected && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide);
         const minimal = this.props.ignoreAutoHeight;
         const margins = NumCast(this.layoutDoc._yMargin, this.props.yMargin || 0);
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 05d81f40f..1e574b9c0 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -56,10 +56,10 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
     }
 
     @undoBatch
-    pinToPres = () => this.props.pinToPres(this.annoTextRegion);
+    pinToPres = () => this.props.pinToPres(this.annoTextRegion)
 
     @undoBatch
-    makePushpin = () => this.annoTextRegion.isPushpin = !this.annoTextRegion.isPushpin;
+    makePushpin = () => this.annoTextRegion.isPushpin = !this.annoTextRegion.isPushpin
 
     isPushpin = () => BoolCast(this.annoTextRegion.isPushpin);
 
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 18e167b7a..1a1bc70b2 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -28,6 +28,7 @@ import "./PDFViewer.scss";
 const pdfjs = require('pdfjs-dist/es5/build/pdf.js');
 import React = require("react");
 import { SharingManager } from "../../util/SharingManager";
+import { CurrentUserUtils } from "../../util/CurrentUserUtils";
 const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer");
 const pdfjsLib = require("pdfjs-dist");
 const _global = (window /* browser */ || global /* node */) as any;
@@ -512,7 +513,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
     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);
     @computed get overlayLayer() {
-        return <div className={`pdfViewerDash-overlay${Doc.GetSelectedTool() !== InkTool.None || SnappingManager.GetIsDragging() ? "-inking" : ""}`}
+        return <div className={`pdfViewerDash-overlay${CurrentUserUtils.SelectedTool !== InkTool.None || SnappingManager.GetIsDragging() ? "-inking" : ""}`}
             style={{
                 pointerEvents: SnappingManager.GetIsDragging() ? "all" : undefined,
                 mixBlendMode: this.allAnnotations.some(anno => anno.mixBlendMode) ? "hard-light" : undefined,
diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx
index 82c0e19c8..505a8da7e 100644
--- a/src/client/views/webcam/DashWebRTCVideo.tsx
+++ b/src/client/views/webcam/DashWebRTCVideo.tsx
@@ -11,6 +11,7 @@ import { FieldView, FieldViewProps } from "../nodes/FieldView";
 import "./DashWebRTCVideo.scss";
 import { hangup, initialize, refreshVideos } from "./WebCamLogic";
 import React = require("react");
+import { CurrentUserUtils } from "../../util/CurrentUserUtils";
 
 
 /**
@@ -69,7 +70,7 @@ export class DashWebRTCVideo extends React.Component<CollectionFreeFormDocumentV
             </div >;
 
         const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
-        const classname = "webBox-cont" + (this.props.isSelected() && Doc.GetSelectedTool() === InkTool.None && !DocumentDecorations.Instance.Interacting ? "-interactive" : "");
+        const classname = "webBox-cont" + (this.props.isSelected() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? "-interactive" : "");
 
         return (
             <>
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index d590695d0..e64195b63 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -905,9 +905,6 @@ export namespace Doc {
     export function UserDoc(): Doc { return manager._user_doc; }
     export function SharingDoc(): Doc { return Cast(Doc.UserDoc().mySharedDocs, Doc, null); }
     export function LinkDBDoc(): Doc { return Cast(Doc.UserDoc().myLinkDatabase, Doc, null); }
-
-    export function SetSelectedTool(tool: InkTool) { Doc.UserDoc().activeInkTool = tool; }
-    export function GetSelectedTool(): InkTool { return StrCast(Doc.UserDoc().activeInkTool, InkTool.None) as InkTool; }
     export function SetUserDoc(doc: Doc) { return (manager._user_doc = doc); }
 
     const isSearchMatchCache = computedFn(function IsSearchMatch(doc: Doc) {
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index da3dbecbe..1001d9e19 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -76,7 +76,7 @@ export class MobileInterface extends React.Component {
     componentDidMount = () => {
         // if the home menu is in list view -> adjust the menu toggle appropriately
         this._menuListView = this._homeDoc._viewType === "stacking" ? true : false;
-        Doc.SetSelectedTool(InkTool.None); // ink should intially be set to none
+        CurrentUserUtils.SelectedTool = InkTool.None; // ink should intially be set to none
         Doc.UserDoc().activeMobile = this._homeDoc; // active mobile set to home
         AudioBox.Enabled = true;
 
@@ -419,10 +419,10 @@ export class MobileInterface extends React.Component {
         button.style.color = this._ink ? "black" : "white";
 
         if (!this._ink) {
-            Doc.SetSelectedTool(InkTool.Pen);
+            CurrentUserUtils.SelectedTool = InkTool.Pen;
             this._ink = true;
         } else {
-            Doc.SetSelectedTool(InkTool.None);
+            CurrentUserUtils.SelectedTool = InkTool.None;
             this._ink = false;
         }
     }
-- 
cgit v1.2.3-70-g09d2


From 917aeb762ee5464156f2e2225388e2fe3882a124 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 12 Mar 2021 20:16:05 -0500
Subject: fixed dropping documents onto file system view.  fixed problem with
 tabDocView not removing itself from TabMap causing problem trying to open the
 same doc twice from the file system.  made shouldNotScale a computed value.

---
 src/client/views/collections/TabDocView.tsx | 4 +++-
 src/client/views/collections/TreeView.tsx   | 7 +++++--
 src/client/views/nodes/DocumentView.tsx     | 8 ++++----
 3 files changed, 12 insertions(+), 7 deletions(-)

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

diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index f7e067399..e0bbd1224 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -213,7 +213,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     }
 
     componentDidMount() {
-        const selected = () => SelectionManager.Views().some(v => v.props.Document === this._document);
         new _global.ResizeObserver(action((entries: any) => {
             for (const entry of entries) {
                 this._panelWidth = entry.contentRect.width;
@@ -229,6 +228,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
 
     componentWillUnmount() {
         this._tabReaction?.();
+        this.tab && CollectionDockingView.Instance.tabMap.delete(this.tab);
+
         this.props.glContainer.layoutManager.off("activeContentItemChanged", this.onActiveContentItemChanged);
     }
 
@@ -344,6 +345,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     }
 
     render() {
+        this.tab && CollectionDockingView.Instance.tabMap.delete(this.tab);
         return (
             <div className="collectionDockingView-content" style={{ height: "100%", width: "100%" }} ref={ref => {
                 if (this._mainCont = ref) {
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 461289733..0d7ccc4bd 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -32,6 +32,9 @@ import { CollectionTreeView } from './CollectionTreeView';
 import { CollectionView, CollectionViewType } from './CollectionView';
 import "./TreeView.scss";
 import React = require("react");
+import { ContextMenu } from '../ContextMenu';
+import { ContextMenuProps } from '../ContextMenuItem';
+import { SharingManager } from '../../util/SharingManager';
 
 export interface TreeViewProps {
     document: Doc;
@@ -268,7 +271,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc), true as boolean);
             const move = (!docDragData.dropAction || docDragData.dropAction === "proto" || docDragData.dropAction === "move" || docDragData.dropAction === "same") && docDragData.moveDocument;
             if (canAdd) {
-                UndoManager.RunInTempBatch(() => docDragData.droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) : addDoc(d)) || added, false));
+                UndoManager.RunInTempBatch(() => docDragData.droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (docDragData.dropAction === "proto" ? addDoc(d) : false) : addDoc(d)) || added, false));
             }
         }
     }
@@ -550,7 +553,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         const view = this._editTitle ? <EditableView key="_editTitle"
             oneLine={true}
             display={"inline-block"}
-            editing={true}
+            editing={this._editTitle}
             background={"#7089bb"}
             contents={StrCast(this.doc.title)}
             height={12}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 6592c896f..6d7d62085 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1001,11 +1001,11 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         return this.docView?._componentView?.reverseNativeScaling?.() ? 0 :
             returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions));
     }
-    shouldNotScale = () => (this.layoutDoc._fitWidth && !this.nativeWidth) || [CollectionViewType.Docking, CollectionViewType.Tree].includes(this.Document._viewType as any);
-    @computed get effectiveNativeWidth() { return this.shouldNotScale() ? 0 : (this.nativeWidth || NumCast(this.layoutDoc.width)); }
-    @computed get effectiveNativeHeight() { return this.shouldNotScale() ? 0 : (this.nativeHeight || NumCast(this.layoutDoc.height)); }
+    @computed get shouldNotScale() { return (this.layoutDoc._fitWidth && !this.nativeWidth) || [CollectionViewType.Docking, CollectionViewType.Tree].includes(this.Document._viewType as any); }
+    @computed get effectiveNativeWidth() { return this.shouldNotScale ? 0 : (this.nativeWidth || NumCast(this.layoutDoc.width)); }
+    @computed get effectiveNativeHeight() { return this.shouldNotScale ? 0 : (this.nativeHeight || NumCast(this.layoutDoc.height)); }
     @computed get nativeScaling() {
-        if (this.shouldNotScale()) return 1;
+        if (this.shouldNotScale) return 1;
         const minTextScale = this.Document.type === DocumentType.RTF ? 0.1 : 0;
         if (this.layoutDoc._fitWidth || this.props.PanelHeight() / this.effectiveNativeHeight > this.props.PanelWidth() / this.effectiveNativeWidth) {
             return Math.max(minTextScale, this.props.PanelWidth() / this.effectiveNativeWidth);  // width-limited or fitWidth
-- 
cgit v1.2.3-70-g09d2

