From 146f8622d5bac2edc6b09f57c173bd057dfbcfad Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 8 Jul 2022 00:17:26 -0400
Subject: restructured currentUserUtils to avoid having import cycles.

---
 src/client/views/pdf/PDFViewer.tsx | 455 ++++++++++++++++++++-----------------
 1 file changed, 249 insertions(+), 206 deletions(-)

(limited to 'src/client/views/pdf/PDFViewer.tsx')

diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 510c5c385..837734edf 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -1,36 +1,35 @@
-import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, trace } from "mobx";
-import { observer } from "mobx-react";
-import * as Pdfjs from "pdfjs-dist";
-import "pdfjs-dist/web/pdf_viewer.css";
-import { Doc, DocListCast, Field, HeightSym, Opt } from "../../../fields/Doc";
-import { Id } from "../../../fields/FieldSymbols";
-import { InkTool } from "../../../fields/InkField";
-import { Cast, NumCast, StrCast } from "../../../fields/Types";
-import { TraceMobx } from "../../../fields/util";
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, OmitKeys, returnFalse, smoothScroll, Utils } from "../../../Utils";
-import { DocUtils } from "../../documents/Documents";
-import { CurrentUserUtils } from "../../util/CurrentUserUtils";
-import { SelectionManager } from "../../util/SelectionManager";
-import { SharingManager } from "../../util/SharingManager";
-import { SnappingManager } from "../../util/SnappingManager";
-import { MarqueeOptionsMenu } from "../collections/collectionFreeForm";
-import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
-import { MarqueeAnnotator } from "../MarqueeAnnotator";
-import { DocumentViewProps } from "../nodes/DocumentView";
-import { FieldViewProps } from "../nodes/FieldView";
-import { LinkDocPreview } from "../nodes/LinkDocPreview";
-import { StyleProp } from "../StyleProvider";
-import { AnchorMenu } from "./AnchorMenu";
-import { Annotation } from "./Annotation";
-import "./PDFViewer.scss";
-import React = require("react");
-const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer");
-const pdfjsLib = require("pdfjs-dist");
-const _global = (window /* browser */ || global /* node */) as any;
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import * as Pdfjs from 'pdfjs-dist';
+import 'pdfjs-dist/web/pdf_viewer.css';
+import { Doc, DocListCast, Field, HeightSym, Opt } from '../../../fields/Doc';
+import { Id } from '../../../fields/FieldSymbols';
+import { InkTool } from '../../../fields/InkField';
+import { Cast, NumCast, StrCast } from '../../../fields/Types';
+import { TraceMobx } from '../../../fields/util';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, OmitKeys, smoothScroll, Utils } from '../../../Utils';
+import { DocUtils } from '../../documents/Documents';
+import { SelectionManager } from '../../util/SelectionManager';
+import { SharingManager } from '../../util/SharingManager';
+import { SnappingManager } from '../../util/SnappingManager';
+import { MarqueeOptionsMenu } from '../collections/collectionFreeForm';
+import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
+import { MarqueeAnnotator } from '../MarqueeAnnotator';
+import { DocumentViewProps } from '../nodes/DocumentView';
+import { FieldViewProps } from '../nodes/FieldView';
+import { LinkDocPreview } from '../nodes/LinkDocPreview';
+import { StyleProp } from '../StyleProvider';
+import { AnchorMenu } from './AnchorMenu';
+import { Annotation } from './Annotation';
+import './PDFViewer.scss';
+import React = require('react');
+const PDFJSViewer = require('pdfjs-dist/web/pdf_viewer');
+const pdfjsLib = require('pdfjs-dist');
+const _global = (window /* browser */ || global) /* node */ as any;
 
 //pdfjsLib.GlobalWorkerOptions.workerSrc = `/assets/pdf.worker.js`;
 // The workerSrc property shall be specified.
-pdfjsLib.GlobalWorkerOptions.workerSrc = "https://unpkg.com/pdfjs-dist@2.14.305/build/pdf.worker.js";
+pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@2.14.305/build/pdf.worker.js';
 
 interface IViewerProps extends FieldViewProps {
     Document: Doc;
@@ -53,7 +52,7 @@ interface IViewerProps extends FieldViewProps {
 @observer
 export class PDFViewer extends React.Component<IViewerProps> {
     static _annotationStyle: any = addStyleSheet();
-    @observable private _pageSizes: { width: number, height: number }[] = [];
+    @observable private _pageSizes: { width: number; height: number }[] = [];
     @observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
     @observable private _marqueeing: number[] | undefined;
     @observable private _textSelecting = true;
@@ -70,7 +69,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
     private _viewer: React.RefObject<HTMLDivElement> = React.createRef();
     public _getAnchor: (savedAnnotations?: ObservableMap<number, HTMLDivElement[]>) => Opt<Doc> = () => undefined;
     _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
-    private _selectionText: string = "";
+    private _selectionText: string = '';
     private _downX: number = 0;
     private _downY: number = 0;
     private _lastSearch = false;
@@ -82,69 +81,80 @@ export class PDFViewer extends React.Component<IViewerProps> {
     @observable isAnnotating = false;
     // key where data is stored
     @computed get allAnnotations() {
-        return DocUtils.FilterDocs(DocListCast(this.props.dataDoc[this.props.fieldKey + "-annotations"]), this.props.docFilters(), this.props.docRangeFilters(), undefined);
+        return DocUtils.FilterDocs(DocListCast(this.props.dataDoc[this.props.fieldKey + '-annotations']), this.props.docFilters(), this.props.docRangeFilters(), undefined);
+    }
+    @computed get inlineTextAnnotations() {
+        return this.allAnnotations.filter(a => a.textInlineAnnotations);
     }
-    @computed get inlineTextAnnotations() { return this.allAnnotations.filter(a => a.textInlineAnnotations); }
 
     componentDidMount = async () => {
-        runInAction(() => this._showWaiting = true);
+        runInAction(() => (this._showWaiting = true));
         this.setupPdfJsViewer();
-        this._mainCont.current?.addEventListener("scroll", e => (e.target as any).scrollLeft = 0);
+        this._mainCont.current?.addEventListener('scroll', e => ((e.target as any).scrollLeft = 0));
 
-        this._disposers.autoHeight = reaction(() => this.props.layoutDoc._autoHeight,
+        this._disposers.autoHeight = reaction(
+            () => this.props.layoutDoc._autoHeight,
             autoHeight => {
                 if (autoHeight) {
-                    this.props.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]);
-                    this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]) * (this.props.scaling?.() || 1));
+                    this.props.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']);
+                    this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']) * (this.props.scaling?.() || 1));
                 }
-            });
+            }
+        );
 
-        this._disposers.selected = reaction(() => this.props.isSelected(),
+        this._disposers.selected = reaction(
+            () => this.props.isSelected(),
             selected => {
                 // if (!selected) {
                 //     Array.from(this._savedAnnotations.values()).forEach(v => v.forEach(a => a.remove()));
                 //     Array.from(this._savedAnnotations.keys()).forEach(k => this._savedAnnotations.set(k, []));
                 // }
-                (SelectionManager.Views().length === 1) && this.setupPdfJsViewer();
+                SelectionManager.Views().length === 1 && this.setupPdfJsViewer();
             },
-            { fireImmediately: true });
-        this._disposers.curPage = reaction(() => Cast(this.props.Document._curPage, "number", null),
-            (page) => page !== undefined && page !== this._pdfViewer?.currentPageNumber && this.gotoPage(page),
             { fireImmediately: true }
         );
-    }
+        this._disposers.curPage = reaction(
+            () => Cast(this.props.Document._curPage, 'number', null),
+            page => page !== undefined && page !== this._pdfViewer?.currentPageNumber && this.gotoPage(page),
+            { fireImmediately: true }
+        );
+    };
 
     componentWillUnmount = () => {
         Object.values(this._disposers).forEach(disposer => disposer?.());
-        document.removeEventListener("copy", this.copy);
-    }
+        document.removeEventListener('copy', this.copy);
+    };
 
     copy = (e: ClipboardEvent) => {
         if (this.props.isContentActive() && e.clipboardData) {
-            e.clipboardData.setData("text/plain", this._selectionText);
+            e.clipboardData.setData('text/plain', this._selectionText);
             e.preventDefault();
         }
-    }
+    };
 
     @action
     initialLoad = async () => {
         if (this._pageSizes.length === 0) {
-            this._pageSizes = Array<{ width: number, height: number }>(this.props.pdf.numPages);
-            await Promise.all(this._pageSizes.map((val, i) =>
-                this.props.pdf.getPage(i + 1).then(action((page: Pdfjs.PDFPageProxy) => {
-                    const page0or180 = page.rotate === 0 || page.rotate === 180;
-                    this._pageSizes.splice(i, 1, {
-                        width: (page.view[page0or180 ? 2 : 3] - page.view[page0or180 ? 0 : 1]),
-                        height: (page.view[page0or180 ? 3 : 2] - page.view[page0or180 ? 1 : 0])
-                    });
-                    if (i === this.props.pdf.numPages - 1) {
-                        this.props.loaded?.(page.view[page0or180 ? 2 : 3] - page.view[page0or180 ? 0 : 1],
-                            page.view[page0or180 ? 3 : 2] - page.view[page0or180 ? 1 : 0], this.props.pdf.numPages);
-                    }
-                }))));
-            this.props.Document.scrollHeight = this._pageSizes.reduce((size, page) => size + page.height, 0) * 96 / 72;
+            this._pageSizes = Array<{ width: number; height: number }>(this.props.pdf.numPages);
+            await Promise.all(
+                this._pageSizes.map((val, i) =>
+                    this.props.pdf.getPage(i + 1).then(
+                        action((page: Pdfjs.PDFPageProxy) => {
+                            const page0or180 = page.rotate === 0 || page.rotate === 180;
+                            this._pageSizes.splice(i, 1, {
+                                width: page.view[page0or180 ? 2 : 3] - page.view[page0or180 ? 0 : 1],
+                                height: page.view[page0or180 ? 3 : 2] - page.view[page0or180 ? 1 : 0],
+                            });
+                            if (i === this.props.pdf.numPages - 1) {
+                                this.props.loaded?.(page.view[page0or180 ? 2 : 3] - page.view[page0or180 ? 0 : 1], page.view[page0or180 ? 3 : 2] - page.view[page0or180 ? 1 : 0], this.props.pdf.numPages);
+                            }
+                        })
+                    )
+                )
+            );
+            this.props.Document.scrollHeight = (this._pageSizes.reduce((size, page) => size + page.height, 0) * 96) / 72;
         }
-    }
+    };
 
     // scrolls to focus on a nested annotation document.  if this is part a link preview then it will jump to the scroll location,
     // otherwise it will scroll smoothly.
@@ -153,7 +163,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         let focusSpeed: Opt<number>;
         if (doc !== this.props.rootDoc && mainCont) {
             const windowHeight = this.props.PanelHeight() / (this.props.scaling?.() || 1);
-            const scrollTo = doc.unrendered ? NumCast(doc.y) : Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, .1 * windowHeight, NumCast(this.props.Document.scrollHeight));
+            const scrollTo = doc.unrendered ? NumCast(doc.y) : Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, 0.1 * windowHeight, NumCast(this.props.Document.scrollHeight));
             if (scrollTo !== undefined && scrollTo !== this.props.layoutDoc._scrollTop) {
                 focusSpeed = 500;
 
@@ -165,10 +175,10 @@ export class PDFViewer extends React.Component<IViewerProps> {
             this._initialScroll = NumCast(this.props.layoutDoc._scrollTop);
         }
         return focusSpeed;
-    }
+    };
     crop = (region: Doc | undefined, addCrop?: boolean) => {
         return this.props.crop(region, addCrop);
-    }
+    };
 
     @action
     setupPdfJsViewer = async () => {
@@ -179,18 +189,18 @@ export class PDFViewer extends React.Component<IViewerProps> {
         await this.initialLoad();
 
         this.createPdfViewer();
-    }
+    };
 
     pagesinit = () => {
         if (this._pdfViewer._setDocumentViewerElement?.offsetParent) {
-            runInAction(() => this._pdfViewer.currentScaleValue = this.props.layoutDoc._viewScale = 1);
+            runInAction(() => (this._pdfViewer.currentScaleValue = this.props.layoutDoc._viewScale = 1));
             this.gotoPage(NumCast(this.props.Document._curPage, 1));
         }
-        document.removeEventListener("pagesinit", this.pagesinit);
-        var quickScroll: string | undefined = this._initialScroll ? this._initialScroll.toString() : "";
+        document.removeEventListener('pagesinit', this.pagesinit);
+        var quickScroll: string | undefined = this._initialScroll ? this._initialScroll.toString() : '';
         this._disposers.scroll = reaction(
             () => Math.abs(NumCast(this.props.Document._scrollTop)),
-            (pos) => {
+            pos => {
                 if (!this._ignoreScroll) {
                     this._showWaiting && this.setupPdfJsViewer();
                     const viewTrans = quickScroll ?? StrCast(this.props.Document._viewTransition);
@@ -199,10 +209,13 @@ export class PDFViewer extends React.Component<IViewerProps> {
                     const duration = durationMiliStr ? Number(durationMiliStr[1]) : durationSecStr ? Number(durationSecStr[1]) * 1000 : 0;
                     this._forcedScroll = true;
                     if (duration) {
-                        setTimeout(() => {
-                            this._mainCont.current && smoothScroll(duration, this._mainCont.current, pos);
-                            setTimeout(() => this._forcedScroll = false, duration);
-                        }, this._mainCont.current ? 0 : 250); // wait for mainCont and try again to scroll
+                        setTimeout(
+                            () => {
+                                this._mainCont.current && smoothScroll(duration, this._mainCont.current, pos);
+                                setTimeout(() => (this._forcedScroll = false), duration);
+                            },
+                            this._mainCont.current ? 0 : 250
+                        ); // wait for mainCont and try again to scroll
                     } else {
                         this._mainCont.current?.scrollTo({ top: pos });
                         this._forcedScroll = false;
@@ -216,23 +229,27 @@ export class PDFViewer extends React.Component<IViewerProps> {
             this._mainCont.current?.scrollTo({ top: Math.abs(this._initialScroll || 0) });
             this._initialScroll = undefined;
         }
-    }
+    };
 
     createPdfViewer() {
-        if (!this._mainCont.current) { // bcz: I don't think this is ever triggered or needed
-            console.log("PDFViewer- I guess we got here");
+        if (!this._mainCont.current) {
+            // bcz: I don't think this is ever triggered or needed
+            console.log('PDFViewer- I guess we got here');
             if (this._retries < 5) {
                 this._retries++;
-                console.log("PDFViewer- retry num:" + this._retries);
+                console.log('PDFViewer- retry num:' + this._retries);
                 setTimeout(() => this.createPdfViewer(), 1000);
             }
             return;
         }
-        document.removeEventListener("copy", this.copy);
-        document.addEventListener("copy", this.copy);
+        document.removeEventListener('copy', this.copy);
+        document.addEventListener('copy', this.copy);
         const eventBus = new PDFJSViewer.EventBus(true);
-        eventBus._on("pagesinit", this.pagesinit);
-        eventBus._on("pagerendered", action(() => this._showWaiting = false));
+        eventBus._on('pagesinit', this.pagesinit);
+        eventBus._on(
+            'pagerendered',
+            action(() => (this._showWaiting = false))
+        );
         const pdfLinkService = new PDFJSViewer.PDFLinkService({ eventBus });
         const pdfFindController = new PDFJSViewer.PDFFindController({ linkService: pdfLinkService, eventBus });
         this._pdfViewer = new PDFJSViewer.PDFViewer({
@@ -240,31 +257,30 @@ export class PDFViewer extends React.Component<IViewerProps> {
             viewer: this._viewer.current,
             linkService: pdfLinkService,
             findController: pdfFindController,
-            renderer: "canvas",
-            eventBus
+            renderer: 'canvas',
+            eventBus,
         });
         pdfLinkService.setViewer(this._pdfViewer);
         pdfLinkService.setDocument(this.props.pdf, null);
         this._pdfViewer.setDocument(this.props.pdf);
     }
 
-
     @action
     prevAnnotation = () => {
         this.Index = Math.max(this.Index - 1, 0);
         this.scrollToAnnotation(this.allAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y))[this.Index]);
-    }
+    };
 
     @action
     nextAnnotation = () => {
         this.Index = Math.min(this.Index + 1, this.allAnnotations.length - 1);
         this.scrollToAnnotation(this.allAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y))[this.Index]);
-    }
+    };
 
     @action
     gotoPage = (p: number) => {
         this._pdfViewer?.scrollPageIntoView({ pageNumber: Math.min(Math.max(1, p), this._pageSizes.length) });
-    }
+    };
 
     @action
     scrollToAnnotation = (scrollToAnnotation: Doc) => {
@@ -272,7 +288,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
             this.scrollFocus(scrollToAnnotation, true);
             Doc.linkFollowHighlight(scrollToAnnotation);
         }
-    }
+    };
 
     @observable private _scrollTimer: any;
 
@@ -289,7 +305,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 this._scrollTimer = undefined;
             }, 200);
         }
-    }
+    };
 
     // get the page index that the vertical offset passed in is on
     getPageFromScroll = (vOffset: number) => {
@@ -299,7 +315,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
             currOffset -= this._pageSizes[index++].height;
         }
         return index;
-    }
+    };
 
     @action
     search = (searchString: string, bwd?: boolean, clear: boolean = false) => {
@@ -308,22 +324,21 @@ export class PDFViewer extends React.Component<IViewerProps> {
             findPrevious: bwd,
             highlightAll: true,
             phraseSearch: true,
-            query: searchString
+            query: searchString,
         };
         if (clear) {
-            this._pdfViewer?.findController.executeCommand('reset', { query: "" });
+            this._pdfViewer?.findController.executeCommand('reset', { query: '' });
         } else if (!searchString) {
             bwd ? this.prevAnnotation() : this.nextAnnotation();
         } else if (this._pdfViewer?.pageViewsReady) {
             this._pdfViewer.findController.executeCommand('findagain', findOpts);
-        }
-        else if (this._mainCont.current) {
+        } else if (this._mainCont.current) {
             const executeFind = () => this._pdfViewer.findController.executeCommand('find', findOpts);
-            this._mainCont.current.addEventListener("pagesloaded", executeFind);
-            this._mainCont.current.addEventListener("pagerendered", executeFind);
+            this._mainCont.current.addEventListener('pagesloaded', executeFind);
+            this._mainCont.current.addEventListener('pagerendered', executeFind);
         }
         return true;
-    }
+    };
 
     @action
     onPointerDown = (e: React.PointerEvent): void => {
@@ -340,24 +355,27 @@ export class PDFViewer extends React.Component<IViewerProps> {
         if ((e.button !== 0 || e.altKey) && this.props.isContentActive(true)) {
             this._setPreviewCursor?.(e.clientX, e.clientY, true, false);
         }
-        if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool)) {
+        if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
             this.props.select(false);
             MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
             this._marqueeing = [e.clientX, e.clientY];
             this.isAnnotating = true;
-            if (e.target && ((e.target as any).className.includes("endOfContent") || ((e.target as any).parentElement.className !== "textLayer"))) {
+            if (e.target && ((e.target as any).className.includes('endOfContent') || (e.target as any).parentElement.className !== 'textLayer')) {
                 this._textSelecting = false;
-                document.addEventListener("pointermove", this.onSelectMove); // need this to prevent document from being dragged if stopPropagation doesn't get called
+                document.addEventListener('pointermove', this.onSelectMove); // need this to prevent document from being dragged if stopPropagation doesn't get called
             } else {
                 // if textLayer is hit, then we select text instead of using a marquee so clear out the marquee.
-                setTimeout(action(() => this._marqueeing = undefined), 100); // bcz: hack .. anchor menu is setup within MarqueeAnnotator so we need to at least create the marqueeAnnotator even though we aren't using it.
-
-                this._styleRule = addStyleSheetRule(PDFViewer._annotationStyle, "htmlAnnotation", { "pointer-events": "none" });
-                document.addEventListener("pointerup", this.onSelectEnd);
-                document.addEventListener("pointermove", this.onSelectMove);
+                setTimeout(
+                    action(() => (this._marqueeing = undefined)),
+                    100
+                ); // bcz: hack .. anchor menu is setup within MarqueeAnnotator so we need to at least create the marqueeAnnotator even though we aren't using it.
+
+                this._styleRule = addStyleSheetRule(PDFViewer._annotationStyle, 'htmlAnnotation', { 'pointer-events': 'none' });
+                document.addEventListener('pointerup', this.onSelectEnd);
+                document.addEventListener('pointermove', this.onSelectMove);
             }
         }
-    }
+    };
 
     @action
     finishMarquee = (x?: number, y?: number) => {
@@ -365,8 +383,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
         this.isAnnotating = false;
         this._marqueeing = undefined;
         this._textSelecting = true;
-        document.removeEventListener("pointermove", this.onSelectMove);
-    }
+        document.removeEventListener('pointermove', this.onSelectMove);
+    };
 
     onSelectMove = (e: PointerEvent) => e.stopPropagation();
 
@@ -375,15 +393,15 @@ export class PDFViewer extends React.Component<IViewerProps> {
         this.isAnnotating = false;
         clearStyleSheetRules(PDFViewer._annotationStyle);
         this.props.select(false);
-        document.removeEventListener("pointermove", this.onSelectMove);
-        document.removeEventListener("pointerup", this.onSelectEnd);
+        document.removeEventListener('pointermove', this.onSelectMove);
+        document.removeEventListener('pointerup', this.onSelectEnd);
 
         const sel = window.getSelection();
-        if (sel?.type === "Range") {
+        if (sel?.type === 'Range') {
             this.createTextAnnotation(sel, sel.getRangeAt(0));
             AnchorMenu.Instance.jumpTo(e.clientX, e.clientY);
         }
-    }
+    };
 
     @action
     createTextAnnotation = (sel: Selection, selRange: Range) => {
@@ -395,41 +413,41 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 if (rect && rect.width !== this._mainCont.current.clientWidth && rect.width) {
                     const scaleX = this._mainCont.current.offsetWidth / boundingRect.width;
                     const pdfScale = NumCast(this.props.layoutDoc._viewScale, 1);
-                    const annoBox = document.createElement("div");
-                    annoBox.className = "marqueeAnnotator-annotationBox";
+                    const annoBox = document.createElement('div');
+                    annoBox.className = 'marqueeAnnotator-annotationBox';
                     // transforms the positions from screen onto the pdf div
-                    annoBox.style.top = ((rect.top - boundingRect.top) * scaleX / pdfScale + this._mainCont.current.scrollTop).toString();
-                    annoBox.style.left = ((rect.left - boundingRect.left) * scaleX / pdfScale).toString();
-                    annoBox.style.width = (rect.width * this._mainCont.current.offsetWidth / boundingRect.width / pdfScale).toString();
-                    annoBox.style.height = (rect.height * this._mainCont.current.offsetHeight / boundingRect.height / pdfScale).toString();
+                    annoBox.style.top = (((rect.top - boundingRect.top) * scaleX) / pdfScale + this._mainCont.current.scrollTop).toString();
+                    annoBox.style.left = (((rect.left - boundingRect.left) * scaleX) / pdfScale).toString();
+                    annoBox.style.width = ((rect.width * this._mainCont.current.offsetWidth) / boundingRect.width / pdfScale).toString();
+                    annoBox.style.height = ((rect.height * this._mainCont.current.offsetHeight) / boundingRect.height / pdfScale).toString();
                     this._annotationLayer.current && MarqueeAnnotator.previewNewAnnotation(this._savedAnnotations, this._annotationLayer.current, annoBox, this.getPageFromScroll(rect.top));
                 }
             }
         }
-        this._selectionText = selRange.cloneContents().textContent || "";
+        this._selectionText = selRange.cloneContents().textContent || '';
 
         // clear selection
-        if (sel.empty) {  // Chrome
+        if (sel.empty) {
+            // Chrome
             sel.empty();
-        } else if (sel.removeAllRanges) {  // Firefox
+        } else if (sel.removeAllRanges) {
+            // Firefox
             sel.removeAllRanges();
         }
-    }
+    };
 
     scrollXf = () => {
         return this._mainCont.current ? this.props.ScreenToLocalTransform().translate(0, NumCast(this.props.layoutDoc._scrollTop)) : this.props.ScreenToLocalTransform();
-    }
+    };
 
     onClick = (e: React.MouseEvent) => {
-        if (this._setPreviewCursor && e.button === 0 &&
-            Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
-            Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
+        if (this._setPreviewCursor && e.button === 0 && Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
             this._setPreviewCursor(e.clientX, e.clientY, false, false);
         }
         // e.stopPropagation();  // bcz: not sure why this was here.  We need to allow the DocumentView to get clicks to process doubleClicks
-    }
+    };
 
-    setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => this._setPreviewCursor = func;
+    setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => (this._setPreviewCursor = func);
 
     @action
     onZoomWheel = (e: React.WheelEvent) => {
@@ -437,52 +455,59 @@ export class PDFViewer extends React.Component<IViewerProps> {
             e.stopPropagation();
             if (e.ctrlKey) {
                 const curScale = Number(this._pdfViewer.currentScaleValue);
-                this._pdfViewer.currentScaleValue = Math.max(1, Math.min(10, curScale - curScale * e.deltaY / 1000));
+                this._pdfViewer.currentScaleValue = Math.max(1, Math.min(10, curScale - (curScale * e.deltaY) / 1000));
                 this.props.layoutDoc._viewScale = Number(this._pdfViewer.currentScaleValue);
             }
         }
-    }
+    };
 
-    pointerEvents = () => this.props.isContentActive() && this.props.pointerEvents?.() !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none";
+    pointerEvents = () => (this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none');
     @computed get annotationLayer() {
-        return <div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this.props.Document), transform: `scale(${NumCast(this.props.layoutDoc._viewScale, 1)})` }} ref={this._annotationLayer}>
-            {this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno =>
-                <Annotation {...this.props} fieldKey={this.props.fieldKey + "-annotations"} pointerEvents={this.pointerEvents} showInfo={this.showInfo} dataDoc={this.props.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} />)}
-        </div>;
+        return (
+            <div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this.props.Document), transform: `scale(${NumCast(this.props.layoutDoc._viewScale, 1)})` }} ref={this._annotationLayer}>
+                {this.inlineTextAnnotations
+                    .sort((a, b) => NumCast(a.y) - NumCast(b.y))
+                    .map(anno => (
+                        <Annotation {...this.props} fieldKey={this.props.fieldKey + '-annotations'} pointerEvents={this.pointerEvents} showInfo={this.showInfo} dataDoc={this.props.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} />
+                    ))}
+            </div>
+        );
     }
 
     @computed get overlayInfo() {
-        return !this._overlayAnnoInfo ? (null) :
+        return !this._overlayAnnoInfo ? null : (
             <div className="pdfViewerDash-overlayAnno" style={{ top: NumCast(this._overlayAnnoInfo.y), left: NumCast(this._overlayAnnoInfo.x) }}>
                 <div className="pdfViewerDash-overlayAnno" style={{ right: -50, background: SharingManager.Instance.users.find(users => users.user.email === this._overlayAnnoInfo!.author)?.userColor }}>
-                    {this._overlayAnnoInfo.author + " " + Field.toString(this._overlayAnnoInfo.creationDate as Field)}
+                    {this._overlayAnnoInfo.author + ' ' + Field.toString(this._overlayAnnoInfo.creationDate as Field)}
                 </div>
-            </div>;
+            </div>
+        );
     }
 
-    showInfo = action((anno: Opt<Doc>) => this._overlayAnnoInfo = anno);
+    showInfo = action((anno: Opt<Doc>) => (this._overlayAnnoInfo = anno));
     overlayTransform = () => this.scrollXf().scale(1 / NumCast(this.props.layoutDoc._viewScale, 1));
     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);
-    basicFilter = () => [...this.props.docFilters(), Utils.PropUnsetFilter("textInlineAnnotations")];
+    basicFilter = () => [...this.props.docFilters(), Utils.PropUnsetFilter('textInlineAnnotations')];
     transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
     opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
-    childStyleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps>, property: string): any => {
+    childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
         if (doc instanceof Doc && property === StyleProp.PointerEvents) {
-            if (doc.textInlineAnnotations) return "none";
-            return "all";
+            if (doc.textInlineAnnotations) return 'none';
+            return 'all';
         }
         return this.props.styleProvider?.(doc, props, property);
-    }
+    };
 
-    renderAnnotations = (docFilters?: () => string[], dontRender?: boolean) =>
-        <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
+    renderAnnotations = (docFilters?: () => string[], dontRender?: boolean) => (
+        <CollectionFreeFormView
+            {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
             isAnnotationOverlay={true}
-            fieldKey={this.props.fieldKey + "-annotations"}
+            fieldKey={this.props.fieldKey + '-annotations'}
             setPreviewCursor={this.setPreviewCursor}
             PanelHeight={this.panelHeight}
             PanelWidth={this.panelWidth}
-            dropAction={"alias"}
+            dropAction={'alias'}
             select={emptyFunction}
             ContentScaling={this.contentZoom}
             bringToFront={emptyFunction}
@@ -493,70 +518,88 @@ export class PDFViewer extends React.Component<IViewerProps> {
             ScreenToLocalTransform={this.overlayTransform}
             renderDepth={this.props.renderDepth + 1}
         />
-    @computed get overlayTransparentAnnotations() { return this.renderAnnotations(this.transparentFilter, false); }
-    @computed get overlayOpaqueAnnotations() { return this.renderAnnotations(this.opaqueFilter, false); }
+    );
+    @computed get overlayTransparentAnnotations() {
+        return this.renderAnnotations(this.transparentFilter, false);
+    }
+    @computed get overlayOpaqueAnnotations() {
+        return this.renderAnnotations(this.opaqueFilter, false);
+    }
     @computed get overlayClickableAnnotations() {
-        return <div style={{ height: NumCast(this.props.rootDoc.scrollHeight) }}>
-            {this.renderAnnotations(undefined, true)}
-        </div>;
+        return <div style={{ height: NumCast(this.props.rootDoc.scrollHeight) }}>{this.renderAnnotations(undefined, true)}</div>;
     }
     @computed get overlayLayer() {
-        return <div style={{ pointerEvents: SnappingManager.GetIsDragging() ? "all" : "none" }}>
-            <div className="pdfViewerDash-overlay"
-                style={{
-                    pointerEvents: SnappingManager.GetIsDragging() ? "all" : "none",
-                    mixBlendMode: "multiply",
-                    transform: `scale(${NumCast(this.props.layoutDoc._viewScale, 1)})`
-                }}>
-                {this.overlayTransparentAnnotations}
-            </div>
-            <div className="pdfViewerDash-overlay"
-                style={{
-                    pointerEvents: SnappingManager.GetIsDragging() ? "all" : "none",
-                    mixBlendMode: this.allAnnotations.some(anno => anno.mixBlendMode) ? "hard-light" : undefined,
-                    transform: `scale(${NumCast(this.props.layoutDoc._viewScale, 1)})`
-                }}>
-                {this.overlayOpaqueAnnotations}
-                {this.overlayClickableAnnotations}
+        return (
+            <div style={{ pointerEvents: SnappingManager.GetIsDragging() ? 'all' : 'none' }}>
+                <div
+                    className="pdfViewerDash-overlay"
+                    style={{
+                        pointerEvents: SnappingManager.GetIsDragging() ? 'all' : 'none',
+                        mixBlendMode: 'multiply',
+                        transform: `scale(${NumCast(this.props.layoutDoc._viewScale, 1)})`,
+                    }}>
+                    {this.overlayTransparentAnnotations}
+                </div>
+                <div
+                    className="pdfViewerDash-overlay"
+                    style={{
+                        pointerEvents: SnappingManager.GetIsDragging() ? 'all' : 'none',
+                        mixBlendMode: this.allAnnotations.some(anno => anno.mixBlendMode) ? 'hard-light' : undefined,
+                        transform: `scale(${NumCast(this.props.layoutDoc._viewScale, 1)})`,
+                    }}>
+                    {this.overlayOpaqueAnnotations}
+                    {this.overlayClickableAnnotations}
+                </div>
             </div>
-        </div>;
+        );
     }
     @computed get pdfViewerDiv() {
-        return <div className={"pdfViewerDash-text" + (this.props.pointerEvents?.() !== "none" && this._textSelecting && this.props.isContentActive() ? "-selected" : "")} ref={this._viewer} />;
+        return <div className={'pdfViewerDash-text' + (this.props.pointerEvents?.() !== 'none' && this._textSelecting && this.props.isContentActive() ? '-selected' : '')} ref={this._viewer} />;
+    }
+    @computed get contentScaling() {
+        return this.props.ContentScaling?.() || 1;
     }
-    @computed get contentScaling() { return this.props.ContentScaling?.() || 1; }
     contentZoom = () => NumCast(this.props.layoutDoc._viewScale, 1);
     savedAnnotations = () => this._savedAnnotations;
     render() {
         TraceMobx();
-        return <div className="pdfViewer-content">
-            <div className={`pdfViewerDash${this.props.isContentActive() && this.props.pointerEvents?.() !== "none" ? "-interactive" : ""}`} ref={this._mainCont}
-                onScroll={this.onScroll} onWheel={this.onZoomWheel} onPointerDown={this.onPointerDown} onClick={this.onClick}
-                style={{
-                    overflowX: NumCast(this.props.layoutDoc._viewScale, 1) !== 1 ? "scroll" : undefined,
-                    height: !this.props.Document._fitWidth && (window.screen.width > 600) ? Doc.NativeHeight(this.props.Document) : `${100 / this.contentScaling}%`,
-                    transform: `scale(${this.contentScaling})`
-                }}  >
-                {this.pdfViewerDiv}
-                {this.annotationLayer}
-                {this.overlayLayer}
-                {this.overlayInfo}
-                {this._showWaiting ? <img className="pdfViewerDash-waiting" src={"/assets/loading.gif"} /> : (null)}
-                {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? (null) :
-                    <MarqueeAnnotator rootDoc={this.props.rootDoc}
-                        getPageFromScroll={this.getPageFromScroll}
-                        anchorMenuClick={this.props.anchorMenuClick}
-                        scrollTop={0}
-                        down={this._marqueeing}
-                        addDocument={(doc: Doc | Doc[]) => this.props.addDocument!(doc)}
-                        docView={this.props.docViewPath().lastElement()}
-                        finishMarquee={this.finishMarquee}
-                        savedAnnotations={this.savedAnnotations}
-                        annotationLayer={this._annotationLayer.current}
-                        mainCont={this._mainCont.current}
-                        anchorMenuCrop={this._textSelecting ? undefined : this.crop}
-                    />}
+        return (
+            <div className="pdfViewer-content">
+                <div
+                    className={`pdfViewerDash${this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' ? '-interactive' : ''}`}
+                    ref={this._mainCont}
+                    onScroll={this.onScroll}
+                    onWheel={this.onZoomWheel}
+                    onPointerDown={this.onPointerDown}
+                    onClick={this.onClick}
+                    style={{
+                        overflowX: NumCast(this.props.layoutDoc._viewScale, 1) !== 1 ? 'scroll' : undefined,
+                        height: !this.props.Document._fitWidth && window.screen.width > 600 ? Doc.NativeHeight(this.props.Document) : `${100 / this.contentScaling}%`,
+                        transform: `scale(${this.contentScaling})`,
+                    }}>
+                    {this.pdfViewerDiv}
+                    {this.annotationLayer}
+                    {this.overlayLayer}
+                    {this.overlayInfo}
+                    {this._showWaiting ? <img className="pdfViewerDash-waiting" src={'/assets/loading.gif'} /> : null}
+                    {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : (
+                        <MarqueeAnnotator
+                            rootDoc={this.props.rootDoc}
+                            getPageFromScroll={this.getPageFromScroll}
+                            anchorMenuClick={this.props.anchorMenuClick}
+                            scrollTop={0}
+                            down={this._marqueeing}
+                            addDocument={(doc: Doc | Doc[]) => this.props.addDocument!(doc)}
+                            docView={this.props.docViewPath().lastElement()}
+                            finishMarquee={this.finishMarquee}
+                            savedAnnotations={this.savedAnnotations}
+                            annotationLayer={this._annotationLayer.current}
+                            mainCont={this._mainCont.current}
+                            anchorMenuCrop={this._textSelecting ? undefined : this.crop}
+                        />
+                    )}
+                </div>
             </div>
-        </div>;
+        );
     }
-}
\ No newline at end of file
+}
-- 
cgit v1.2.3-70-g09d2


From 358f9e266ef264442aea1e2c7d5d959a19f7624c Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 22 Jul 2022 14:11:30 -0400
Subject: adjusted native dim scaling slightly combining props.scaling and
 props.ContentScaling into props.NativeDimScaling and fixing some resizing
 behaviors for fitWidth freeformviews and native-sized text boxes.   Also
 fixed clicking on presboxe elements to not drag.

---
 src/client/views/DocumentDecorations.tsx           |   3 +-
 src/client/views/InkingStroke.tsx                  | 536 +++++++++++++--------
 src/client/views/SidebarAnnos.tsx                  |   4 +-
 src/client/views/StyleProvider.tsx                 |   4 +-
 .../collections/CollectionStackedTimeline.tsx      |   2 +-
 .../views/collections/CollectionTreeView.tsx       |  11 +-
 src/client/views/collections/TreeView.tsx          |   6 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  30 +-
 .../CollectionMulticolumnView.tsx                  | 187 +++----
 .../CollectionMultirowView.tsx                     | 180 +++----
 src/client/views/nodes/DocumentContentsView.tsx    |   5 +-
 src/client/views/nodes/DocumentLinksButton.tsx     | 384 ++++++++-------
 src/client/views/nodes/DocumentView.tsx            |  24 +-
 src/client/views/nodes/EquationBox.tsx             |  90 ++--
 src/client/views/nodes/FieldView.tsx               |  55 ++-
 src/client/views/nodes/ImageBox.tsx                |  10 +-
 src/client/views/nodes/MapBox/MapBox.tsx           |   9 +-
 src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx |   2 +-
 src/client/views/nodes/PDFBox.tsx                  |  12 +-
 src/client/views/nodes/ScreenshotBox.tsx           |   4 +-
 src/client/views/nodes/VideoBox.tsx                |   6 +-
 src/client/views/nodes/WebBox.tsx                  |  25 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  10 +-
 src/client/views/nodes/trails/PresElementBox.tsx   |   8 +-
 src/client/views/pdf/PDFViewer.tsx                 |  17 +-
 25 files changed, 883 insertions(+), 741 deletions(-)

(limited to 'src/client/views/pdf/PDFViewer.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 780dcfb6d..964fd36c8 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -521,7 +521,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                             } else doc._height = actualdH;
                         }
                     } else {
-                        dH && (doc._height = actualdH);
+                        const maxHeight = Math.max(nheight, NumCast(doc.scrollHeight)) * docView.NativeDimScaling();
+                        dH && (doc._height = actualdH > maxHeight ? maxHeight : actualdH);
                         dW && (doc._width = actualdW);
                         dH && (doc._autoHeight = false);
                     }
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index dace9716a..e5de7a0c5 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -20,35 +20,37 @@
     
     Most of the operations that can be performed on an InkStroke (eg delete a point, rotate, stretch) are implemented in the InkStrokeProperties helper class
 */
-import React = require("react");
-import { action, IReactionDisposer, observable, reaction } from "mobx";
-import { observer } from "mobx-react";
-import { Doc, WidthSym } from "../../fields/Doc";
-import { InkData, InkField, InkTool } from "../../fields/InkField";
-import { Cast, NumCast, RTFCast, StrCast } from "../../fields/Types";
-import { TraceMobx } from "../../fields/util";
-import { OmitKeys, returnFalse, setupMoveUpEvents } from "../../Utils";
-import { CognitiveServices } from "../cognitive_services/CognitiveServices";
-import { InteractionUtils } from "../util/InteractionUtils";
-import { SnappingManager } from "../util/SnappingManager";
-import { Transform } from "../util/Transform";
-import { UndoManager } from "../util/UndoManager";
-import { ContextMenu } from "./ContextMenu";
-import { ViewBoxBaseComponent } from "./DocComponent";
-import { Colors } from "./global/globalEnums";
-import { InkControlPtHandles, InkEndPtHandles } from "./InkControlPtHandles";
-import { InkStrokeProperties } from "./InkStrokeProperties";
-import { InkTangentHandles } from "./InkTangentHandles";
-import { DocComponentView } from "./nodes/DocumentView";
-import { FieldView, FieldViewProps } from "./nodes/FieldView";
-import { FormattedTextBox } from "./nodes/formattedText/FormattedTextBox";
-import "./InkStroke.scss";
-import Color = require("color");
+import React = require('react');
+import { action, IReactionDisposer, observable, reaction } from 'mobx';
+import { observer } from 'mobx-react';
+import { Doc, WidthSym } from '../../fields/Doc';
+import { InkData, InkField, InkTool } from '../../fields/InkField';
+import { Cast, NumCast, RTFCast, StrCast } from '../../fields/Types';
+import { TraceMobx } from '../../fields/util';
+import { OmitKeys, returnFalse, setupMoveUpEvents } from '../../Utils';
+import { CognitiveServices } from '../cognitive_services/CognitiveServices';
+import { InteractionUtils } from '../util/InteractionUtils';
+import { SnappingManager } from '../util/SnappingManager';
+import { Transform } from '../util/Transform';
+import { UndoManager } from '../util/UndoManager';
+import { ContextMenu } from './ContextMenu';
+import { ViewBoxBaseComponent } from './DocComponent';
+import { Colors } from './global/globalEnums';
+import { InkControlPtHandles, InkEndPtHandles } from './InkControlPtHandles';
+import { InkStrokeProperties } from './InkStrokeProperties';
+import { InkTangentHandles } from './InkTangentHandles';
+import { DocComponentView } from './nodes/DocumentView';
+import { FieldView, FieldViewProps } from './nodes/FieldView';
+import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
+import './InkStroke.scss';
+import Color = require('color');
 
 @observer
 export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
     static readonly MaskDim = 50000; // choose a really big number to make sure mask fits over container (which in theory can be arbitrarily big)
-    public static LayoutString(fieldStr: string) { return FieldView.LayoutString(InkingStroke, fieldStr); }
+    public static LayoutString(fieldStr: string) {
+        return FieldView.LayoutString(InkingStroke, fieldStr);
+    }
     public static IsClosed(inkData: InkData) {
         return inkData && inkData.lastElement().X === inkData[0].X && inkData.lastElement().Y === inkData[0].Y;
     }
@@ -56,13 +58,15 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
     private _selDisposer?: IReactionDisposer;
 
     @observable _nearestSeg?: number; // nearest Bezier segment along the ink stroke to the cursor (used for displaying the Add Point highlight)
-    @observable _nearestT?: number;  // nearest t value within the nearest Bezier segment "
-    @observable _nearestScrPt?: { X: number, Y: number }; // nearst screen point on the ink stroke ""
+    @observable _nearestT?: number; // nearest t value within the nearest Bezier segment "
+    @observable _nearestScrPt?: { X: number; Y: number }; // nearst screen point on the ink stroke ""
 
     componentDidMount() {
         this.props.setContentView?.(this);
-        this._selDisposer = reaction(() => this.props.isSelected(), // react to stroke being deselected by turning off ink handles
-            selected => !selected && (InkStrokeProperties.Instance._controlButton = false));
+        this._selDisposer = reaction(
+            () => this.props.isSelected(), // react to stroke being deselected by turning off ink handles
+            selected => !selected && (InkStrokeProperties.Instance._controlButton = false)
+        );
     }
     componentWillUnmount() {
         this._selDisposer?.();
@@ -70,36 +74,36 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
 
     // transform is the inherited screentolocal xf plus any scaling that was done to make the stroke
     // fit within its panel (e.g., for content fitting views like Lightbox or multicolumn, etc)
-    screenToLocal = () => this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1);
+    screenToLocal = () => this.props.ScreenToLocalTransform().scale(this.props.NativeDimScaling?.() || 1);
 
     getAnchor = () => {
         console.log(document.activeElement);
         return this._subContentView?.getAnchor?.() || this.rootDoc;
-    }
+    };
 
     scrollFocus = (textAnchor: Doc, smooth: boolean) => {
         return this._subContentView?.scrollFocus?.(textAnchor, smooth);
-    }
+    };
     /**
-    * @returns the center of the ink stroke in the ink document's coordinate space (not screen space, and not the ink data coordinate space); 
-    * DocumentDecorations calls getBounds() on DocumentViews which call getCenter() if defined - in the case of ink it needs to be defined since
-    * the center of the ink stroke changes as the stroke is rotated.
-    */
+     * @returns the center of the ink stroke in the ink document's coordinate space (not screen space, and not the ink data coordinate space);
+     * DocumentDecorations calls getBounds() on DocumentViews which call getCenter() if defined - in the case of ink it needs to be defined since
+     * the center of the ink stroke changes as the stroke is rotated.
+     */
     getCenter = (xf: Transform) => {
         const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData();
         const angle = -NumCast(this.layoutDoc.rotation);
         const newPoints = inkData.map(pt => {
-            const newX = Math.cos(angle) * pt.X - Math.sin(angle) * pt.Y * inkScaleY / inkScaleX;
-            const newY = Math.sin(angle) * pt.X * inkScaleX / inkScaleY + Math.cos(angle) * pt.Y;
+            const newX = Math.cos(angle) * pt.X - (Math.sin(angle) * pt.Y * inkScaleY) / inkScaleX;
+            const newY = (Math.sin(angle) * pt.X * inkScaleX) / inkScaleY + Math.cos(angle) * pt.Y;
             return { X: newX, Y: newY };
         });
         const crx = (Math.max(...newPoints.map(np => np.X)) + Math.min(...newPoints.map(np => np.X))) / 2;
         const cry = (Math.max(...newPoints.map(np => np.Y)) + Math.min(...newPoints.map(np => np.Y))) / 2;
-        const cx = Math.cos(-angle) * crx - Math.sin(-angle) * cry * inkScaleY / inkScaleX;
-        const cy = Math.sin(-angle) * crx * inkScaleX / inkScaleY + Math.cos(-angle) * cry;
+        const cx = Math.cos(-angle) * crx - (Math.sin(-angle) * cry * inkScaleY) / inkScaleX;
+        const cy = (Math.sin(-angle) * crx * inkScaleX) / inkScaleY + Math.cos(-angle) * cry;
         const tc = xf.transformPoint((cx - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (cy - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2);
         return { X: tc[0], Y: tc[1] };
-    }
+    };
 
     /**
      * analyzes the ink stroke and saves the analysis of the stroke to the 'inkAnalysis' field,
@@ -107,7 +111,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
      */
     analyzeStrokes() {
         const data: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? [];
-        CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.dataDoc, ["inkAnalysis", "handwriting"], [data]);
+        CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.dataDoc, ['inkAnalysis', 'handwriting'], [data]);
     }
 
     /**
@@ -115,12 +119,12 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
      *    When displayed as a mask, the stroke is rendered with mixBlendMode set to multiply so that the stroke will
      *  appear to illuminate what it covers up.  At the same time, all pixels that are not under the stroke will be
      *  dimmed by a semi-opaque overlay mask.
-    */
+     */
     public static toggleMask = action((inkDoc: Doc) => {
         inkDoc.isInkMask = !inkDoc.isInkMask;
-        inkDoc._backgroundColor = inkDoc.isInkMask ? "rgba(0,0,0,0.7)" : undefined;
-        inkDoc.mixBlendMode = inkDoc.isInkMask ? "hard-light" : undefined;
-        inkDoc.color = "#9b9b9bff";
+        inkDoc._backgroundColor = inkDoc.isInkMask ? 'rgba(0,0,0,0.7)' : undefined;
+        inkDoc.mixBlendMode = inkDoc.isInkMask ? 'hard-light' : undefined;
+        inkDoc.color = '#9b9b9bff';
         inkDoc._stayInCollection = inkDoc.isInkMask ? true : undefined;
     });
     /**
@@ -132,46 +136,60 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
         this._handledClick = false;
         const inkView = this.props.docViewPath().lastElement();
         const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData();
-        const screenPts = inkData.map(point => this.screenToLocal().inverse().transformPoint(
-            (point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2,
-            (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2)).map(p => ({ X: p[0], Y: p[1] }));
+        const screenPts = inkData
+            .map(point =>
+                this.screenToLocal()
+                    .inverse()
+                    .transformPoint((point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2)
+            )
+            .map(p => ({ X: p[0], Y: p[1] }));
         const { nearestSeg } = InkStrokeProperties.nearestPtToStroke(screenPts, { X: e.clientX, Y: e.clientY });
         const controlIndex = nearestSeg;
         const wasSelected = InkStrokeProperties.Instance._currentPoint === controlIndex;
         var controlUndo: UndoManager.Batch | undefined;
         const isEditing = InkStrokeProperties.Instance._controlButton && this.props.isSelected();
-        setupMoveUpEvents(this, e,
-            !isEditing ? returnFalse : action((e: PointerEvent, down: number[], delta: number[]) => {
-                if (!controlUndo) controlUndo = UndoManager.StartBatch("drag ink ctrl pt");
-                const inkMoveEnd = this.ptFromScreen({ X: delta[0], Y: delta[1] });
-                const inkMoveStart = this.ptFromScreen({ X: 0, Y: 0 });
-                InkStrokeProperties.Instance.moveControlPtHandle(inkView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex);
-                InkStrokeProperties.Instance.moveControlPtHandle(inkView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex + 3);
-                return false;
-            }),
-            !isEditing ? returnFalse : action(() => {
-                controlUndo?.end();
-                controlUndo = undefined;
-                UndoManager.FilterBatches(["data", "x", "y", "width", "height"]);
-            }),
+        setupMoveUpEvents(
+            this,
+            e,
+            !isEditing
+                ? returnFalse
+                : action((e: PointerEvent, down: number[], delta: number[]) => {
+                      if (!controlUndo) controlUndo = UndoManager.StartBatch('drag ink ctrl pt');
+                      const inkMoveEnd = this.ptFromScreen({ X: delta[0], Y: delta[1] });
+                      const inkMoveStart = this.ptFromScreen({ X: 0, Y: 0 });
+                      InkStrokeProperties.Instance.moveControlPtHandle(inkView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex);
+                      InkStrokeProperties.Instance.moveControlPtHandle(inkView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex + 3);
+                      return false;
+                  }),
+            !isEditing
+                ? returnFalse
+                : action(() => {
+                      controlUndo?.end();
+                      controlUndo = undefined;
+                      UndoManager.FilterBatches(['data', 'x', 'y', 'width', 'height']);
+                  }),
             action((e: PointerEvent, doubleTap: boolean | undefined) => {
                 doubleTap = doubleTap || this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick;
                 if (doubleTap) {
                     InkStrokeProperties.Instance._controlButton = true;
                     InkStrokeProperties.Instance._currentPoint = -1;
-                    this._handledClick = true;  // mark the double-click pseudo pointerevent so we can block the real mouse event from propagating to DocumentView
+                    this._handledClick = true; // mark the double-click pseudo pointerevent so we can block the real mouse event from propagating to DocumentView
                     if (isEditing) {
                         this._nearestT && this._nearestSeg !== undefined && InkStrokeProperties.Instance.addPoints(this.props.docViewPath().lastElement(), this._nearestT, this._nearestSeg, this.inkScaledData().inkData.slice());
                     }
                 }
-            }), isEditing, isEditing, action(() => wasSelected && (InkStrokeProperties.Instance._currentPoint = -1)));
-    }
+            }),
+            isEditing,
+            isEditing,
+            action(() => wasSelected && (InkStrokeProperties.Instance._currentPoint = -1))
+        );
+    };
 
     /**
      * @param scrPt a point in the screen coordinate space
      * @returns the point in the ink data's coordinate space.
      */
-    ptFromScreen = (scrPt: { X: number, Y: number }) => {
+    ptFromScreen = (scrPt: { X: number; Y: number }) => {
         const { inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData();
         const docPt = this.screenToLocal().transformPoint(scrPt.X, scrPt.Y);
         const inkPt = {
@@ -179,39 +197,39 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
             Y: (docPt[1] - inkStrokeWidth / 2) / inkScaleY + inkStrokeWidth / 2 + inkTop,
         };
         return inkPt;
-    }
+    };
 
     /**
      * @param inkPt a point in the ink data's coordinate space
      * @returns the screen point corresponding to the ink point
      */
-    ptToScreen = (inkPt: { X: number, Y: number }) => {
+    ptToScreen = (inkPt: { X: number; Y: number }) => {
         const { inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData();
         const docPt = {
             X: (inkPt.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2,
-            Y: (inkPt.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2
+            Y: (inkPt.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2,
         };
         const scrPt = this.screenToLocal().inverse().transformPoint(docPt.X, docPt.Y);
         return { X: scrPt[0], Y: scrPt[1] };
-    }
+    };
 
     /**
-    * Snaps a screen space point to this stroke, optionally skipping bezier segments indicated by 'excludeSegs'
-    * @param scrPt - the point to snap to this stroke
-    * @param excludeSegs - optional segments in this stroke to skip (this is used when dragging a point on the stroke and not wanting the drag point to snap to its neighboring segments)
-    *
-    * @returns the nearest ink space point on this stroke to the screen point AND the screen space distance from the snapped point to the nearest point
-    */
-    snapPt = (scrPt: { X: number, Y: number }, excludeSegs?: number[]) => {
+     * Snaps a screen space point to this stroke, optionally skipping bezier segments indicated by 'excludeSegs'
+     * @param scrPt - the point to snap to this stroke
+     * @param excludeSegs - optional segments in this stroke to skip (this is used when dragging a point on the stroke and not wanting the drag point to snap to its neighboring segments)
+     *
+     * @returns the nearest ink space point on this stroke to the screen point AND the screen space distance from the snapped point to the nearest point
+     */
+    snapPt = (scrPt: { X: number; Y: number }, excludeSegs?: number[]) => {
         const { inkData } = this.inkScaledData();
         const { nearestPt, distance } = InkStrokeProperties.nearestPtToStroke(inkData, this.ptFromScreen(scrPt), excludeSegs ?? []);
         return { nearestPt, distance: distance * this.screenToLocal().inverse().Scale };
-    }
+    };
 
     /**
-    * extracts key features from the inkData, including: the data points, the ink width, the ink bounds (top,left, width, height), and the scale
-    * factor for converting between ink and screen space.
-    */
+     * extracts key features from the inkData, including: the data points, the ink width, the ink bounds (top,left, width, height), and the scale
+     * factor for converting between ink and screen space.
+     */
     inkScaledData = () => {
         const inkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? [];
         const inkStrokeWidth = NumCast(this.rootDoc.strokeWidth, 1);
@@ -228,27 +246,31 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
             inkLeft,
             inkWidth,
             inkHeight,
-            inkScaleX: ((this.props.PanelWidth() - inkStrokeWidth) / ((inkWidth - inkStrokeWidth) || 1) || 1),
-            inkScaleY: ((this.props.PanelHeight() - inkStrokeWidth) / ((inkHeight - inkStrokeWidth) || 1) || 1)
+            inkScaleX: (this.props.PanelWidth() - inkStrokeWidth) / (inkWidth - inkStrokeWidth || 1) || 1,
+            inkScaleY: (this.props.PanelHeight() - inkStrokeWidth) / (inkHeight - inkStrokeWidth || 1) || 1,
         };
-    }
+    };
 
     //
-    // this updates the highlight for the nearest point on the curve to the cursor.  
+    // this updates the highlight for the nearest point on the curve to the cursor.
     // if the user double clicks, this highlighted point will be added as a control point in the curve.
     //
     @action
     onPointerMove = (e: React.PointerEvent) => {
         const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData();
-        const screenPts = inkData.map(point => this.screenToLocal().inverse().transformPoint(
-            (point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2,
-            (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2)).map(p => ({ X: p[0], Y: p[1] }));
+        const screenPts = inkData
+            .map(point =>
+                this.screenToLocal()
+                    .inverse()
+                    .transformPoint((point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2)
+            )
+            .map(p => ({ X: p[0], Y: p[1] }));
         const { distance, nearestT, nearestSeg, nearestPt } = InkStrokeProperties.nearestPtToStroke(screenPts, { X: e.clientX, Y: e.clientY });
 
         this._nearestT = nearestT;
         this._nearestSeg = nearestSeg;
         this._nearestScrPt = nearestPt;
-    }
+    };
 
     /**
      * @returns the nearest screen point to the cursor (to render a highlight for the point to be added)
@@ -263,50 +285,66 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
     componentUI = (boundsLeft: number, boundsTop: number) => {
         const inkDoc = this.props.Document;
         const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData();
-        const screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.screenToLocal().inverse().Scale);  // the width of the blue line widget that shows the centerline of the ink stroke
+        const screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.screenToLocal().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke
 
         const screenInkWidth = this.screenToLocal().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth);
-        const screenPts = inkData.map(point => this.screenToLocal().inverse().transformPoint(
-            (point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2,
-            (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2)).map(p => ({ X: p[0], Y: p[1] }));
+        const screenPts = inkData
+            .map(point =>
+                this.screenToLocal()
+                    .inverse()
+                    .transformPoint((point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2)
+            )
+            .map(p => ({ X: p[0], Y: p[1] }));
         const screenHdlPts = screenPts;
 
         const startMarker = StrCast(this.layoutDoc.strokeStartMarker);
         const endMarker = StrCast(this.layoutDoc.strokeEndMarker);
         const markerScale = NumCast(this.layoutDoc.strokeMarkerScale);
-        return SnappingManager.GetIsDragging() ? (null) :
-            !InkStrokeProperties.Instance._controlButton ?
-                (!this.props.isSelected() || InkingStroke.IsClosed(inkData) ? (null) :
-                    <div className="inkstroke-UI" style={{ clip: `rect(${boundsTop}px, 10000px, 10000px, ${boundsLeft}px)` }}>
-                        <InkEndPtHandles
-                            inkView={this.props.docViewPath().lastElement()}
-                            inkDoc={inkDoc}
-                            startPt={screenPts[0]}
-                            endPt={screenPts.lastElement()}
-                            screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} />
-                    </div>) :
+        return SnappingManager.GetIsDragging() ? null : !InkStrokeProperties.Instance._controlButton ? (
+            !this.props.isSelected() || InkingStroke.IsClosed(inkData) ? null : (
                 <div className="inkstroke-UI" style={{ clip: `rect(${boundsTop}px, 10000px, 10000px, ${boundsLeft}px)` }}>
-                    {InteractionUtils.CreatePolyline(screenPts, 0, 0, Colors.MEDIUM_BLUE, screenInkWidth[0], screenSpaceCenterlineStrokeWidth,
-                        StrCast(inkDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap), StrCast(inkDoc.strokeBezier),
-                        "none", startMarker, endMarker, markerScale * Math.min(screenSpaceCenterlineStrokeWidth, screenInkWidth[0] / screenSpaceCenterlineStrokeWidth), StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false)}
-                    <InkControlPtHandles
-                        inkView={this.props.docViewPath().lastElement()}
-                        inkDoc={inkDoc}
-                        inkCtrlPoints={inkData}
-                        screenCtrlPoints={screenHdlPts}
-                        nearestScreenPt={this.nearestScreenPt}
-                        screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} />
-                    <InkTangentHandles
-                        inkView={this.props.docViewPath().lastElement()}
-                        inkDoc={inkDoc}
-                        screenCtrlPoints={screenHdlPts}
-                        screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth}
-                        ScreenToLocalTransform={this.screenToLocal} />
-                </div>;
-    }
+                    <InkEndPtHandles inkView={this.props.docViewPath().lastElement()} inkDoc={inkDoc} startPt={screenPts[0]} endPt={screenPts.lastElement()} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} />
+                </div>
+            )
+        ) : (
+            <div className="inkstroke-UI" style={{ clip: `rect(${boundsTop}px, 10000px, 10000px, ${boundsLeft}px)` }}>
+                {InteractionUtils.CreatePolyline(
+                    screenPts,
+                    0,
+                    0,
+                    Colors.MEDIUM_BLUE,
+                    screenInkWidth[0],
+                    screenSpaceCenterlineStrokeWidth,
+                    StrCast(inkDoc.strokeLineJoin),
+                    StrCast(this.layoutDoc.strokeLineCap),
+                    StrCast(inkDoc.strokeBezier),
+                    'none',
+                    startMarker,
+                    endMarker,
+                    markerScale * Math.min(screenSpaceCenterlineStrokeWidth, screenInkWidth[0] / screenSpaceCenterlineStrokeWidth),
+                    StrCast(inkDoc.strokeDash),
+                    1,
+                    1,
+                    '',
+                    'none',
+                    1.0,
+                    false
+                )}
+                <InkControlPtHandles
+                    inkView={this.props.docViewPath().lastElement()}
+                    inkDoc={inkDoc}
+                    inkCtrlPoints={inkData}
+                    screenCtrlPoints={screenHdlPts}
+                    nearestScreenPt={this.nearestScreenPt}
+                    screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth}
+                />
+                <InkTangentHandles inkView={this.props.docViewPath().lastElement()} inkDoc={inkDoc} screenCtrlPoints={screenHdlPts} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} ScreenToLocalTransform={this.screenToLocal} />
+            </div>
+        );
+    };
 
     _subContentView: DocComponentView | undefined;
-    setSubContentView = (doc: DocComponentView) => this._subContentView = doc;
+    setSubContentView = (doc: DocComponentView) => (this._subContentView = doc);
     render() {
         TraceMobx();
         const { inkData, inkStrokeWidth, inkLeft, inkTop, inkScaleX, inkScaleY, inkWidth, inkHeight } = this.inkScaledData();
@@ -315,105 +353,181 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
         const endMarker = StrCast(this.layoutDoc.strokeEndMarker);
         const markerScale = NumCast(this.layoutDoc.strokeMarkerScale, 1);
         const closed = InkingStroke.IsClosed(inkData);
-        const fillColor = StrCast(this.layoutDoc.fillColor, "transparent");
-        const strokeColor = !closed && fillColor && fillColor !== "transparent" ? fillColor : StrCast(this.layoutDoc.color);
+        const fillColor = StrCast(this.layoutDoc.fillColor, 'transparent');
+        const strokeColor = !closed && fillColor && fillColor !== 'transparent' ? fillColor : StrCast(this.layoutDoc.color);
 
         // Visually renders the polygonal line made by the user.
-        const inkLine = InteractionUtils.CreatePolyline(inkData, inkLeft, inkTop, strokeColor, inkStrokeWidth, inkStrokeWidth,
-            StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap),
-            StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" ? "none" : fillColor, startMarker, endMarker,
-            markerScale, StrCast(this.layoutDoc.strokeDash), inkScaleX, inkScaleY, "", "none", 1.0, false);
+        const inkLine = InteractionUtils.CreatePolyline(
+            inkData,
+            inkLeft,
+            inkTop,
+            strokeColor,
+            inkStrokeWidth,
+            inkStrokeWidth,
+            StrCast(this.layoutDoc.strokeLineJoin),
+            StrCast(this.layoutDoc.strokeLineCap),
+            StrCast(this.layoutDoc.strokeBezier),
+            !closed ? 'none' : fillColor === 'transparent' ? 'none' : fillColor,
+            startMarker,
+            endMarker,
+            markerScale,
+            StrCast(this.layoutDoc.strokeDash),
+            inkScaleX,
+            inkScaleY,
+            '',
+            'none',
+            1.0,
+            false
+        );
         const highlightIndex = /*BoolCast(this.props.Document.isLinkButton) && */ Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString
-        const highlightColor = !highlightIndex ?
-            StrCast(this.layoutDoc.strokeOutlineColor, !closed && fillColor && fillColor !== "transparent" ? StrCast(this.layoutDoc.color, "transparent") : "transparent") :
-            ["transparent", "rgb(68, 118, 247)", "rgb(68, 118, 247)", "yellow", "magenta", "cyan", "orange"][highlightIndex];
+        const highlightColor = !highlightIndex
+            ? StrCast(this.layoutDoc.strokeOutlineColor, !closed && fillColor && fillColor !== 'transparent' ? StrCast(this.layoutDoc.color, 'transparent') : 'transparent')
+            : ['transparent', 'rgb(68, 118, 247)', 'rgb(68, 118, 247)', 'yellow', 'magenta', 'cyan', 'orange'][highlightIndex];
         // Invisible polygonal line that enables the ink to be selected by the user.
-        const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, suppressFill: boolean = false) => InteractionUtils.CreatePolyline(inkData, inkLeft, inkTop, highlightColor,
-            inkStrokeWidth, fillColor && closed && highlightIndex ? highlightIndex / 2 : inkStrokeWidth + (fillColor ? closed ? 0 : (highlightIndex + 2) : 0),
-            StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap),
-            StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" || suppressFill ? "none" : fillColor, startMarker, endMarker,
-            markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents?.() ?? (this.rootDoc._lockedPosition ? "none" : "visiblepainted"), 0.0,
-            false, downHdlr);
-        const fsize = +(StrCast(this.props.Document.fontSize, "12px").replace("px", ""));
-        // bootsrap 3 style sheet sets line height to be 20px for default 14 point font size. 
+        const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, suppressFill: boolean = false) =>
+            InteractionUtils.CreatePolyline(
+                inkData,
+                inkLeft,
+                inkTop,
+                highlightColor,
+                inkStrokeWidth,
+                fillColor && closed && highlightIndex ? highlightIndex / 2 : inkStrokeWidth + (fillColor ? (closed ? 0 : highlightIndex + 2) : 0),
+                StrCast(this.layoutDoc.strokeLineJoin),
+                StrCast(this.layoutDoc.strokeLineCap),
+                StrCast(this.layoutDoc.strokeBezier),
+                !closed ? 'none' : fillColor === 'transparent' || suppressFill ? 'none' : fillColor,
+                startMarker,
+                endMarker,
+                markerScale,
+                undefined,
+                inkScaleX,
+                inkScaleY,
+                '',
+                this.props.pointerEvents?.() ?? (this.rootDoc._lockedPosition ? 'none' : 'visiblepainted'),
+                0.0,
+                false,
+                downHdlr
+            );
+        const fsize = +StrCast(this.props.Document.fontSize, '12px').replace('px', '');
+        // bootsrap 3 style sheet sets line height to be 20px for default 14 point font size.
         // this attempts to figure out the lineHeight ratio by inquiring the body's lineHeight and dividing by the fontsize which should yield 1.428571429
         // see: https://bibwild.wordpress.com/2019/06/10/bootstrap-3-to-4-changes-in-how-font-size-line-height-and-spacing-is-done-or-what-happened-to-line-height-computed/
-        const lineHeightGuess = (+getComputedStyle(document.body).lineHeight.replace("px", "")) / (+getComputedStyle(document.body).fontSize.replace("px", ""));
+        const lineHeightGuess = +getComputedStyle(document.body).lineHeight.replace('px', '') / +getComputedStyle(document.body).fontSize.replace('px', '');
         const interactions = {
-            onPointerLeave: action(() => this._nearestScrPt = undefined),
+            onPointerLeave: action(() => (this._nearestScrPt = undefined)),
             onPointerMove: this.props.isSelected() ? this.onPointerMove : undefined,
             onClick: (e: React.MouseEvent) => this._handledClick && e.stopPropagation(),
             onContextMenu: () => {
                 const cm = ContextMenu.Instance;
-                !Doc.noviceMode && cm?.addItem({ description: "Recognize Writing", event: this.analyzeStrokes, icon: "paint-brush" });
-                cm?.addItem({ description: "Toggle Mask", event: () => InkingStroke.toggleMask(this.rootDoc), icon: "paint-brush" });
-                cm?.addItem({ description: "Edit Points", event: action(() => InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton), icon: "paint-brush" });
-            }
+                !Doc.noviceMode && cm?.addItem({ description: 'Recognize Writing', event: this.analyzeStrokes, icon: 'paint-brush' });
+                cm?.addItem({ description: 'Toggle Mask', event: () => InkingStroke.toggleMask(this.rootDoc), icon: 'paint-brush' });
+                cm?.addItem({ description: 'Edit Points', event: action(() => (InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton)), icon: 'paint-brush' });
+            },
         };
-        return <div className="inkStroke-wrapper">
-            <svg className="inkStroke"
-                style={{
-                    transform: this.props.Document.isInkMask ? `translate(${InkingStroke.MaskDim / 2}px, ${InkingStroke.MaskDim / 2}px)` : undefined,
-                    mixBlendMode: this.layoutDoc.tool === InkTool.Highlighter ? "multiply" : "unset",
-                    cursor: this.props.isSelected() ? "default" : undefined
-                }}
-                {...(!closed ? interactions : {})}
-            >
-                {closed ? inkLine : clickableLine(this.onPointerDown)}
-                {closed ? clickableLine(this.onPointerDown) : inkLine}
-            </svg>
-            {!closed || (!RTFCast(this.rootDoc.text)?.Text && !this.props.isSelected()) ? (null) :
-                <div className="inkStroke-text" style={{
-                    color: StrCast(this.layoutDoc.textColor, "black"),
-                    pointerEvents: this.props.isDocumentActive?.() ? "all" : undefined,
-                    width: this.layoutDoc[WidthSym](),
-                    transform: `scale(${this.props.scaling?.() || 1})`,
-                    transformOrigin: "top left",
-                    top: (this.props.PanelHeight() - (lineHeightGuess * fsize + 20) * (this.props.scaling?.() || 1)) / 2
-                }}>
-                    <FormattedTextBox
-                        {...OmitKeys(this.props, ['children']).omit}
-                        setContentView={this.setSubContentView} // this makes the inkingStroke the "dominant" component - ie, it will show the inking UI when selected (not text)
-                        yPadding={10}
-                        xPadding={10}
-                        fieldKey={"text"}
-                        fontSize={fsize}
-                        dontRegisterView={true}
-                        noSidebar={true}
-                        dontScale={true}
-                        isContentActive={this.isContentActive}
-                    />
-                </div>
-            }
-            {!closed ? null : <svg className="inkStroke"
-                style={{
-                    transform: this.props.Document.isInkMask ? `translate(${InkingStroke.MaskDim / 2}px, ${InkingStroke.MaskDim / 2}px)` : undefined,
-                    mixBlendMode: this.layoutDoc.tool === InkTool.Highlighter ? "multiply" : "unset",
-                    cursor: this.props.isSelected() ? "default" : undefined, position: "absolute"
-                }}
-                {...interactions}
-            >
-                {clickableLine(this.onPointerDown, true)}
-            </svg>}
-        </div>;
+        return (
+            <div className="inkStroke-wrapper">
+                <svg
+                    className="inkStroke"
+                    style={{
+                        transform: this.props.Document.isInkMask ? `translate(${InkingStroke.MaskDim / 2}px, ${InkingStroke.MaskDim / 2}px)` : undefined,
+                        mixBlendMode: this.layoutDoc.tool === InkTool.Highlighter ? 'multiply' : 'unset',
+                        cursor: this.props.isSelected() ? 'default' : undefined,
+                    }}
+                    {...(!closed ? interactions : {})}>
+                    {closed ? inkLine : clickableLine(this.onPointerDown)}
+                    {closed ? clickableLine(this.onPointerDown) : inkLine}
+                </svg>
+                {!closed || (!RTFCast(this.rootDoc.text)?.Text && !this.props.isSelected()) ? null : (
+                    <div
+                        className="inkStroke-text"
+                        style={{
+                            color: StrCast(this.layoutDoc.textColor, 'black'),
+                            pointerEvents: this.props.isDocumentActive?.() ? 'all' : undefined,
+                            width: this.layoutDoc[WidthSym](),
+                            transform: `scale(${this.props.NativeDimScaling?.() || 1})`,
+                            transformOrigin: 'top left',
+                            top: (this.props.PanelHeight() - (lineHeightGuess * fsize + 20) * (this.props.NativeDimScaling?.() || 1)) / 2,
+                        }}>
+                        <FormattedTextBox
+                            {...OmitKeys(this.props, ['children']).omit}
+                            setContentView={this.setSubContentView} // this makes the inkingStroke the "dominant" component - ie, it will show the inking UI when selected (not text)
+                            yPadding={10}
+                            xPadding={10}
+                            fieldKey={'text'}
+                            fontSize={fsize}
+                            dontRegisterView={true}
+                            noSidebar={true}
+                            dontScale={true}
+                            isContentActive={this.isContentActive}
+                        />
+                    </div>
+                )}
+                {!closed ? null : (
+                    <svg
+                        className="inkStroke"
+                        style={{
+                            transform: this.props.Document.isInkMask ? `translate(${InkingStroke.MaskDim / 2}px, ${InkingStroke.MaskDim / 2}px)` : undefined,
+                            mixBlendMode: this.layoutDoc.tool === InkTool.Highlighter ? 'multiply' : 'unset',
+                            cursor: this.props.isSelected() ? 'default' : undefined,
+                            position: 'absolute',
+                        }}
+                        {...interactions}>
+                        {clickableLine(this.onPointerDown, true)}
+                    </svg>
+                )}
+            </div>
+        );
     }
 }
 
-
-export function SetActiveInkWidth(width: string): void { !isNaN(parseInt(width)) && ActiveInkPen() && (ActiveInkPen().activeInkWidth = width); }
-export function SetActiveBezierApprox(bezier: string): void { ActiveInkPen() && (ActiveInkPen().activeInkBezier = isNaN(parseInt(bezier)) ? "" : bezier); }
-export function SetActiveInkColor(value: string) { ActiveInkPen() && (ActiveInkPen().activeInkColor = value); }
-export function SetActiveFillColor(value: string) { ActiveInkPen() && (ActiveInkPen().activeFillColor = value); }
-export function SetActiveArrowStart(value: string) { ActiveInkPen() && (ActiveInkPen().activeArrowStart = value); }
-export function SetActiveArrowEnd(value: string) { ActiveInkPen() && (ActiveInkPen().activeArrowEnd = value); }
-export function SetActiveArrowScale(value: number) { ActiveInkPen() && (ActiveInkPen().activeArrowScale = value); }
-export function SetActiveDash(dash: string): void { !isNaN(parseInt(dash)) && ActiveInkPen() && (ActiveInkPen().activeDash = dash); }
-export function ActiveInkPen(): Doc { return Doc.UserDoc(); }
-export function ActiveInkColor(): string { return StrCast(ActiveInkPen()?.activeInkColor, "black"); }
-export function ActiveFillColor(): string { return StrCast(ActiveInkPen()?.activeFillColor, ""); }
-export function ActiveArrowStart(): string { return StrCast(ActiveInkPen()?.activeArrowStart, ""); }
-export function ActiveArrowEnd(): string { return StrCast(ActiveInkPen()?.activeArrowEnd, ""); }
-export function ActiveArrowScale(): number { return NumCast(ActiveInkPen()?.activeArrowScale, 1); }
-export function ActiveDash(): string { return StrCast(ActiveInkPen()?.activeDash, "0"); }
-export function ActiveInkWidth(): number { return Number(ActiveInkPen()?.activeInkWidth); }
-export function ActiveInkBezierApprox(): string { return StrCast(ActiveInkPen()?.activeInkBezier); }
+export function SetActiveInkWidth(width: string): void {
+    !isNaN(parseInt(width)) && ActiveInkPen() && (ActiveInkPen().activeInkWidth = width);
+}
+export function SetActiveBezierApprox(bezier: string): void {
+    ActiveInkPen() && (ActiveInkPen().activeInkBezier = isNaN(parseInt(bezier)) ? '' : bezier);
+}
+export function SetActiveInkColor(value: string) {
+    ActiveInkPen() && (ActiveInkPen().activeInkColor = value);
+}
+export function SetActiveFillColor(value: string) {
+    ActiveInkPen() && (ActiveInkPen().activeFillColor = value);
+}
+export function SetActiveArrowStart(value: string) {
+    ActiveInkPen() && (ActiveInkPen().activeArrowStart = value);
+}
+export function SetActiveArrowEnd(value: string) {
+    ActiveInkPen() && (ActiveInkPen().activeArrowEnd = value);
+}
+export function SetActiveArrowScale(value: number) {
+    ActiveInkPen() && (ActiveInkPen().activeArrowScale = value);
+}
+export function SetActiveDash(dash: string): void {
+    !isNaN(parseInt(dash)) && ActiveInkPen() && (ActiveInkPen().activeDash = dash);
+}
+export function ActiveInkPen(): Doc {
+    return Doc.UserDoc();
+}
+export function ActiveInkColor(): string {
+    return StrCast(ActiveInkPen()?.activeInkColor, 'black');
+}
+export function ActiveFillColor(): string {
+    return StrCast(ActiveInkPen()?.activeFillColor, '');
+}
+export function ActiveArrowStart(): string {
+    return StrCast(ActiveInkPen()?.activeArrowStart, '');
+}
+export function ActiveArrowEnd(): string {
+    return StrCast(ActiveInkPen()?.activeArrowEnd, '');
+}
+export function ActiveArrowScale(): number {
+    return NumCast(ActiveInkPen()?.activeArrowScale, 1);
+}
+export function ActiveDash(): string {
+    return StrCast(ActiveInkPen()?.activeDash, '0');
+}
+export function ActiveInkWidth(): number {
+    return Number(ActiveInkPen()?.activeInkWidth);
+}
+export function ActiveInkBezierApprox(): string {
+    return StrCast(ActiveInkPen()?.activeInkBezier);
+}
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index e81a9c40f..9fdf9d2be 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -93,7 +93,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
         this.props
             .ScreenToLocalTransform()
             .translate(Doc.NativeWidth(this.props.dataDoc), 0)
-            .scale(this.props.scaling?.() || 1);
+            .scale(this.props.NativeDimScaling?.() || 1);
     // panelWidth = () => !this.props.layoutDoc._showSidebar ? 0 :
     //     this.props.usePanelWidth ? this.props.PanelWidth() :
     //         (NumCast(this.props.layoutDoc.nativeWidth) - Doc.NativeWidth(this.props.dataDoc)) * this.props.PanelWidth() / NumCast(this.props.layoutDoc.nativeWidth);
@@ -164,7 +164,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
                         setHeight={this.setHeightCallback}
                         isAnnotationOverlay={false}
                         select={emptyFunction}
-                        scaling={returnOne}
+                        NativeDimScaling={returnOne}
                         childShowTitle={this.showTitle}
                         childDocumentsActive={this.props.isContentActive}
                         whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 340a5df45..334f381be 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -250,9 +250,9 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                     return doc.z
                         ? `#9c9396  ${StrCast(doc?.boxShadow, '10px 10px 0.9vw')}` // if it's a floating doc, give it a big shadow
                         : props?.ContainingCollectionDoc?._useClusters && doc.type !== DocumentType.INK
-                        ? `${backgroundCol()} ${StrCast(doc.boxShadow, `0vw 0vw ${(isBackground() ? 100 : 50) / (docProps?.ContentScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
+                        ? `${backgroundCol()} ${StrCast(doc.boxShadow, `0vw 0vw ${(isBackground() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
                         : NumCast(doc.group, -1) !== -1 && doc.type !== DocumentType.INK
-                        ? `gray ${StrCast(doc.boxShadow, `0vw 0vw ${(isBackground() ? 100 : 50) / (docProps?.ContentScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
+                        ? `gray ${StrCast(doc.boxShadow, `0vw 0vw ${(isBackground() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
                         : isBackground()
                         ? undefined // if it's a background & has a cluster color, make the shadow spread really big
                         : StrCast(doc.boxShadow, '');
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index f1d842386..714d8421a 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -519,7 +519,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
                     isAnnotationOverlay={true}
                     isDocumentActive={returnFalse}
                     select={emptyFunction}
-                    scaling={returnOne}
+                    NativeDimScaling={returnOne}
                     xMargin={25}
                     yMargin={10}
                     ScreenToLocalTransform={this.dictationScreenToLocalTransform}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 809a73a77..dce792d19 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -235,7 +235,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                 forceAutoHeight={true} // needed to make the title resize even if the rest of the tree view is not autoHeight
                 PanelWidth={this.documentTitleWidth}
                 PanelHeight={this.documentTitleHeight}
-                scaling={returnOne}
+                NativeDimScaling={returnOne}
                 onKey={this.onKey}
                 docFilters={returnEmptyFilter}
                 docRangeFilters={returnEmptyFilter}
@@ -351,7 +351,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
         return Doc.NativeHeight(this.Document, undefined, true);
     }
 
-    @computed get contentScaling() {
+    /// scale factor for tree view so that it will fit within it's panel bounds
+    @computed get nativeDimScaling() {
         const nw = this.nativeWidth;
         const nh = this.nativeHeight;
         const hscale = nh ? this.props.PanelHeight() / nh : 1;
@@ -365,7 +366,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     documentTitleHeight = () => (this.layoutDoc?.[HeightSym]() || 0) - NumCast(this.layoutDoc.autoHeightMargins);
     truncateTitleWidth = () => this.treeViewtruncateTitleWidth;
     onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick);
-    panelWidth = () => Math.max(0, this.props.PanelWidth() - this.marginX() - CollectionTreeView.expandViewLabelSize) * (this.props.scaling?.() || 1);
+    panelWidth = () => Math.max(0, this.props.PanelWidth() - this.marginX() - CollectionTreeView.expandViewLabelSize) * (this.props.NativeDimScaling?.() || 1);
 
     addAnnotationDocument = (doc: Doc | Doc[]) => this.props.CollectionView?.addDocument(doc, `${this.props.fieldKey}-annotations`) || false;
     remAnnotationDocument = (doc: Doc | Doc[]) => this.props.CollectionView?.removeDocument(doc, `${this.props.fieldKey}-annotations`) || false;
@@ -389,9 +390,9 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                 <div
                     className="collectionTreeView-container"
                     style={{
-                        transform: this.outlineMode ? `scale(${this.contentScaling})` : '',
+                        transform: this.outlineMode ? `scale(${this.nativeDimScaling})` : '',
                         paddingLeft: `${this.marginX()}px`,
-                        width: this.outlineMode ? `calc(${100 / this.contentScaling}%)` : '',
+                        width: this.outlineMode ? `calc(${100 / this.nativeDimScaling}%)` : '',
                     }}
                     onContextMenu={this.onContextMenu}>
                     {!this.buttonMenu && !this.noviceExplainer ? null : (
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 5a2103e98..aa1330762 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -403,7 +403,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         const aspect = Doc.NativeAspect(layoutDoc);
         if (layoutDoc._fitWidth) return Math.min(this.props.panelWidth() - treeBulletWidth(), layoutDoc[WidthSym]());
         if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.panelWidth() - treeBulletWidth()));
-        return Math.min((this.props.panelWidth() - treeBulletWidth()) / (this.props.treeView.props.scaling?.() || 1), Doc.NativeWidth(layoutDoc) ? layoutDoc[WidthSym]() : this.layoutDoc[WidthSym]());
+        return Math.min((this.props.panelWidth() - treeBulletWidth()) / (this.props.treeView.props.NativeDimScaling?.() || 1), Doc.NativeWidth(layoutDoc) ? layoutDoc[WidthSym]() : this.layoutDoc[WidthSym]());
     };
     docHeight = () => {
         const layoutDoc = this.layoutDoc;
@@ -514,7 +514,7 @@ export class TreeView extends React.Component<TreeViewProps> {
 
     rtfWidth = () => {
         const layout = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ''))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc;
-        return Math.min(layout[WidthSym](), this.props.panelWidth() - treeBulletWidth()) / (this.props.treeView.props.scaling?.() || 1);
+        return Math.min(layout[WidthSym](), this.props.panelWidth() - treeBulletWidth()) / (this.props.treeView.props.NativeDimScaling?.() || 1);
     };
     rtfHeight = () => {
         const layout = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ''))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc;
@@ -921,7 +921,6 @@ export class TreeView extends React.Component<TreeViewProps> {
                 searchFilterDocs={returnEmptyDoclist}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={this.props.treeView.props.Document}
-                ContentScaling={returnOne}
             />
         );
 
@@ -992,7 +991,6 @@ export class TreeView extends React.Component<TreeViewProps> {
                 hideResizeHandles={this.props.treeView.outlineMode}
                 onClick={this.onChildClick}
                 focus={this.refocus}
-                ContentScaling={returnOne}
                 onKey={this.onKeyDown}
                 hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)}
                 dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 5d7a12122..3e938ec1c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -58,7 +58,7 @@ import e = require('connect-flash');
 export type collectionFreeformViewProps = {
     annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox)
     viewDefDivClick?: ScriptField;
-    childPointerEvents?: boolean;
+    childPointerEvents?: string;
     scaleField?: string;
     noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale)
     engineProps?: any;
@@ -150,11 +150,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         return this.fitContentsToBox ? 0 : Doc.NativeHeight(this.Document, Cast(this.Document.resolvedDataDoc, Doc, null));
     }
     @computed get cachedCenteringShiftX(): number {
-        const scaling = this.fitContentsToBox || !this.contentScaling ? 1 : this.contentScaling;
+        const scaling = this.fitContentsToBox || !this.nativeDimScaling ? 1 : this.nativeDimScaling;
         return this.props.isAnnotationOverlay ? 0 : this.props.PanelWidth() / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
     }
     @computed get cachedCenteringShiftY(): number {
-        const scaling = this.fitContentsToBox || !this.contentScaling ? 1 : this.contentScaling;
+        const scaling = this.fitContentsToBox || !this.nativeDimScaling ? 1 : this.nativeDimScaling;
         return this.props.isAnnotationOverlay ? 0 : this.props.PanelHeight() / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
     }
     @computed get cachedGetLocalTransform(): Transform {
@@ -1065,7 +1065,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     onPointerWheel = (e: React.WheelEvent): void => {
-        if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || DocListCast(Doc.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return;
+        if (this.layoutDoc._Transform || DocListCast(Doc.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return;
         if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) {
             // things that can scroll vertically should do that instead of zooming
             e.stopPropagation();
@@ -1251,7 +1251,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
         if (scale) {
             const maxZoom = 5; // sets the limit for how far we will zoom. this is useful for preventing small text boxes from filling the screen. So probably needs to be more sophisticated to consider more about the target and context
-            const newScale = Math.min(maxZoom, (1 / (this.contentScaling || 1)) * scale * Math.min(this.props.PanelWidth() / Math.abs(bounds.width), this.props.PanelHeight() / Math.abs(bounds.height)));
+            const newScale = Math.min(maxZoom, (1 / (this.nativeDimScaling || 1)) * scale * Math.min(this.props.PanelWidth() / Math.abs(bounds.width), this.props.PanelHeight() / Math.abs(bounds.height)));
             return {
                 panX: this.props.isAnnotationOverlay ? bounds.left - (Doc.NativeWidth(this.layoutDoc) / newScale - bounds.width) / 2 : (bounds.left + bounds.right) / 2,
                 panY: this.props.isAnnotationOverlay ? bounds.top - (Doc.NativeHeight(this.layoutDoc) / newScale - bounds.height) / 2 : (bounds.top + bounds.bot) / 2,
@@ -1301,7 +1301,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     };
     pointerEvents = () => {
         const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine);
-        const pointerEvents = this.props.isContentActive() === false ? 'none' : this.props.childPointerEvents ? 'all' : this.props.viewDefDivClick || (engine === 'pass' && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.();
+        const pointerEvents = this.props.isContentActive() === false ? 'none' : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === 'pass' && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.());
         return pointerEvents;
     };
     getChildDocView(entry: PoolData) {
@@ -1631,9 +1631,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 img.style.width = canvas.style.width;
                 img.style.height = canvas.style.height;
                 const newCan = newDiv as HTMLCanvasElement;
-                const parEle = newCan.parentElement as HTMLElement;
-                parEle.removeChild(newCan);
-                parEle.appendChild(img);
+                if (newCan) {
+                    const parEle = newCan.parentElement as HTMLElement;
+                    parEle.removeChild(newCan);
+                    parEle.appendChild(img);
+                }
             }
         }
     }
@@ -1943,13 +1945,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         );
     }
 
-    @computed get contentScaling() {
+    @computed get nativeDimScaling() {
         if (this._firstRender || (this.props.isAnnotationOverlay && !this.props.annotationLayerHostsContent)) return 0;
         const nw = this.nativeWidth;
         const nh = this.nativeHeight;
         const hscale = nh ? this.props.PanelHeight() / nh : 1;
         const wscale = nw ? this.props.PanelWidth() / nw : 1;
-        return wscale < hscale ? wscale : hscale;
+        return wscale < hscale || this.layoutDoc.fitWidth ? wscale : hscale;
     }
 
     private groupDropDisposer?: DragManager.DragDropDisposer;
@@ -1983,9 +1985,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                             : SnappingManager.GetIsDragging() && this.childDocs.includes(DragManager.docsBeingDragged.lastElement())
                             ? 'all'
                             : (this.props.pointerEvents?.() as any),
-                    transform: `scale(${this.contentScaling || 1})`,
-                    width: `${100 / (this.contentScaling || 1)}%`,
-                    height: this.isAnnotationOverlay && this.Document.scrollHeight ? NumCast(this.Document.scrollHeight) : `${100 / (this.contentScaling || 1)}%`, // : this.isAnnotationOverlay ? (this.Document.scrollHeight ? this.Document.scrollHeight : "100%") : this.props.PanelHeight()
+                    transform: `scale(${this.nativeDimScaling || 1})`,
+                    width: `${100 / (this.nativeDimScaling || 1)}%`,
+                    height: this.isAnnotationOverlay && this.Document.scrollHeight ? NumCast(this.Document.scrollHeight) : `${100 / (this.nativeDimScaling || 1)}%`, // : this.isAnnotationOverlay ? (this.Document.scrollHeight ? this.Document.scrollHeight : "100%") : this.props.PanelHeight()
                 }}>
                 {this._firstRender ? this.placeholder : this.marqueeView}
                 {this.props.noOverlay ? null : <CollectionFreeFormOverlayView elements={this.elementFunc} />}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 777ef464f..465dbfe6d 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -1,6 +1,6 @@
 import { action, computed } from 'mobx';
 import { observer } from 'mobx-react';
-import * as React from "react";
+import * as React from 'react';
 import { Doc, DocListCast } from '../../../../fields/Doc';
 import { List } from '../../../../fields/List';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
@@ -11,11 +11,10 @@ import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
 import { DocumentView } from '../../nodes/DocumentView';
 import { CollectionSubView } from '../CollectionSubView';
-import "./CollectionMulticolumnView.scss";
+import './CollectionMulticolumnView.scss';
 import ResizeBar from './MulticolumnResizer';
 import WidthLabel from './MulticolumnWidthLabel';
 
-
 interface WidthSpecifier {
     magnitude: number;
     unit: string;
@@ -27,8 +26,8 @@ interface LayoutData {
 }
 
 export const DimUnit = {
-    Pixel: "px",
-    Ratio: "*"
+    Pixel: 'px',
+    Ratio: '*',
 };
 
 const resolvedUnits = Object.values(DimUnit);
@@ -36,14 +35,13 @@ const resizerWidth = 8;
 
 @observer
 export class CollectionMulticolumnView extends CollectionSubView() {
-
     /**
      * @returns the list of layout documents whose width unit is
      * *, denoting that it will be displayed with a ratio, not fixed pixel, value
      */
     @computed
     private get ratioDefinedDocs() {
-        return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout._dimUnit, "*") === DimUnit.Ratio);
+        return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout._dimUnit, '*') === DimUnit.Ratio);
     }
 
     @computed
@@ -65,10 +63,10 @@ export class CollectionMulticolumnView extends CollectionSubView() {
         let starSum = 0;
         const widthSpecifiers: WidthSpecifier[] = [];
         this.childLayoutPairs.map(pair => {
-            const unit = StrCast(pair.layout._dimUnit, "*");
+            const unit = StrCast(pair.layout._dimUnit, '*');
             const magnitude = NumCast(pair.layout._dimMagnitude, this.minimumDim);
             if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) {
-                (unit === DimUnit.Ratio) && (starSum += magnitude);
+                unit === DimUnit.Ratio && (starSum += magnitude);
                 widthSpecifiers.push({ magnitude, unit });
             }
             /**
@@ -100,14 +98,13 @@ export class CollectionMulticolumnView extends CollectionSubView() {
      * This returns the total quantity, in pixels, that this
      * view needs to reserve for child documents that have
      * (with higher priority) requested a fixed pixel width.
-     * 
+     *
      * If the underlying resolvedLayoutInformation returns null
      * because we're waiting on promises to resolve, this value will be undefined as well.
      */
     @computed
     private get totalFixedAllocation(): number | undefined {
-        return this.resolvedLayoutInformation?.widthSpecifiers.reduce(
-            (sum, { magnitude, unit }) => sum + (unit === DimUnit.Pixel ? magnitude : 0), 0);
+        return this.resolvedLayoutInformation?.widthSpecifiers.reduce((sum, { magnitude, unit }) => sum + (unit === DimUnit.Pixel ? magnitude : 0), 0);
     }
 
     /**
@@ -115,7 +112,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
      * view needs to reserve for child documents that have
      * (with lower priority) requested a certain relative proportion of the
      * remaining pixel width not allocated for fixed widths.
-     * 
+     *
      * If the underlying totalFixedAllocation returns undefined
      * because we're waiting indirectly on promises to resolve, this value will be undefined as well.
      */
@@ -135,7 +132,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
      * this accessor returns 1000 / (2 + 2 + 1), or 200px.
      * Elsewhere, this is then multiplied by each relative-width
      * document's (potentially decimal) * count to compute its actual width (400px, 400px and 200px).
-     * 
+     *
      * If the underlying totalRatioAllocation or this.resolveLayoutInformation return undefined
      * because we're waiting indirectly on promises to resolve, this value will be undefined as well.
      */
@@ -165,17 +162,17 @@ export class CollectionMulticolumnView extends CollectionSubView() {
             return 0; // we're still waiting on promises to resolve
         }
         let width = NumCast(layout._dimMagnitude, this.minimumDim);
-        if (StrCast(layout._dimUnit, "*") === DimUnit.Ratio) {
+        if (StrCast(layout._dimUnit, '*') === DimUnit.Ratio) {
             width *= columnUnitLength;
         }
         return width;
-    }
+    };
 
     /**
      * @returns the transform that will correctly place
      * the document decorations box, shifted to the right by
      * the sum of all the resolved column widths of the
-     * documents before the target. 
+     * documents before the target.
      */
     private lookupIndividualTransform = (layout: Doc) => {
         const columnUnitLength = this.columnUnitLength;
@@ -185,12 +182,12 @@ export class CollectionMulticolumnView extends CollectionSubView() {
         let offset = 0;
         for (const { layout: candidate } of this.childLayoutPairs) {
             if (candidate === layout) {
-                return this.props.ScreenToLocalTransform().translate(-offset / (this.props.scaling?.() || 1), 0);
+                return this.props.ScreenToLocalTransform().translate(-offset / (this.props.NativeDimScaling?.() || 1), 0);
             }
             offset += this.lookupPixels(candidate) + resizerWidth;
         }
         return Transform.Identity(); // type coersion, this case should never be hit
-    }
+    };
 
     @undoBatch
     @action
@@ -198,16 +195,17 @@ export class CollectionMulticolumnView extends CollectionSubView() {
         let dropInd = -1;
         if (de.complete.docDragData && this._mainCont) {
             let curInd = -1;
-            de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => {
-                curInd = this.childDocs.indexOf(d);
-            }));
+            de.complete.docDragData?.droppedDocuments.forEach(
+                action((d: Doc) => {
+                    curInd = this.childDocs.indexOf(d);
+                })
+            );
             Array.from(this._mainCont.children).forEach((child, index) => {
                 const brect = child.getBoundingClientRect();
                 if (brect.x < de.x && brect.x + brect.width > de.x) {
                     if (curInd !== -1 && curInd === Math.floor(index / 2)) {
                         dropInd = curInd;
-                    }
-                    else if (child.className === "multiColumnResizer") {
+                    } else if (child.className === 'multiColumnResizer') {
                         dropInd = Math.floor(index / 2);
                     } else {
                         dropInd = Math.ceil(index / 2 + (de.x - brect.x > brect.width / 2 ? 0 : -1));
@@ -215,76 +213,80 @@ export class CollectionMulticolumnView extends CollectionSubView() {
                 }
             });
             if (super.onInternalDrop(e, de)) {
-                de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => {
-                    d._dimUnit = "*";
-                    d._dimMagnitude = 1;
-                    if (dropInd !== curInd || dropInd === -1) {
-                        if (this.childDocs.includes(d)) {
-                            if (dropInd > this.childDocs.indexOf(d)) dropInd--;
+                de.complete.docDragData?.droppedDocuments.forEach(
+                    action((d: Doc) => {
+                        d._dimUnit = '*';
+                        d._dimMagnitude = 1;
+                        if (dropInd !== curInd || dropInd === -1) {
+                            if (this.childDocs.includes(d)) {
+                                if (dropInd > this.childDocs.indexOf(d)) dropInd--;
+                            }
+                            Doc.RemoveDocFromList(this.rootDoc, this.props.fieldKey, d);
+                            Doc.AddDocToList(this.rootDoc, this.props.fieldKey, d, DocListCast(this.rootDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1);
                         }
-                        Doc.RemoveDocFromList(this.rootDoc, this.props.fieldKey, d);
-                        Doc.AddDocToList(this.rootDoc, this.props.fieldKey, d, DocListCast(this.rootDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1);
-                    }
-                }));
+                    })
+                );
             }
         }
         return false;
-    }
-
+    };
 
     onChildClickHandler = () => ScriptCast(this.Document.onChildClick);
     onChildDoubleClickHandler = () => ScriptCast(this.Document.onChildDoubleClick);
 
     addDocTab = (doc: Doc, where: string) => {
-        if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
+        if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) {
             this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
             return true;
         }
         return this.props.addDocTab(doc, where);
-    }
+    };
     isContentActive = () => this.props.isSelected() || this.props.isContentActive();
-    isChildContentActive = () => ((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false;
+    isChildContentActive = () =>
+        ((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false;
     getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => {
-        return <DocumentView
-            Document={layout}
-            DataDoc={layout.resolvedDataDoc as Doc}
-            styleProvider={this.props.styleProvider}
-            docViewPath={this.props.docViewPath}
-            LayoutTemplate={this.props.childLayoutTemplate}
-            LayoutTemplateString={this.props.childLayoutString}
-            renderDepth={this.props.renderDepth + 1}
-            PanelWidth={width}
-            PanelHeight={height}
-            rootSelected={this.rootSelected}
-            dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
-            onClick={this.onChildClickHandler}
-            onDoubleClick={this.onChildDoubleClickHandler}
-            suppressSetHeight={true}
-            ScreenToLocalTransform={dxf}
-            isContentActive={this.isChildContentActive}
-            isDocumentActive={this.props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
-            hideResizeHandles={this.props.childHideResizeHandles?.()}
-            hideDecorationTitle={this.props.childHideDecorationTitle?.()}
-            fitContentsToBox={this.props.fitContentsToBox}
-            focus={this.props.focus}
-            docFilters={this.childDocFilters}
-            docRangeFilters={this.childDocRangeFilters}
-            searchFilterDocs={this.searchFilterDocs}
-            ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-            ContainingCollectionView={this.props.CollectionView}
-            dontRegisterView={this.props.dontRegisterView}
-            addDocument={this.props.addDocument}
-            moveDocument={this.props.moveDocument}
-            removeDocument={this.props.removeDocument}
-            whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
-            addDocTab={this.addDocTab}
-            pinToPres={this.props.pinToPres}
-            bringToFront={returnFalse}
-        />;
-    }
+        return (
+            <DocumentView
+                Document={layout}
+                DataDoc={layout.resolvedDataDoc as Doc}
+                styleProvider={this.props.styleProvider}
+                docViewPath={this.props.docViewPath}
+                LayoutTemplate={this.props.childLayoutTemplate}
+                LayoutTemplateString={this.props.childLayoutString}
+                renderDepth={this.props.renderDepth + 1}
+                PanelWidth={width}
+                PanelHeight={height}
+                rootSelected={this.rootSelected}
+                dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
+                onClick={this.onChildClickHandler}
+                onDoubleClick={this.onChildDoubleClickHandler}
+                suppressSetHeight={true}
+                ScreenToLocalTransform={dxf}
+                isContentActive={this.isChildContentActive}
+                isDocumentActive={this.props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
+                hideResizeHandles={this.props.childHideResizeHandles?.()}
+                hideDecorationTitle={this.props.childHideDecorationTitle?.()}
+                fitContentsToBox={this.props.fitContentsToBox}
+                focus={this.props.focus}
+                docFilters={this.childDocFilters}
+                docRangeFilters={this.childDocRangeFilters}
+                searchFilterDocs={this.searchFilterDocs}
+                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+                ContainingCollectionView={this.props.CollectionView}
+                dontRegisterView={this.props.dontRegisterView}
+                addDocument={this.props.addDocument}
+                moveDocument={this.props.moveDocument}
+                removeDocument={this.props.removeDocument}
+                whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
+                addDocTab={this.addDocTab}
+                pinToPres={this.props.pinToPres}
+                bringToFront={returnFalse}
+            />
+        );
+    };
     /**
      * @returns the resolved list of rendered child documents, displayed
-     * at their resolved pixel widths, each separated by a resizer. 
+     * at their resolved pixel widths, each separated by a resizer.
      */
     @computed
     private get contents(): JSX.Element[] | null {
@@ -293,22 +295,20 @@ export class CollectionMulticolumnView extends CollectionSubView() {
         const collector: JSX.Element[] = [];
         for (let i = 0; i < childLayoutPairs.length; i++) {
             const { layout } = childLayoutPairs[i];
-            const dxf = () => this.lookupIndividualTransform(layout).translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin)).scale((this.props.scaling?.() || 1));
+            const dxf = () =>
+                this.lookupIndividualTransform(layout)
+                    .translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin))
+                    .scale(this.props.NativeDimScaling?.() || 1);
             const width = () => this.lookupPixels(layout);
             const height = () => PanelHeight() - 2 * NumCast(Document._yMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0);
             collector.push(
-                <div className={"document-wrapper"}
-                    key={"wrapper" + i}
-                    style={{ width: width() }} >
+                <div className={'document-wrapper'} key={'wrapper' + i} style={{ width: width() }}>
                     {this.getDisplayDoc(layout, dxf, width, height)}
-                    <WidthLabel
-                        layout={layout}
-                        collectionDoc={Document}
-                    />
+                    <WidthLabel layout={layout} collectionDoc={Document} />
                 </div>,
                 <ResizeBar
                     width={resizerWidth}
-                    key={"resizer" + i}
+                    key={'resizer' + i}
                     styleProvider={this.props.styleProvider}
                     isContentActive={this.props.isContentActive}
                     select={this.props.select}
@@ -324,16 +324,19 @@ export class CollectionMulticolumnView extends CollectionSubView() {
 
     render(): JSX.Element {
         return (
-            <div className={"collectionMulticolumnView_contents"} ref={this.createDashEventsTarget}
+            <div
+                className={'collectionMulticolumnView_contents'}
+                ref={this.createDashEventsTarget}
                 style={{
                     width: `calc(100% - ${2 * NumCast(this.props.Document._xMargin)}px)`,
                     height: `calc(100% - ${2 * NumCast(this.props.Document._yMargin)}px)`,
-                    marginLeft: NumCast(this.props.Document._xMargin), marginRight: NumCast(this.props.Document._xMargin),
-                    marginTop: NumCast(this.props.Document._yMargin), marginBottom: NumCast(this.props.Document._yMargin)
-                }} >
+                    marginLeft: NumCast(this.props.Document._xMargin),
+                    marginRight: NumCast(this.props.Document._xMargin),
+                    marginTop: NumCast(this.props.Document._yMargin),
+                    marginBottom: NumCast(this.props.Document._yMargin),
+                }}>
                 {this.contents}
             </div>
         );
     }
-
-}
\ No newline at end of file
+}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 08385bcb5..f8de4e5de 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -1,6 +1,6 @@
 import { action, computed } from 'mobx';
 import { observer } from 'mobx-react';
-import * as React from "react";
+import * as React from 'react';
 import { Doc, DocListCast } from '../../../../fields/Doc';
 import { List } from '../../../../fields/List';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
@@ -11,7 +11,7 @@ import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
 import { DocumentView } from '../../nodes/DocumentView';
 import { CollectionSubView } from '../CollectionSubView';
-import "./CollectionMultirowView.scss";
+import './CollectionMultirowView.scss';
 import HeightLabel from './MultirowHeightLabel';
 import ResizeBar from './MultirowResizer';
 
@@ -26,8 +26,8 @@ interface LayoutData {
 }
 
 export const DimUnit = {
-    Pixel: "px",
-    Ratio: "*"
+    Pixel: 'px',
+    Ratio: '*',
 };
 
 const resolvedUnits = Object.values(DimUnit);
@@ -35,14 +35,13 @@ const resizerHeight = 8;
 
 @observer
 export class CollectionMultirowView extends CollectionSubView() {
-
     /**
      * @returns the list of layout documents whose width unit is
      * *, denoting that it will be displayed with a ratio, not fixed pixel, value
      */
     @computed
     private get ratioDefinedDocs() {
-        return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout._dimUnit, "*") === DimUnit.Ratio);
+        return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout._dimUnit, '*') === DimUnit.Ratio);
     }
 
     @computed
@@ -64,10 +63,10 @@ export class CollectionMultirowView extends CollectionSubView() {
         let starSum = 0;
         const heightSpecifiers: HeightSpecifier[] = [];
         this.childLayoutPairs.map(pair => {
-            const unit = StrCast(pair.layout._dimUnit, "*");
+            const unit = StrCast(pair.layout._dimUnit, '*');
             const magnitude = NumCast(pair.layout._dimMagnitude, this.minimumDim);
             if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) {
-                (unit === DimUnit.Ratio) && (starSum += magnitude);
+                unit === DimUnit.Ratio && (starSum += magnitude);
                 heightSpecifiers.push({ magnitude, unit });
             }
             /**
@@ -99,14 +98,13 @@ export class CollectionMultirowView extends CollectionSubView() {
      * This returns the total quantity, in pixels, that this
      * view needs to reserve for child documents that have
      * (with higher priority) requested a fixed pixel width.
-     * 
+     *
      * If the underlying resolvedLayoutInformation returns null
      * because we're waiting on promises to resolve, this value will be undefined as well.
      */
     @computed
     private get totalFixedAllocation(): number | undefined {
-        return this.resolvedLayoutInformation?.heightSpecifiers.reduce(
-            (sum, { magnitude, unit }) => sum + (unit === DimUnit.Pixel ? magnitude : 0), 0);
+        return this.resolvedLayoutInformation?.heightSpecifiers.reduce((sum, { magnitude, unit }) => sum + (unit === DimUnit.Pixel ? magnitude : 0), 0);
     }
 
     /**
@@ -114,7 +112,7 @@ export class CollectionMultirowView extends CollectionSubView() {
      * view needs to reserve for child documents that have
      * (with lower priority) requested a certain relative proportion of the
      * remaining pixel width not allocated for fixed widths.
-     * 
+     *
      * If the underlying totalFixedAllocation returns undefined
      * because we're waiting indirectly on promises to resolve, this value will be undefined as well.
      */
@@ -134,7 +132,7 @@ export class CollectionMultirowView extends CollectionSubView() {
      * this accessor returns 1000 / (2 + 2 + 1), or 200px.
      * Elsewhere, this is then multiplied by each relative-width
      * document's (potentially decimal) * count to compute its actual width (400px, 400px and 200px).
-     * 
+     *
      * If the underlying totalRatioAllocation or this.resolveLayoutInformation return undefined
      * because we're waiting indirectly on promises to resolve, this value will be undefined as well.
      */
@@ -164,17 +162,17 @@ export class CollectionMultirowView extends CollectionSubView() {
             return 0; // we're still waiting on promises to resolve
         }
         let height = NumCast(layout._dimMagnitude, this.minimumDim);
-        if (StrCast(layout._dimUnit, "*") === DimUnit.Ratio) {
+        if (StrCast(layout._dimUnit, '*') === DimUnit.Ratio) {
             height *= rowUnitLength;
         }
         return height;
-    }
+    };
 
     /**
      * @returns the transform that will correctly place
      * the document decorations box, shifted to the right by
      * the sum of all the resolved row widths of the
-     * documents before the target. 
+     * documents before the target.
      */
     private lookupIndividualTransform = (layout: Doc) => {
         const rowUnitLength = this.rowUnitLength;
@@ -184,13 +182,12 @@ export class CollectionMultirowView extends CollectionSubView() {
         let offset = 0;
         for (const { layout: candidate } of this.childLayoutPairs) {
             if (candidate === layout) {
-                return this.props.ScreenToLocalTransform().translate(0, -offset / (this.props.scaling?.() || 1));
+                return this.props.ScreenToLocalTransform().translate(0, -offset / (this.props.NativeDimScaling?.() || 1));
             }
             offset += this.lookupPixels(candidate) + resizerHeight;
         }
         return Transform.Identity(); // type coersion, this case should never be hit
-    }
-
+    };
 
     @undoBatch
     @action
@@ -198,16 +195,17 @@ export class CollectionMultirowView extends CollectionSubView() {
         let dropInd = -1;
         if (de.complete.docDragData && this._mainCont) {
             let curInd = -1;
-            de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => {
-                curInd = this.childDocs.indexOf(d);
-            }));
+            de.complete.docDragData?.droppedDocuments.forEach(
+                action((d: Doc) => {
+                    curInd = this.childDocs.indexOf(d);
+                })
+            );
             Array.from(this._mainCont.children).forEach((child, index) => {
                 const brect = child.getBoundingClientRect();
                 if (brect.y < de.y && brect.y + brect.height > de.y) {
                     if (curInd !== -1 && curInd === Math.floor(index / 2)) {
                         dropInd = curInd;
-                    }
-                    else if (child.className === "multiColumnResizer") {
+                    } else if (child.className === 'multiColumnResizer') {
                         dropInd = Math.floor(index / 2);
                     } else {
                         dropInd = Math.ceil(index / 2 + (de.y - brect.y > brect.height / 2 ? 0 : -1));
@@ -215,75 +213,79 @@ export class CollectionMultirowView extends CollectionSubView() {
                 }
             });
             if (super.onInternalDrop(e, de)) {
-                de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => {
-                    d._dimUnit = "*";
-                    d._dimMagnitude = 1;
-                    if (dropInd !== curInd || dropInd === -1) {
-                        if (this.childDocs.includes(d)) {
-                            if (dropInd > this.childDocs.indexOf(d)) dropInd--;
+                de.complete.docDragData?.droppedDocuments.forEach(
+                    action((d: Doc) => {
+                        d._dimUnit = '*';
+                        d._dimMagnitude = 1;
+                        if (dropInd !== curInd || dropInd === -1) {
+                            if (this.childDocs.includes(d)) {
+                                if (dropInd > this.childDocs.indexOf(d)) dropInd--;
+                            }
+                            Doc.RemoveDocFromList(this.rootDoc, this.props.fieldKey, d);
+                            Doc.AddDocToList(this.rootDoc, this.props.fieldKey, d, DocListCast(this.rootDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1);
                         }
-                        Doc.RemoveDocFromList(this.rootDoc, this.props.fieldKey, d);
-                        Doc.AddDocToList(this.rootDoc, this.props.fieldKey, d, DocListCast(this.rootDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1);
-                    }
-                }));
+                    })
+                );
             }
         }
         return false;
-    }
-
+    };
 
     onChildClickHandler = () => ScriptCast(this.Document.onChildClick);
     onChildDoubleClickHandler = () => ScriptCast(this.Document.onChildDoubleClick);
 
     addDocTab = (doc: Doc, where: string) => {
-        if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
+        if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) {
             this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
             return true;
         }
         return this.props.addDocTab(doc, where);
-    }
+    };
     isContentActive = () => this.props.isSelected() || this.props.isContentActive();
-    isChildContentActive = () => ((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false;
+    isChildContentActive = () =>
+        ((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false;
     getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => {
-        return <DocumentView
-            Document={layout}
-            DataDoc={layout.resolvedDataDoc as Doc}
-            styleProvider={this.props.styleProvider}
-            docViewPath={this.props.docViewPath}
-            LayoutTemplate={this.props.childLayoutTemplate}
-            LayoutTemplateString={this.props.childLayoutString}
-            renderDepth={this.props.renderDepth + 1}
-            PanelWidth={width}
-            PanelHeight={height}
-            rootSelected={this.rootSelected}
-            dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
-            onClick={this.onChildClickHandler}
-            onDoubleClick={this.onChildDoubleClickHandler}
-            ScreenToLocalTransform={dxf}
-            isContentActive={this.isChildContentActive}
-            isDocumentActive={this.props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
-            hideResizeHandles={this.props.childHideResizeHandles?.()}
-            hideDecorationTitle={this.props.childHideDecorationTitle?.()}
-            fitContentsToBox={this.props.fitContentsToBox}
-            focus={this.props.focus}
-            docFilters={this.childDocFilters}
-            docRangeFilters={this.childDocRangeFilters}
-            searchFilterDocs={this.searchFilterDocs}
-            ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-            ContainingCollectionView={this.props.CollectionView}
-            dontRegisterView={this.props.dontRegisterView}
-            addDocument={this.props.addDocument}
-            moveDocument={this.props.moveDocument}
-            removeDocument={this.props.removeDocument}
-            whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
-            addDocTab={this.addDocTab}
-            pinToPres={this.props.pinToPres}
-            bringToFront={returnFalse}
-        />;
-    }
+        return (
+            <DocumentView
+                Document={layout}
+                DataDoc={layout.resolvedDataDoc as Doc}
+                styleProvider={this.props.styleProvider}
+                docViewPath={this.props.docViewPath}
+                LayoutTemplate={this.props.childLayoutTemplate}
+                LayoutTemplateString={this.props.childLayoutString}
+                renderDepth={this.props.renderDepth + 1}
+                PanelWidth={width}
+                PanelHeight={height}
+                rootSelected={this.rootSelected}
+                dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
+                onClick={this.onChildClickHandler}
+                onDoubleClick={this.onChildDoubleClickHandler}
+                ScreenToLocalTransform={dxf}
+                isContentActive={this.isChildContentActive}
+                isDocumentActive={this.props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
+                hideResizeHandles={this.props.childHideResizeHandles?.()}
+                hideDecorationTitle={this.props.childHideDecorationTitle?.()}
+                fitContentsToBox={this.props.fitContentsToBox}
+                focus={this.props.focus}
+                docFilters={this.childDocFilters}
+                docRangeFilters={this.childDocRangeFilters}
+                searchFilterDocs={this.searchFilterDocs}
+                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+                ContainingCollectionView={this.props.CollectionView}
+                dontRegisterView={this.props.dontRegisterView}
+                addDocument={this.props.addDocument}
+                moveDocument={this.props.moveDocument}
+                removeDocument={this.props.removeDocument}
+                whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
+                addDocTab={this.addDocTab}
+                pinToPres={this.props.pinToPres}
+                bringToFront={returnFalse}
+            />
+        );
+    };
     /**
      * @returns the resolved list of rendered child documents, displayed
-     * at their resolved pixel widths, each separated by a resizer. 
+     * at their resolved pixel widths, each separated by a resizer.
      */
     @computed
     private get contents(): JSX.Element[] | null {
@@ -292,13 +294,14 @@ export class CollectionMultirowView extends CollectionSubView() {
         const collector: JSX.Element[] = [];
         for (let i = 0; i < childLayoutPairs.length; i++) {
             const { layout } = childLayoutPairs[i];
-            const dxf = () => this.lookupIndividualTransform(layout).translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin)).scale((this.props.scaling?.() || 1));
+            const dxf = () =>
+                this.lookupIndividualTransform(layout)
+                    .translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin))
+                    .scale(this.props.NativeDimScaling?.() || 1);
             const height = () => this.lookupPixels(layout);
             const width = () => PanelWidth() - 2 * NumCast(Document._xMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0);
             collector.push(
-                <div className={"document-wrapper"}
-                    style={{ height: height() }}
-                    key={"wrapper" + i} >
+                <div className={'document-wrapper'} style={{ height: height() }} key={'wrapper' + i}>
                     {this.getDisplayDoc(layout, dxf, width, height)}
                     <HeightLabel layout={layout} collectionDoc={Document} />
                 </div>,
@@ -306,7 +309,7 @@ export class CollectionMultirowView extends CollectionSubView() {
                     height={resizerHeight}
                     styleProvider={this.props.styleProvider}
                     isContentActive={this.props.isContentActive}
-                    key={"resizer" + i}
+                    key={'resizer' + i}
                     columnUnitLength={this.getRowUnitLength}
                     toTop={layout}
                     toBottom={childLayoutPairs[i + 1]?.layout}
@@ -319,16 +322,19 @@ export class CollectionMultirowView extends CollectionSubView() {
 
     render(): JSX.Element {
         return (
-            <div className={"collectionMultirowView_contents"}
+            <div
+                className={'collectionMultirowView_contents'}
                 style={{
                     width: `calc(100% - ${2 * NumCast(this.props.Document._xMargin)}px)`,
                     height: `calc(100% - ${2 * NumCast(this.props.Document._yMargin)}px)`,
-                    marginLeft: NumCast(this.props.Document._xMargin), marginRight: NumCast(this.props.Document._xMargin),
-                    marginTop: NumCast(this.props.Document._yMargin), marginBottom: NumCast(this.props.Document._yMargin)
-                }} ref={this.createDashEventsTarget}>
+                    marginLeft: NumCast(this.props.Document._xMargin),
+                    marginRight: NumCast(this.props.Document._xMargin),
+                    marginTop: NumCast(this.props.Document._yMargin),
+                    marginBottom: NumCast(this.props.Document._yMargin),
+                }}
+                ref={this.createDashEventsTarget}>
                 {this.contents}
             </div>
         );
     }
-
-}
\ No newline at end of file
+}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index f1d8123da..381436a56 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -118,7 +118,7 @@ export class DocumentContentsView extends React.Component<
         FormattedTextBoxProps & {
             isSelected: (outsideReaction: boolean) => boolean;
             select: (ctrl: boolean) => void;
-            scaling?: () => number;
+            NativeDimScaling?: () => number;
             setHeight?: (height: number) => void;
             layoutKey: string;
         }
@@ -161,7 +161,6 @@ export class DocumentContentsView extends React.Component<
             'LayoutTemplateString',
             'LayoutTemplate',
             'dontCenter',
-            'ContentScaling',
             'contextMenuItems',
             'onClick',
             'onDoubleClick',
@@ -195,7 +194,7 @@ export class DocumentContentsView extends React.Component<
 
         // replace HTML<tag> with corresponding HTML tag as in:  <HTMLdiv> becomes  <HTMLtag Document={props.Document} htmltag='div'>
         const replacer2 = (match: any, p1: string, offset: any, string: any) => {
-            return `<HTMLtag RootDoc={props.RootDoc} Document={props.Document} scaling='${this.props.scaling?.() || 1}' htmltag='${p1}'`;
+            return `<HTMLtag RootDoc={props.RootDoc} Document={props.Document} scaling='${this.props.NativeDimScaling?.() || 1}' htmltag='${p1}'`;
         };
         layoutFrame = layoutFrame.replace(/<HTML([a-zA-Z0-9_-]+)/g, replacer2);
 
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 78d35ab99..5939d1680 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -1,24 +1,24 @@
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { Tooltip } from "@material-ui/core";
-import { action, computed, observable, runInAction } from "mobx";
-import { observer } from "mobx-react";
-import { Doc, Opt } from "../../../fields/Doc";
-import { StrCast } from "../../../fields/Types";
-import { TraceMobx } from "../../../fields/util";
-import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../../Utils";
-import { DocUtils } from "../../documents/Documents";
-import { DragManager } from "../../util/DragManager";
-import { Hypothesis } from "../../util/HypothesisUtils";
-import { LinkManager } from "../../util/LinkManager";
-import { undoBatch, UndoManager } from "../../util/UndoManager";
-import { Colors } from "../global/globalEnums";
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Tooltip } from '@material-ui/core';
+import { action, computed, observable, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import { Doc, Opt } from '../../../fields/Doc';
+import { StrCast } from '../../../fields/Types';
+import { TraceMobx } from '../../../fields/util';
+import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils';
+import { DocUtils } from '../../documents/Documents';
+import { DragManager } from '../../util/DragManager';
+import { Hypothesis } from '../../util/HypothesisUtils';
+import { LinkManager } from '../../util/LinkManager';
+import { undoBatch, UndoManager } from '../../util/UndoManager';
+import { Colors } from '../global/globalEnums';
 import './DocumentLinksButton.scss';
-import { DocumentView } from "./DocumentView";
-import { LinkDescriptionPopup } from "./LinkDescriptionPopup";
-import { TaskCompletionBox } from "./TaskCompletedBox";
-import React = require("react");
+import { DocumentView } from './DocumentView';
+import { LinkDescriptionPopup } from './LinkDescriptionPopup';
+import { TaskCompletionBox } from './TaskCompletedBox';
+import React = require('react');
 
-const higflyout = require("@hig/flyout");
+const higflyout = require('@hig/flyout');
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
 
@@ -28,7 +28,7 @@ interface DocumentLinksButtonProps {
     AlwaysOn?: boolean;
     InMenu?: boolean;
     StartLink?: boolean; //whether the link HAS been started (i.e. now needs to be completed)
-    ContentScaling?: () => number;
+    scaling?: () => number; // how uch doc is scaled so that link buttons can invert it
 }
 @observer
 export class DocumentLinksButton extends React.Component<DocumentLinksButtonProps, {}> {
@@ -42,53 +42,71 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
     @observable public static invisibleWebDoc: Opt<Doc>;
     public static invisibleWebRef = React.createRef<HTMLDivElement>();
 
-    @action @undoBatch
+    @action
+    @undoBatch
     onLinkButtonMoved = (e: PointerEvent) => {
         if (this.props.InMenu && this.props.StartLink) {
             if (this._linkButton.current !== null) {
-                const linkDrag = UndoManager.StartBatch("Drag Link");
-                this.props.View && DragManager.StartLinkDrag(this._linkButton.current, this.props.View, this.props.View.ComponentView?.getAnchor, e.pageX, e.pageY, {
-                    dragComplete: dropEv => {
-                        if (this.props.View && dropEv.linkDocument) {// dropEv.linkDocument equivalent to !dropEve.aborted since linkDocument is only assigned on a completed drop
-                            !dropEv.linkDocument.linkRelationship && (Doc.GetProto(dropEv.linkDocument).linkRelationship = "hyperlink");
-                        }
-                        linkDrag?.end();
-                    },
-                    hideSource: false
-                });
+                const linkDrag = UndoManager.StartBatch('Drag Link');
+                this.props.View &&
+                    DragManager.StartLinkDrag(this._linkButton.current, this.props.View, this.props.View.ComponentView?.getAnchor, e.pageX, e.pageY, {
+                        dragComplete: dropEv => {
+                            if (this.props.View && dropEv.linkDocument) {
+                                // dropEv.linkDocument equivalent to !dropEve.aborted since linkDocument is only assigned on a completed drop
+                                !dropEv.linkDocument.linkRelationship && (Doc.GetProto(dropEv.linkDocument).linkRelationship = 'hyperlink');
+                            }
+                            linkDrag?.end();
+                        },
+                        hideSource: false,
+                    });
                 return true;
             }
             return false;
         }
         return false;
-    }
+    };
 
     onLinkMenuOpen = (e: React.PointerEvent): void => {
-        setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, action((e, doubleTap) => {
-            if (doubleTap) {
-                DocumentView.showBackLinks(this.props.View.rootDoc);
-            }
-        }), undefined, undefined,
-            action(() => DocumentLinksButton.LinkEditorDocView = this.props.View));
-    }
+        setupMoveUpEvents(
+            this,
+            e,
+            this.onLinkButtonMoved,
+            emptyFunction,
+            action((e, doubleTap) => {
+                if (doubleTap) {
+                    DocumentView.showBackLinks(this.props.View.rootDoc);
+                }
+            }),
+            undefined,
+            undefined,
+            action(() => (DocumentLinksButton.LinkEditorDocView = this.props.View))
+        );
+    };
 
     @undoBatch
     onLinkButtonDown = (e: React.PointerEvent): void => {
-        setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, action((e, doubleTap) => {
-            if (doubleTap && this.props.InMenu && this.props.StartLink) {
-                //action(() => Doc.BrushDoc(this.props.View.Document));
-                if (DocumentLinksButton.StartLink === this.props.View.props.Document) {
-                    DocumentLinksButton.StartLink = undefined;
-                    DocumentLinksButton.StartLinkView = undefined;
-                } else {
-                    DocumentLinksButton.StartLink = this.props.View.props.Document;
-                    DocumentLinksButton.StartLinkView = this.props.View;
+        setupMoveUpEvents(
+            this,
+            e,
+            this.onLinkButtonMoved,
+            emptyFunction,
+            action((e, doubleTap) => {
+                if (doubleTap && this.props.InMenu && this.props.StartLink) {
+                    //action(() => Doc.BrushDoc(this.props.View.Document));
+                    if (DocumentLinksButton.StartLink === this.props.View.props.Document) {
+                        DocumentLinksButton.StartLink = undefined;
+                        DocumentLinksButton.StartLinkView = undefined;
+                    } else {
+                        DocumentLinksButton.StartLink = this.props.View.props.Document;
+                        DocumentLinksButton.StartLinkView = this.props.View;
+                    }
                 }
-            }
-        }));
-    }
+            })
+        );
+    };
 
-    @action @undoBatch
+    @action
+    @undoBatch
     onLinkClick = (e: React.MouseEvent): void => {
         if (this.props.InMenu && this.props.StartLink) {
             DocumentLinksButton.AnnotationId = undefined;
@@ -96,108 +114,125 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
             if (DocumentLinksButton.StartLink === this.props.View.props.Document) {
                 DocumentLinksButton.StartLink = undefined;
                 DocumentLinksButton.StartLinkView = undefined;
-            } else { //if this LinkButton's Document is undefined
+            } else {
+                //if this LinkButton's Document is undefined
                 DocumentLinksButton.StartLink = this.props.View.props.Document;
                 DocumentLinksButton.StartLinkView = this.props.View;
             }
             //action(() => Doc.BrushDoc(this.props.View.Document));
         }
-    }
-
+    };
 
     completeLink = (e: React.PointerEvent): void => {
-        setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action((e, doubleTap) => {
-            if (doubleTap && !this.props.StartLink) {
-                if (DocumentLinksButton.StartLink === this.props.View.props.Document) {
-                    DocumentLinksButton.StartLink = undefined;
-                    DocumentLinksButton.StartLinkView = undefined;
-                    DocumentLinksButton.AnnotationId = undefined;
-                } else if (DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document) {
-                    const sourceDoc = DocumentLinksButton.StartLink;
-                    const targetDoc = this.props.View.ComponentView?.getAnchor?.() || this.props.View.Document;
-                    const linkDoc = DocUtils.MakeLink({ doc: sourceDoc }, { doc: targetDoc }, "links"); //why is long drag here when this is used for completing links by clicking?
+        setupMoveUpEvents(
+            this,
+            e,
+            returnFalse,
+            emptyFunction,
+            undoBatch(
+                action((e, doubleTap) => {
+                    if (doubleTap && !this.props.StartLink) {
+                        if (DocumentLinksButton.StartLink === this.props.View.props.Document) {
+                            DocumentLinksButton.StartLink = undefined;
+                            DocumentLinksButton.StartLinkView = undefined;
+                            DocumentLinksButton.AnnotationId = undefined;
+                        } else if (DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document) {
+                            const sourceDoc = DocumentLinksButton.StartLink;
+                            const targetDoc = this.props.View.ComponentView?.getAnchor?.() || this.props.View.Document;
+                            const linkDoc = DocUtils.MakeLink({ doc: sourceDoc }, { doc: targetDoc }, 'links'); //why is long drag here when this is used for completing links by clicking?
 
-                    LinkManager.currentLink = linkDoc;
+                            LinkManager.currentLink = linkDoc;
 
-                    runInAction(() => {
-                        if (linkDoc) {
-                            TaskCompletionBox.textDisplayed = "Link Created";
-                            TaskCompletionBox.popupX = e.screenX;
-                            TaskCompletionBox.popupY = e.screenY - 133;
-                            TaskCompletionBox.taskCompleted = true;
+                            runInAction(() => {
+                                if (linkDoc) {
+                                    TaskCompletionBox.textDisplayed = 'Link Created';
+                                    TaskCompletionBox.popupX = e.screenX;
+                                    TaskCompletionBox.popupY = e.screenY - 133;
+                                    TaskCompletionBox.taskCompleted = true;
 
-                            LinkDescriptionPopup.popupX = e.screenX;
-                            LinkDescriptionPopup.popupY = e.screenY - 100;
-                            LinkDescriptionPopup.descriptionPopup = true;
+                                    LinkDescriptionPopup.popupX = e.screenX;
+                                    LinkDescriptionPopup.popupY = e.screenY - 100;
+                                    LinkDescriptionPopup.descriptionPopup = true;
 
-                            const rect = document.body.getBoundingClientRect();
-                            if (LinkDescriptionPopup.popupX + 200 > rect.width) {
-                                LinkDescriptionPopup.popupX -= 190;
-                                TaskCompletionBox.popupX -= 40;
-                            }
-                            if (LinkDescriptionPopup.popupY + 100 > rect.height) {
-                                LinkDescriptionPopup.popupY -= 40;
-                                TaskCompletionBox.popupY -= 40;
-                            }
+                                    const rect = document.body.getBoundingClientRect();
+                                    if (LinkDescriptionPopup.popupX + 200 > rect.width) {
+                                        LinkDescriptionPopup.popupX -= 190;
+                                        TaskCompletionBox.popupX -= 40;
+                                    }
+                                    if (LinkDescriptionPopup.popupY + 100 > rect.height) {
+                                        LinkDescriptionPopup.popupY -= 40;
+                                        TaskCompletionBox.popupY -= 40;
+                                    }
 
-                            setTimeout(action(() => TaskCompletionBox.taskCompleted = false), 2500);
+                                    setTimeout(
+                                        action(() => (TaskCompletionBox.taskCompleted = false)),
+                                        2500
+                                    );
+                                }
+                            });
                         }
-                    });
-                }
-            }
-        })));
-    }
+                    }
+                })
+            )
+        );
+    };
 
-    public static finishLinkClick = undoBatch(action((screenX: number, screenY: number, startLink: Doc, endLink: Doc, startIsAnnotation: boolean, endLinkView?: DocumentView,) => {
-        if (startLink === endLink) {
-            DocumentLinksButton.StartLink = undefined;
-            DocumentLinksButton.StartLinkView = undefined;
-            DocumentLinksButton.AnnotationId = undefined;
-            DocumentLinksButton.AnnotationUri = undefined;
-            //!this.props.StartLink 
-        } else if (startLink !== endLink) {
-            endLink = endLinkView?.docView?._componentView?.getAnchor?.() || endLink;
-            startLink = DocumentLinksButton.StartLinkView?.docView?._componentView?.getAnchor?.() || startLink;
-            const linkDoc = DocUtils.MakeLink({ doc: startLink }, { doc: endLink },
-                DocumentLinksButton.AnnotationId ? "hypothes.is annotation" : undefined, undefined, undefined, true);
+    public static finishLinkClick = undoBatch(
+        action((screenX: number, screenY: number, startLink: Doc, endLink: Doc, startIsAnnotation: boolean, endLinkView?: DocumentView) => {
+            if (startLink === endLink) {
+                DocumentLinksButton.StartLink = undefined;
+                DocumentLinksButton.StartLinkView = undefined;
+                DocumentLinksButton.AnnotationId = undefined;
+                DocumentLinksButton.AnnotationUri = undefined;
+                //!this.props.StartLink
+            } else if (startLink !== endLink) {
+                endLink = endLinkView?.docView?._componentView?.getAnchor?.() || endLink;
+                startLink = DocumentLinksButton.StartLinkView?.docView?._componentView?.getAnchor?.() || startLink;
+                const linkDoc = DocUtils.MakeLink({ doc: startLink }, { doc: endLink }, DocumentLinksButton.AnnotationId ? 'hypothes.is annotation' : undefined, undefined, undefined, true);
 
-            LinkManager.currentLink = linkDoc;
+                LinkManager.currentLink = linkDoc;
 
-            if (DocumentLinksButton.AnnotationId && DocumentLinksButton.AnnotationUri) { // if linking from a Hypothes.is annotation
-                Doc.GetProto(linkDoc as Doc).linksToAnnotation = true;
-                Doc.GetProto(linkDoc as Doc).annotationId = DocumentLinksButton.AnnotationId;
-                Doc.GetProto(linkDoc as Doc).annotationUri = DocumentLinksButton.AnnotationUri;
-                const dashHyperlink = Doc.globalServerPath(startIsAnnotation ? endLink : startLink);
-                Hypothesis.makeLink(StrCast(startIsAnnotation ? endLink.title : startLink.title), dashHyperlink, DocumentLinksButton.AnnotationId,
-                    (startIsAnnotation ? startLink : endLink)); // edit annotation to add a Dash hyperlink to the linked doc
-            }
+                if (DocumentLinksButton.AnnotationId && DocumentLinksButton.AnnotationUri) {
+                    // if linking from a Hypothes.is annotation
+                    Doc.GetProto(linkDoc as Doc).linksToAnnotation = true;
+                    Doc.GetProto(linkDoc as Doc).annotationId = DocumentLinksButton.AnnotationId;
+                    Doc.GetProto(linkDoc as Doc).annotationUri = DocumentLinksButton.AnnotationUri;
+                    const dashHyperlink = Doc.globalServerPath(startIsAnnotation ? endLink : startLink);
+                    Hypothesis.makeLink(StrCast(startIsAnnotation ? endLink.title : startLink.title), dashHyperlink, DocumentLinksButton.AnnotationId, startIsAnnotation ? startLink : endLink); // edit annotation to add a Dash hyperlink to the linked doc
+                }
 
-            if (linkDoc) {
-                TaskCompletionBox.textDisplayed = "Link Created";
-                TaskCompletionBox.popupX = screenX;
-                TaskCompletionBox.popupY = screenY - 133;
-                TaskCompletionBox.taskCompleted = true;
+                if (linkDoc) {
+                    TaskCompletionBox.textDisplayed = 'Link Created';
+                    TaskCompletionBox.popupX = screenX;
+                    TaskCompletionBox.popupY = screenY - 133;
+                    TaskCompletionBox.taskCompleted = true;
 
-                if (LinkDescriptionPopup.showDescriptions === "ON" || !LinkDescriptionPopup.showDescriptions) {
-                    LinkDescriptionPopup.popupX = screenX;
-                    LinkDescriptionPopup.popupY = screenY - 100;
-                    LinkDescriptionPopup.descriptionPopup = true;
-                }
+                    if (LinkDescriptionPopup.showDescriptions === 'ON' || !LinkDescriptionPopup.showDescriptions) {
+                        LinkDescriptionPopup.popupX = screenX;
+                        LinkDescriptionPopup.popupY = screenY - 100;
+                        LinkDescriptionPopup.descriptionPopup = true;
+                    }
 
-                const rect = document.body.getBoundingClientRect();
-                if (LinkDescriptionPopup.popupX + 200 > rect.width) {
-                    LinkDescriptionPopup.popupX -= 190;
-                    TaskCompletionBox.popupX -= 40;
-                }
-                if (LinkDescriptionPopup.popupY + 100 > rect.height) {
-                    LinkDescriptionPopup.popupY -= 40;
-                    TaskCompletionBox.popupY -= 40;
-                }
+                    const rect = document.body.getBoundingClientRect();
+                    if (LinkDescriptionPopup.popupX + 200 > rect.width) {
+                        LinkDescriptionPopup.popupX -= 190;
+                        TaskCompletionBox.popupX -= 40;
+                    }
+                    if (LinkDescriptionPopup.popupY + 100 > rect.height) {
+                        LinkDescriptionPopup.popupY -= 40;
+                        TaskCompletionBox.popupY -= 40;
+                    }
 
-                setTimeout(action(() => { TaskCompletionBox.taskCompleted = false; }), 2500);
+                    setTimeout(
+                        action(() => {
+                            TaskCompletionBox.taskCompleted = false;
+                        }),
+                        2500
+                    );
+                }
             }
-        }
-    }));
+        })
+    );
 
     @action clearLinks() {
         DocumentLinksButton.StartLink = undefined;
@@ -208,9 +243,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
         const results = [] as Doc[];
         const filters = this.props.View.props.docFilters();
         Array.from(new Set<Doc>(this.props.View.allLinks)).forEach(link => {
-            if (DocUtils.FilterDocs([link], filters, []).length ||
-                DocUtils.FilterDocs([link.anchor2 as Doc], filters, []).length ||
-                DocUtils.FilterDocs([link.anchor1 as Doc], filters, []).length) {
+            if (DocUtils.FilterDocs([link], filters, []).length || DocUtils.FilterDocs([link.anchor2 as Doc], filters, []).length || DocUtils.FilterDocs([link.anchor1 as Doc], filters, []).length) {
                 results.push(link);
             }
         });
@@ -219,48 +252,45 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
 
     /**
      * gets the JSX of the link button (btn used to start/complete links) OR the link-view button (btn on bottom left of each linked node)
-     * 
+     *
      * todo:glr / anh seperate functionality such as onClick onPointerDown of link menu button
      */
     @computed get linkButtonInner() {
-        const btnDim = "30px";
-        const link = <img style={{ width: "22px", height: "16px" }} src={`/assets/${"link.png"}`} />;
-        const isActive = (DocumentLinksButton.StartLink === this.props.View.props.Document) && this.props.StartLink;
-        return (!this.props.InMenu ?
-            <div className="documentLinksButton-cont"
-                style={{ left: this.props.Offset?.[0], top: this.props.Offset?.[1], right: this.props.Offset?.[2], bottom: this.props.Offset?.[3] }}
-            >
-                <div className={"documentLinksButton"}
-                    onPointerDown={this.onLinkMenuOpen} onClick={this.onLinkClick}
+        const btnDim = '30px';
+        const link = <img style={{ width: '22px', height: '16px' }} src={`/assets/${'link.png'}`} />;
+        const isActive = DocumentLinksButton.StartLink === this.props.View.props.Document && this.props.StartLink;
+        return !this.props.InMenu ? (
+            <div className="documentLinksButton-cont" style={{ left: this.props.Offset?.[0], top: this.props.Offset?.[1], right: this.props.Offset?.[2], bottom: this.props.Offset?.[3] }}>
+                <div
+                    className={'documentLinksButton'}
+                    onPointerDown={this.onLinkMenuOpen}
+                    onClick={this.onLinkClick}
                     style={{
                         backgroundColor: Colors.LIGHT_BLUE,
                         color: Colors.BLACK,
-                        fontSize: "20px",
+                        fontSize: '20px',
                         width: btnDim,
                         height: btnDim,
                     }}>
                     {Array.from(this.filteredLinks).length}
                 </div>
             </div>
-            :
-            <div className="documentLinksButton-menu" >
-                {this.props.InMenu && !this.props.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document ? //if the origin node is not this node
-                    <div className={"documentLinksButton-endLink"} ref={this._linkButton}
+        ) : (
+            <div className="documentLinksButton-menu">
+                {this.props.InMenu && !this.props.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document ? ( //if the origin node is not this node
+                    <div
+                        className={'documentLinksButton-endLink'}
+                        ref={this._linkButton}
                         onPointerDown={DocumentLinksButton.StartLink && this.completeLink}
                         onClick={e => DocumentLinksButton.StartLink && DocumentLinksButton.finishLinkClick(e.clientX, e.clientY, DocumentLinksButton.StartLink, this.props.View.props.Document, true, this.props.View)}>
                         <FontAwesomeIcon className="documentdecorations-icon" icon="link" />
                     </div>
-                    : (null)
-                }
-                {
-                    this.props.InMenu && this.props.StartLink ? //if link has been started from current node, then set behavior of link button to deactivate linking when clicked again
-                        <div className={`documentLinksButton ${isActive ? `startLink` : ``}`} ref={this._linkButton}
-                            onPointerDown={isActive ? undefined : this.onLinkButtonDown} onClick={isActive ? this.clearLinks : this.onLinkClick}>
-                            <FontAwesomeIcon className="documentdecorations-icon" icon="link" />
-                        </div>
-                        :
-                        (null)
-                }
+                ) : null}
+                {this.props.InMenu && this.props.StartLink ? ( //if link has been started from current node, then set behavior of link button to deactivate linking when clicked again
+                    <div className={`documentLinksButton ${isActive ? `startLink` : ``}`} ref={this._linkButton} onPointerDown={isActive ? undefined : this.onLinkButtonDown} onClick={isActive ? this.clearLinks : this.onLinkClick}>
+                        <FontAwesomeIcon className="documentdecorations-icon" icon="link" />
+                    </div>
+                ) : null}
             </div>
         );
     }
@@ -268,25 +298,23 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
     render() {
         TraceMobx();
 
-        const menuTitle = this.props.StartLink ? "Drag or tap to start link" : "Tap to complete link";
-        const buttonTitle = "Tap to view links; double tap to open link collection";
+        const menuTitle = this.props.StartLink ? 'Drag or tap to start link' : 'Tap to complete link';
+        const buttonTitle = 'Tap to view links; double tap to open link collection';
         const title = this.props.InMenu ? menuTitle : buttonTitle;
 
         //render circular tooltip if it isn't set to invisible and show the number of doc links the node has, and render inner-menu link button for starting/stopping links if currently in menu
-        return (!Array.from(this.filteredLinks).length && !this.props.AlwaysOn) ? (null) :
-            <div className="documentLinksButton-wrapper"
+        return !Array.from(this.filteredLinks).length && !this.props.AlwaysOn ? null : (
+            <div
+                className="documentLinksButton-wrapper"
                 style={{
-                    transform: this.props.InMenu ? undefined :
-                        `scale(${(this.props.ContentScaling?.() || 1) * this.props.View.screenToLocalTransform().Scale})`
-                }} >
-                {
-                    (this.props.InMenu && (DocumentLinksButton.StartLink || this.props.StartLink)) ||
-                        (!DocumentLinksButton.LinkEditorDocView && !this.props.InMenu) ?
-                        <Tooltip title={<div className="dash-tooltip">{title}</div>}>
-                            {this.linkButtonInner}
-                        </Tooltip>
-                        : this.linkButtonInner
-                }
-            </div>;
+                    transform: this.props.InMenu ? undefined : `scale(${this.props.scaling})`,
+                }}>
+                {(this.props.InMenu && (DocumentLinksButton.StartLink || this.props.StartLink)) || (!DocumentLinksButton.LinkEditorDocView && !this.props.InMenu) ? (
+                    <Tooltip title={<div className="dash-tooltip">{title}</div>}>{this.linkButtonInner}</Tooltip>
+                ) : (
+                    this.linkButtonInner
+                )}
+            </div>
+        );
     }
 }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3a8552325..6bf0c365a 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -175,7 +175,6 @@ export interface DocumentViewProps extends DocumentViewSharedProps {
     LayoutTemplateString?: string;
     dontCenter?: 'x' | 'y' | 'xy';
     dontScaleFilter?: (doc: Doc) => boolean; // decides whether a document can be scaled to fit its container vs native size with scrolling
-    ContentScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal
     NativeWidth?: () => number;
     NativeHeight?: () => number;
     LayoutTemplate?: () => Opt<Doc>;
@@ -192,6 +191,7 @@ export interface DocumentViewProps extends DocumentViewSharedProps {
 export interface DocumentViewInternalProps extends DocumentViewProps {
     NativeWidth: () => number;
     NativeHeight: () => number;
+    NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal NOTE: Must also be added to FieldViewProps
     isSelected: (outsideReaction?: boolean) => boolean;
     select: (ctrlPressed: boolean) => void;
     DocumentView: () => DocumentView;
@@ -235,8 +235,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @computed get ShowTitle() {
         return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.ShowTitle) as Opt<string>;
     }
-    @computed get ContentScale() {
-        return this.props.ContentScaling?.() || 1;
+    @computed get NativeDimScaling() {
+        return this.props.NativeDimScaling?.() || 1;
     }
     @computed get thumb() {
         return ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url.href.replace('.png', '_m.png');
@@ -428,7 +428,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 let nheight = Doc.NativeHeight(layoutDoc);
                 const width = layoutDoc._width || 0;
                 const height = layoutDoc._height || (nheight / nwidth) * width;
-                const scale = this.props.ScreenToLocalTransform().Scale * this.ContentScale;
+                const scale = this.props.ScreenToLocalTransform().Scale * this.NativeDimScaling;
                 const actualdW = Math.max(width + dW * scale, 20);
                 const actualdH = Math.max(height + dH * scale, 20);
                 doc.x = (doc.x || 0) + dX * (actualdW - width);
@@ -491,10 +491,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     startDragging(x: number, y: number, dropAction: dropActionType, hideSource = false) {
         if (this._mainCont.current) {
             const dragData = new DragManager.DocumentDragData([this.props.Document]);
-            const [left, top] = this.props.ScreenToLocalTransform().scale(this.ContentScale).inverse().transformPoint(0, 0);
+            const [left, top] = this.props.ScreenToLocalTransform().scale(this.NativeDimScaling).inverse().transformPoint(0, 0);
             dragData.offset = this.props
                 .ScreenToLocalTransform()
-                .scale(this.ContentScale)
+                .scale(this.NativeDimScaling)
                 .transformDirection(x - left, y - top);
             dragData.offset[0] = Math.min(this.rootDoc[WidthSym](), dragData.offset[0]);
             dragData.offset[1] = Math.min(this.rootDoc[HeightSym](), dragData.offset[1]);
@@ -961,7 +961,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     rootSelected = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false;
     panelHeight = () => this.props.PanelHeight() - this.headerMargin;
     screenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -this.headerMargin);
-    contentScaling = () => this.ContentScale;
     onClickFunc = () => this.onClickHandler;
     setHeight = (height: number) => (this.layoutDoc._height = height);
     setContentView = action((view: { getAnchor?: () => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view));
@@ -989,6 +988,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             ? true
             : false;
     };
+    linkButtonInverseScaling = () => (this.props.NativeDimScaling?.() || 1) * this.props.DocumentView().screenToLocalTransform().Scale;
     @computed get contents() {
         TraceMobx();
         const audioView = !this.layoutDoc._showAudio ? null : (
@@ -1041,7 +1041,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     thumbShown={this.thumbShown}
                     isHovering={this.isHovering}
                     setContentView={this.setContentView}
-                    scaling={this.contentScaling}
+                    NativeDimScaling={this.props.NativeDimScaling}
                     PanelHeight={this.panelHeight}
                     setHeight={!this.props.suppressSetHeight ? this.setHeight : undefined}
                     isContentActive={this.isContentActive}
@@ -1055,7 +1055,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 {(!this.props.isSelected() && !this._isHovering) || this.hideLinkButton || this.props.renderDepth === -1 || SnappingManager.GetIsDragging() ? null : (
                     <DocumentLinksButton
                         View={this.props.DocumentView()}
-                        ContentScaling={this.props.ContentScaling}
+                        scaling={this.linkButtonInverseScaling}
                         Offset={[this.topMost ? 0 : !this.props.isSelected() ? -15 : -30, undefined, undefined, this.topMost ? 10 : !this.props.isSelected() ? -15 : -30]}
                     />
                 )}
@@ -1503,7 +1503,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         return this.props.dontCenter?.includes('y') ? 0 : this.Yshift;
     }
 
-    toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.ContentScale, this.props.PanelWidth(), this.props.PanelHeight());
+    toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight());
     focus = (doc: Doc, options?: DocFocusOptions) => this.docView?.focus(doc, options);
     getBounds = () => {
         if (!this.docView || !this.docView.ContentDiv || this.props.Document.presBox || this.docView.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) {
@@ -1564,7 +1564,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     NativeHeight = () => this.effectiveNativeHeight;
     PanelWidth = () => this.panelWidth;
     PanelHeight = () => this.panelHeight;
-    ContentScale = () => this.nativeScaling;
+    NativeDimScaling = () => this.nativeScaling;
     selfView = () => this;
     screenToLocalTransform = () =>
         this.props
@@ -1620,9 +1620,9 @@ export class DocumentView extends React.Component<DocumentViewProps> {
                             PanelHeight={this.PanelHeight}
                             NativeWidth={this.NativeWidth}
                             NativeHeight={this.NativeHeight}
+                            NativeDimScaling={this.NativeDimScaling}
                             isSelected={this.isSelected}
                             select={this.select}
-                            ContentScaling={this.ContentScale}
                             ScreenToLocalTransform={this.screenToLocalTransform}
                             focus={this.props.focus || emptyFunction}
                             ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))}
diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx
index c170f9867..a714518cc 100644
--- a/src/client/views/nodes/EquationBox.tsx
+++ b/src/client/views/nodes/EquationBox.tsx
@@ -12,11 +12,12 @@ import { LightboxView } from '../LightboxView';
 import './EquationBox.scss';
 import { FieldView, FieldViewProps } from './FieldView';
 
-
 @observer
 export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() {
-    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(EquationBox, fieldKey); }
-    public static SelectOnLoad: string = "";
+    public static LayoutString(fieldKey: string) {
+        return FieldView.LayoutString(EquationBox, fieldKey);
+    }
+    public static SelectOnLoad: string = '';
     _ref: React.RefObject<EquationEditor> = React.createRef();
     componentDidMount() {
         if (EquationBox.SelectOnLoad === this.rootDoc[Id] && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath()))) {
@@ -25,75 +26,82 @@ export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() {
             this._ref.current!.mathField.focus();
             this._ref.current!.mathField.select();
         }
-        reaction(() => StrCast(this.dataDoc.text),
+        reaction(
+            () => StrCast(this.dataDoc.text),
             text => {
                 if (text && text !== this._ref.current!.mathField.latex()) {
                     this._ref.current!.mathField.latex(text);
                 }
-            });
-        reaction(() => this.props.isSelected(),
+            }
+        );
+        reaction(
+            () => this.props.isSelected(),
             selected => {
                 if (this._ref.current) {
-                    if (selected) this._ref.current.element.current.children[0].addEventListener("keydown", this.keyPressed, true);
-                    else this._ref.current.element.current.children[0].removeEventListener("keydown", this.keyPressed);
+                    if (selected) this._ref.current.element.current.children[0].addEventListener('keydown', this.keyPressed, true);
+                    else this._ref.current.element.current.children[0].removeEventListener('keydown', this.keyPressed);
                 }
-            }, { fireImmediately: true });
+            },
+            { fireImmediately: true }
+        );
     }
     plot: any;
     @action
     keyPressed = (e: KeyboardEvent) => {
-        const _height = Number(getComputedStyle(this._ref.current!.element.current).height.replace("px", ""));
-        const _width = Number(getComputedStyle(this._ref.current!.element.current).width.replace("px", ""));
-        if (e.key === "Enter") {
+        const _height = Number(getComputedStyle(this._ref.current!.element.current).height.replace('px', ''));
+        const _width = Number(getComputedStyle(this._ref.current!.element.current).width.replace('px', ''));
+        if (e.key === 'Enter') {
             const nextEq = Docs.Create.EquationDocument({
-                title: "# math", text: StrCast(this.dataDoc.text), _width, _height: 25,
-                x: NumCast(this.layoutDoc.x), y: NumCast(this.layoutDoc.y) + _height + 10
+                title: '# math',
+                text: StrCast(this.dataDoc.text),
+                _width,
+                _height: 25,
+                x: NumCast(this.layoutDoc.x),
+                y: NumCast(this.layoutDoc.y) + _height + 10,
             });
             EquationBox.SelectOnLoad = nextEq[Id];
             this.props.addDocument?.(nextEq);
             e.stopPropagation();
-
         }
-        if (e.key === "Tab") {
+        if (e.key === 'Tab') {
             const graph = Docs.Create.FunctionPlotDocument([this.rootDoc], {
                 x: NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym](),
                 y: NumCast(this.layoutDoc.y),
-                _width: 400, _height: 300, backgroundColor: "white"
+                _width: 400,
+                _height: 300,
+                backgroundColor: 'white',
             });
             this.props.addDocument?.(graph);
             e.stopPropagation();
         }
-        if (e.key === "Backspace" && !this.dataDoc.text) this.props.removeDocument?.(this.rootDoc);
-    }
+        if (e.key === 'Backspace' && !this.dataDoc.text) this.props.removeDocument?.(this.rootDoc);
+    };
     onChange = (str: string) => {
         this.dataDoc.text = str;
         const style = this._ref.current && getComputedStyle(this._ref.current.element.current);
         if (style) {
-            const _height = Number(style.height.replace("px", ""));
-            const _width = Number(style.width.replace("px", ""));
+            const _height = Number(style.height.replace('px', ''));
+            const _width = Number(style.width.replace('px', ''));
             this.layoutDoc._width = Math.max(35, _width);
             this.layoutDoc._height = Math.max(25, _height);
         }
-    }
+    };
     render() {
         TraceMobx();
-        const scale = (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
-        return (<div className="equationBox-cont"
-            onPointerDown={e => !e.ctrlKey && e.stopPropagation()}
-            style={{
-                transform: `scale(${scale})`,
-                width: `${100 / scale}%`,
-                height: `${100 / scale}%`,
-                pointerEvents: !this.props.isSelected() ? "none" : undefined,
-            }}
-            onKeyDown={e => e.stopPropagation()}
-        >
-            <EquationEditor ref={this._ref}
-                value={this.dataDoc.text || "x"}
-                spaceBehavesLikeTab={true}
-                onChange={this.onChange}
-                autoCommands="pi theta sqrt sum prod alpha beta gamma rho"
-                autoOperatorNames="sin cos tan" />
-        </div>);
+        const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
+        return (
+            <div
+                className="equationBox-cont"
+                onPointerDown={e => !e.ctrlKey && e.stopPropagation()}
+                style={{
+                    transform: `scale(${scale})`,
+                    width: `${100 / scale}%`,
+                    height: `${100 / scale}%`,
+                    pointerEvents: !this.props.isSelected() ? 'none' : undefined,
+                }}
+                onKeyDown={e => e.stopPropagation()}>
+                <EquationEditor ref={this._ref} value={this.dataDoc.text || 'x'} spaceBehavesLikeTab={true} onChange={this.onChange} autoCommands="pi theta sqrt sum prod alpha beta gamma rho" autoOperatorNames="sin cos tan" />
+            </div>
+        );
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 67cf18d8b..5a6c49809 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -1,18 +1,18 @@
-import React = require("react");
-import { computed } from "mobx";
-import { observer } from "mobx-react";
-import { DateField } from "../../../fields/DateField";
-import { Doc, Field, FieldResult, Opt } from "../../../fields/Doc";
-import { List } from "../../../fields/List";
-import { WebField } from "../../../fields/URLField";
-import { DocumentView, DocumentViewSharedProps } from "./DocumentView";
-import { ScriptField } from "../../../fields/ScriptField";
-import { RecordingBox } from "./RecordingBox";
+import React = require('react');
+import { computed } from 'mobx';
+import { observer } from 'mobx-react';
+import { DateField } from '../../../fields/DateField';
+import { Doc, Field, FieldResult, Opt } from '../../../fields/Doc';
+import { List } from '../../../fields/List';
+import { WebField } from '../../../fields/URLField';
+import { DocumentView, DocumentViewSharedProps } from './DocumentView';
+import { ScriptField } from '../../../fields/ScriptField';
+import { RecordingBox } from './RecordingBox';
 
 //
 // these properties get assigned through the render() method of the DocumentView when it creates this node.
 // However, that only happens because the properties are "defined" in the markup for the field view.
-// See the LayoutString method on each field view :   ImageBox, FormattedTextBox, etc. 
+// See the LayoutString method on each field view :   ImageBox, FormattedTextBox, etc.
 //
 export interface FieldViewProps extends DocumentViewSharedProps {
     // FieldView specific props that are not part of DocumentView props
@@ -23,10 +23,10 @@ export interface FieldViewProps extends DocumentViewSharedProps {
     isContentActive: (outsideReaction?: boolean) => boolean | undefined;
     isDocumentActive?: () => boolean;
     isSelected: (outsideReaction?: boolean) => boolean;
-    scaling?: () => number;
     setHeight?: (height: number) => void;
-    onBrowseClick?: () => (ScriptField | undefined);
-    onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => (boolean | undefined);
+    NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal NOTE: Must also be added to DocumentViewInternalsProps
+    onBrowseClick?: () => ScriptField | undefined;
+    onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined;
 
     // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React)
     pointerEvents?: () => Opt<string>;
@@ -42,7 +42,7 @@ export interface FieldViewProps extends DocumentViewSharedProps {
 @observer
 export class FieldView extends React.Component<FieldViewProps> {
     public static LayoutString(fieldType: { name: string }, fieldStr: string) {
-        return `<${fieldType.name} {...props} fieldKey={'${fieldStr}'}/>`;  //e.g., "<ImageBox {...props} fieldKey={"data} />"
+        return `<${fieldType.name} {...props} fieldKey={'${fieldStr}'}/>`; //e.g., "<ImageBox {...props} fieldKey={"data} />"
     }
 
     @computed
@@ -75,23 +75,22 @@ export class FieldView extends React.Component<FieldViewProps> {
         //}
         else if (field instanceof DateField) {
             return <p>{field.date.toLocaleString()}</p>;
-        }
-        else if (field instanceof Doc) {
-            return <p><b>{field.title?.toString()}</b></p>;
-        }
-        else if (field instanceof List) {
-            return <div> {field.length ? field.map(f => Field.toString(f)).join(", ") : ""}  </div>;
+        } else if (field instanceof Doc) {
+            return (
+                <p>
+                    <b>{field.title?.toString()}</b>
+                </p>
+            );
+        } else if (field instanceof List) {
+            return <div> {field.length ? field.map(f => Field.toString(f)).join(', ') : ''} </div>;
         }
         // bcz: this belongs here, but it doesn't render well so taking it out for now
         else if (field instanceof WebField) {
             return <p>{Field.toString(field.url.href)}</p>;
-        }
-        else if (!(field instanceof Promise)) {
+        } else if (!(field instanceof Promise)) {
             return <p>{Field.toString(field)}</p>;
-        }
-        else {
-            return <p> {"Waiting for server..."} </p>;
+        } else {
+            return <p> {'Waiting for server...'} </p>;
         }
     }
-
-}
\ No newline at end of file
+}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index ffa839fcb..9590bcb15 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -148,8 +148,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         cropping.title = 'crop: ' + this.rootDoc.title;
         cropping.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc._width);
         cropping.y = NumCast(this.rootDoc.y);
-        cropping._width = anchw * (this.props.scaling?.() || 1);
-        cropping._height = anchh * (this.props.scaling?.() || 1);
+        cropping._width = anchw * (this.props.NativeDimScaling?.() || 1);
+        cropping._height = anchh * (this.props.NativeDimScaling?.() || 1);
         cropping.isLinkButton = undefined;
         const croppingProto = Doc.GetProto(cropping);
         croppingProto.annotationOn = undefined;
@@ -384,7 +384,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     render() {
         TraceMobx();
         const borderRad = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BorderRounding);
-        const borderRadius = borderRad?.includes('px') ? `${Number(borderRad.split('px')[0]) / (this.props.scaling?.() || 1)}px` : borderRad;
+        const borderRadius = borderRad?.includes('px') ? `${Number(borderRad.split('px')[0]) / (this.props.NativeDimScaling?.() || 1)}px` : borderRad;
         return (
             <div
                 className="imageBox"
@@ -407,7 +407,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     PanelHeight={this.props.PanelHeight}
                     ScreenToLocalTransform={this.screenToLocalTransform}
                     select={emptyFunction}
-                    scaling={returnOne}
+                    NativeDimScaling={returnOne}
                     whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                     removeDocument={this.removeDocument}
                     moveDocument={this.moveDocument}
@@ -420,7 +420,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         rootDoc={this.rootDoc}
                         scrollTop={0}
                         down={this._marqueeing}
-                        scaling={this.props.scaling}
+                        scaling={this.props.NativeDimScaling}
                         docView={this.props.docViewPath().slice(-1)[0]}
                         addDocument={this.addDocument}
                         finishMarquee={this.finishMarquee}
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index c4b42301e..e9ed594d3 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -373,7 +373,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 runInAction(() => {
                     const localDelta = this.props
                         .ScreenToLocalTransform()
-                        .scale(this.props.scaling?.() || 1)
+                        .scale(this.props.NativeDimScaling?.() || 1)
                         .transformDirection(delta[0], delta[1]);
                     const fullWidth = this.layoutDoc[WidthSym]();
                     const mapWidth = fullWidth - this.sidebarWidth();
@@ -559,8 +559,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         // }
     };
 
-    panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1) - this.sidebarWidth(); // (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);
+    panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth(); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0);
+    panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 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));
     transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
     opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
@@ -589,13 +589,12 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         //     docFilters={docFilters || this.props.docFilters}
         //     dontRenderDocuments={docFilters ? false : true}
         //     select={emptyFunction}
-        //     ContentScaling={returnOne}
         //     bringToFront={emptyFunction}
         //     whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
         //     removeDocument={this.removeDocument}
         //     moveDocument={this.moveDocument}
         //     addDocument={this.sidebarAddDocument}
-        //     childPointerEvents={true}
+        //     childPointerEvents={"all"}
         //     pointerEvents={Doc.ActiveTool !== InkTool.None || this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none"} />;
         return (
             <div className="mapBox" ref={this._ref}>
diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
index 72569135b..630ae18f5 100644
--- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
+++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
@@ -62,7 +62,7 @@ export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps & Vi
                             setHeight={emptyFunction}
                             isAnnotationOverlay={false}
                             select={emptyFunction}
-                            scaling={returnOne}
+                            NativeDimScaling={returnOne}
                             isContentActive={returnTrue}
                             chromeHidden={true}
                             rootSelected={returnFalse}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index fe18abba9..fad22d6e9 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -104,8 +104,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
         const anchx = NumCast(cropping.x);
         const anchy = NumCast(cropping.y);
-        const anchw = cropping[WidthSym]() * (this.props.scaling?.() || 1);
-        const anchh = cropping[HeightSym]() * (this.props.scaling?.() || 1);
+        const anchw = cropping[WidthSym]() * (this.props.NativeDimScaling?.() || 1);
+        const anchh = cropping[HeightSym]() * (this.props.NativeDimScaling?.() || 1);
         const viewScale = 1;
         cropping.title = 'crop: ' + this.rootDoc.title;
         cropping.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc._width);
@@ -290,11 +290,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             (e, down, delta) => {
                 const localDelta = this.props
                     .ScreenToLocalTransform()
-                    .scale(this.props.scaling?.() || 1)
+                    .scale(this.props.NativeDimScaling?.() || 1)
                     .transformDirection(delta[0], delta[1]);
                 const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']);
                 const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth);
-                const ratio = (curNativeWidth + ((onButton ? 1 : -1) * localDelta[0]) / (this.props.scaling?.() || 1)) / nativeWidth;
+                const ratio = (curNativeWidth + ((onButton ? 1 : -1) * localDelta[0]) / (this.props.NativeDimScaling?.() || 1)) / nativeWidth;
                 if (ratio >= 1) {
                     this.layoutDoc.nativeWidth = nativeWidth * ratio;
                     onButton && (this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]);
@@ -433,12 +433,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return this._showSidebar || this.layoutDoc._showSidebar ? true : false;
     }
 
-    contentScaling = () => 1;
     isPdfContentActive = () => this.isAnyChildContentActive() || this.props.isSelected();
     @computed get renderPdfView() {
         TraceMobx();
         const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
-        const scale = previewScale * (this.props.scaling?.() || 1);
+        const scale = previewScale * (this.props.NativeDimScaling?.() || 1);
         return (
             <div
                 className={'pdfBox'}
@@ -473,7 +472,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         removeDocument={this.removeDocument}
                         whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                         crop={this.crop}
-                        ContentScaling={returnOne}
                     />
                 </div>
                 <SidebarAnnos
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 942072524..76a24d831 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -295,7 +295,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                             isAnnotationOverlay={true}
                             select={emptyFunction}
                             isContentActive={returnFalse}
-                            scaling={returnOne}
+                            NativeDimScaling={returnOne}
                             whenChildContentsActiveChanged={emptyFunction}
                             removeDocument={returnFalse}
                             moveDocument={returnFalse}
@@ -317,7 +317,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                                 isAnnotationOverlay={true}
                                 select={emptyFunction}
                                 isContentActive={emptyFunction}
-                                scaling={returnOne}
+                                NativeDimScaling={returnOne}
                                 xPadding={25}
                                 yPadding={10}
                                 whenChildContentsActiveChanged={emptyFunction}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index b1f7d8023..681f7c5b2 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -898,7 +898,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     contentFunc = () => [this.youtubeVideoId ? this.youtubeContent : this.content];
 
-    scaling = () => this.props.scaling?.() || 1;
+    scaling = () => this.props.NativeDimScaling?.() || 1;
 
     panelWidth = () => (this.props.PanelWidth() * this.heightPercent) / 100;
     panelHeight = () => (this.layoutDoc._fitWidth ? this.panelWidth() / (Doc.NativeAspect(this.rootDoc) || 1) : (this.props.PanelHeight() * this.heightPercent) / 100);
@@ -911,7 +911,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             .scale(100 / this.heightPercent);
     };
 
-    marqueeFitScaling = () => ((this.props.scaling?.() || 1) * this.heightPercent) / 100;
+    marqueeFitScaling = () => ((this.props.NativeDimScaling?.() || 1) * this.heightPercent) / 100;
     marqueeOffset = () => [((this.panelWidth() / 2) * (1 - this.heightPercent / 100)) / (this.heightPercent / 100), 0];
 
     timelineDocFilter = () => [`_timelineLabel:true,${Utils.noRecursionHack}:x`];
@@ -1124,7 +1124,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                             ScreenToLocalTransform={this.screenToLocalTransform}
                             docFilters={this.timelineDocFilter}
                             select={emptyFunction}
-                            scaling={returnOne}
+                            NativeDimScaling={returnOne}
                             whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                             removeDocument={this.removeDocument}
                             moveDocument={this.moveDocument}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 05da8bd7b..71d6959a3 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -200,7 +200,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             autoHeight => {
                 if (autoHeight) {
                     this.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']);
-                    this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']) * (this.props.scaling?.() || 1));
+                    this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']) * (this.props.NativeDimScaling?.() || 1));
                 }
             }
         );
@@ -276,7 +276,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         }
         if (this._sidebarRef?.current?.makeDocUnfiltered(doc)) return 1;
         if (doc !== this.rootDoc && this._outerRef.current) {
-            const windowHeight = this.props.PanelHeight() / (this.props.scaling?.() || 1);
+            const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
             const scrollTo = Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.layoutDoc._scrollTop), windowHeight, windowHeight * 0.1, Math.max(NumCast(doc.y) + doc[HeightSym](), this.getScrollHeight()));
             if (scrollTo !== undefined && this._initialScroll === undefined) {
                 const focusSpeed = smooth ? 500 : 0;
@@ -310,7 +310,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this.props.docViewPath().lastElement()?.docView?.cleanupPointerEvents(); // pointerup events aren't generated on containing document view, so we have to invoke it here.
         if (this._iframe?.contentWindow && this._iframe.contentDocument && !this._iframe.contentWindow.getSelection()?.isCollapsed) {
             const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!);
-            const scale = (this.props.scaling?.() || 1) * mainContBounds.scale;
+            const scale = (this.props.NativeDimScaling?.() || 1) * mainContBounds.scale;
             const sel = this._iframe.contentWindow.getSelection();
             if (sel) {
                 this._textAnnotationCreator = () => this.createTextAnnotation(sel, !sel.isCollapsed ? sel.getRangeAt(0) : undefined);
@@ -322,7 +322,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     iframeDown = (e: PointerEvent) => {
         const sel = this._iframe?.contentWindow?.getSelection?.();
         const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!);
-        const scale = (this.props.scaling?.() || 1) * mainContBounds.scale;
+        const scale = (this.props.NativeDimScaling?.() || 1) * mainContBounds.scale;
         const word = getWordAtPoint(e.target, e.clientX, e.clientY);
         this._setPreviewCursor?.(e.clientX, e.clientY, false, true);
         MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
@@ -604,7 +604,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             funcs.push({
                 description: (!this.layoutDoc.forceReflow ? 'Force' : 'Prevent') + ' Reflow',
                 event: () => {
-                    const nw = !this.layoutDoc.forceReflow ? undefined : Doc.NativeWidth(this.layoutDoc) - this.sidebarWidth() / (this.props.scaling?.() || 1);
+                    const nw = !this.layoutDoc.forceReflow ? undefined : Doc.NativeWidth(this.layoutDoc) - this.sidebarWidth() / (this.props.NativeDimScaling?.() || 1);
                     this.layoutDoc.forceReflow = !nw;
                     if (nw) {
                         Doc.SetInPlace(this.layoutDoc, this.fieldKey + '-nativeWidth', nw, true);
@@ -717,12 +717,12 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 this._draggingSidebar = true;
                 const localDelta = this.props
                     .ScreenToLocalTransform()
-                    .scale(this.props.scaling?.() || 1)
+                    .scale(this.props.NativeDimScaling?.() || 1)
                     .transformDirection(delta[0], delta[1]);
                 const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']);
                 const nativeHeight = NumCast(this.layoutDoc[this.fieldKey + '-nativeHeight']);
                 const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth);
-                const ratio = (curNativeWidth + ((onButton ? 1 : -1) * localDelta[0]) / (this.props.scaling?.() || 1)) / nativeWidth;
+                const ratio = (curNativeWidth + ((onButton ? 1 : -1) * localDelta[0]) / (this.props.NativeDimScaling?.() || 1)) / nativeWidth;
                 if (ratio >= 1) {
                     this.layoutDoc.nativeWidth = nativeWidth * ratio;
                     this.layoutDoc.nativeHeight = nativeHeight * (1 + ratio);
@@ -834,8 +834,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     searchStringChanged = (e: React.ChangeEvent<HTMLInputElement>) => (this._searchString = e.currentTarget.value);
     showInfo = action((anno: Opt<Doc>) => (this._overlayAnnoInfo = anno));
     setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => (this._setPreviewCursor = func);
-    panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1) - this.sidebarWidth() + WebBox.sidebarResizerWidth; // (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);
+    panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth() + WebBox.sidebarResizerWidth; // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0);
+    panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 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;
     basicFilter = () => [...this.props.docFilters(), Utils.PropUnsetFilter('textInlineAnnotations')];
@@ -852,7 +852,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     render() {
         const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this.props.pointerEvents?.() as any);
         const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
-        const scale = previewScale * (this.props.scaling?.() || 1);
+        const scale = previewScale * (this.props.NativeDimScaling?.() || 1);
         const renderAnnotations = (docFilters?: () => string[]) => (
             <CollectionFreeFormView
                 {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
@@ -864,12 +864,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 PanelWidth={this.panelWidth}
                 PanelHeight={this.panelHeight}
                 ScreenToLocalTransform={this.scrollXf}
-                scaling={returnOne}
+                NativeDimScaling={returnOne}
                 dropAction={'alias'}
                 docFilters={docFilters || this.basicFilter}
                 dontRenderDocuments={docFilters ? false : true}
                 select={emptyFunction}
-                ContentScaling={returnOne}
                 bringToFront={emptyFunction}
                 whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                 removeDocument={this.removeDocument}
@@ -950,7 +949,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     layoutDoc={this.layoutDoc}
                     dataDoc={this.dataDoc}
                     setHeight={emptyFunction}
-                    nativeWidth={this._previewNativeWidth ?? NumCast(this.layoutDoc._nativeWidth) - WebBox.sidebarResizerWidth / (this.props.scaling?.() || 1)}
+                    nativeWidth={this._previewNativeWidth ?? NumCast(this.layoutDoc._nativeWidth) - WebBox.sidebarResizerWidth / (this.props.NativeDimScaling?.() || 1)}
                     showSidebar={this.SidebarShown}
                     sidebarAddDocument={this.sidebarAddDocument}
                     moveDocument={this.moveDocument}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 383c22ba8..e9b048c5e 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -968,7 +968,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     };
 
     @computed get contentScaling() {
-        return Doc.NativeAspect(this.rootDoc, this.dataDoc, false) ? this.props.scaling?.() || 1 : 1;
+        return Doc.NativeAspect(this.rootDoc, this.dataDoc, false) ? this.props.NativeDimScaling?.() || 1 : 1;
     }
     componentDidMount() {
         !this.props.dontSelectOnLoad && this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document.  this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
@@ -1691,7 +1691,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         }
     };
     fitContentsToBox = () => this.props.Document._fitContentsToBox;
-    sidebarContentScaling = () => (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
+    sidebarContentScaling = () => (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
     sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
         if (!this.layoutDoc._showSidebar) this.toggleSidebar();
         // console.log("printting allSideBarDocs");
@@ -1705,7 +1705,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     sidebarScreenToLocal = () =>
         this.props
             .ScreenToLocalTransform()
-            .translate(-(this.props.PanelWidth() - this.sidebarWidth()) / (this.props.scaling?.() || 1), 0)
+            .translate(-(this.props.PanelWidth() - this.sidebarWidth()) / (this.props.NativeDimScaling?.() || 1), 0)
             .scale(1 / NumCast(this.layoutDoc._viewScale, 1));
 
     @computed get audioHandle() {
@@ -1768,7 +1768,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     scaleField={this.SidebarKey + '-scale'}
                     isAnnotationOverlay={false}
                     select={emptyFunction}
-                    scaling={this.sidebarContentScaling}
+                    NativeDimScaling={this.sidebarContentScaling}
                     whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                     removeDocument={this.sidebarRemDocument}
                     moveDocument={this.sidebarMoveDocument}
@@ -1793,7 +1793,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         TraceMobx();
         const active = this.props.isContentActive() || this.props.isSelected();
         const selected = active;
-        const scale = (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
+        const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
         const rounded = StrCast(this.layoutDoc.borderRounding) === '100%' ? '-rounded' : '';
         const interactive = (Doc.ActiveTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || !this.layoutDoc._lockedPosition);
         if (!selected && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide);
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index bd5e8caab..0cf15d297 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -199,11 +199,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
         }
     };
 
-    headerUp = (e: React.PointerEvent<HTMLDivElement>) => {
-        e.stopPropagation();
-        e.preventDefault();
-    };
-
     /**
      * Function to drag and drop the pres element to a diferent location
      */
@@ -477,8 +472,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 })}
                 onPointerOver={this.onPointerOver}
                 onPointerLeave={this.onPointerLeave}
-                onPointerDown={this.headerDown}
-                onPointerUp={this.headerUp}>
+                onPointerDown={this.headerDown}>
                 {/* {miniView ?
                               // when width is LESS than 110 px 
                               <div className={`presItem-miniSlide ${isSelected ? "active" : ""}`} ref={miniView ? this._dragRef : null}>
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 837734edf..2c83082b7 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -41,7 +41,6 @@ interface IViewerProps extends FieldViewProps {
     url: string;
     loaded?: (nw: number, nh: number, np: number) => void;
     setPdfViewer: (view: PDFViewer) => void;
-    ContentScaling?: () => number;
     anchorMenuClick?: () => undefined | ((anchor: Doc) => void);
     crop: (region: Doc | undefined, addCrop?: boolean) => Doc | undefined;
 }
@@ -97,7 +96,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
             autoHeight => {
                 if (autoHeight) {
                     this.props.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']);
-                    this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']) * (this.props.scaling?.() || 1));
+                    this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']) * (this.props.NativeDimScaling?.() || 1));
                 }
             }
         );
@@ -162,7 +161,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         const mainCont = this._mainCont.current;
         let focusSpeed: Opt<number>;
         if (doc !== this.props.rootDoc && mainCont) {
-            const windowHeight = this.props.PanelHeight() / (this.props.scaling?.() || 1);
+            const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
             const scrollTo = doc.unrendered ? NumCast(doc.y) : Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, 0.1 * windowHeight, NumCast(this.props.Document.scrollHeight));
             if (scrollTo !== undefined && scrollTo !== this.props.layoutDoc._scrollTop) {
                 focusSpeed = 500;
@@ -486,8 +485,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
 
     showInfo = action((anno: Opt<Doc>) => (this._overlayAnnoInfo = anno));
     overlayTransform = () => this.scrollXf().scale(1 / NumCast(this.props.layoutDoc._viewScale, 1));
-    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);
+    panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0);
+    panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document);
     basicFilter = () => [...this.props.docFilters(), Utils.PropUnsetFilter('textInlineAnnotations')];
     transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
     opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
@@ -509,7 +508,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
             PanelWidth={this.panelWidth}
             dropAction={'alias'}
             select={emptyFunction}
-            ContentScaling={this.contentZoom}
             bringToFront={emptyFunction}
             docFilters={docFilters || this.basicFilter}
             styleProvider={this.childStyleProvider}
@@ -556,10 +554,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
     @computed get pdfViewerDiv() {
         return <div className={'pdfViewerDash-text' + (this.props.pointerEvents?.() !== 'none' && this._textSelecting && this.props.isContentActive() ? '-selected' : '')} ref={this._viewer} />;
     }
-    @computed get contentScaling() {
-        return this.props.ContentScaling?.() || 1;
-    }
-    contentZoom = () => NumCast(this.props.layoutDoc._viewScale, 1);
     savedAnnotations = () => this._savedAnnotations;
     render() {
         TraceMobx();
@@ -574,8 +568,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                     onClick={this.onClick}
                     style={{
                         overflowX: NumCast(this.props.layoutDoc._viewScale, 1) !== 1 ? 'scroll' : undefined,
-                        height: !this.props.Document._fitWidth && window.screen.width > 600 ? Doc.NativeHeight(this.props.Document) : `${100 / this.contentScaling}%`,
-                        transform: `scale(${this.contentScaling})`,
+                        height: !this.props.Document._fitWidth && window.screen.width > 600 ? Doc.NativeHeight(this.props.Document) : `100%`,
                     }}>
                     {this.pdfViewerDiv}
                     {this.annotationLayer}
-- 
cgit v1.2.3-70-g09d2

