From 95c076b64a816c6bd503089f90234f8ce078eae8 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 29 Mar 2023 11:51:51 -0400
Subject: fixed sizing of link count button.  moved border paths and audio to
 style provider

---
 src/client/views/nodes/DocumentView.tsx | 282 ++++++++++----------------------
 1 file changed, 84 insertions(+), 198 deletions(-)

(limited to 'src/client/views/nodes/DocumentView.tsx')

diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f2add9856..091a6b050 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,10 +1,9 @@
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Tooltip } from '@material-ui/core';
 import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
+import { computedFn } from 'mobx-utils';
 import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
-import { AclAdmin, AclEdit, AclPrivate, AnimationSym, DataSym, Doc, DocListCast, Field, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
+import { AclPrivate, AnimationSym, DataSym, Doc, DocListCast, Field, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { List } from '../../../fields/List';
@@ -12,8 +11,7 @@ import { listSpec } from '../../../fields/Schema';
 import { ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { AudioField } from '../../../fields/URLField';
-import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util';
-import { MobileInterface } from '../../../mobile/MobileInterface';
+import { GetEffectiveAcl, TraceMobx } from '../../../fields/util';
 import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, OmitKeys, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils';
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { DocServer } from '../../DocServer';
@@ -28,7 +26,6 @@ import { LinkFollower } from '../../util/LinkFollower';
 import { LinkManager } from '../../util/LinkManager';
 import { ScriptingGlobals } from '../../util/ScriptingGlobals';
 import { SelectionManager } from '../../util/SelectionManager';
-import { SettingsManager } from '../../util/SettingsManager';
 import { SharingManager } from '../../util/SharingManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
@@ -48,7 +45,6 @@ import './DocumentView.scss';
 import { FieldViewProps } from './FieldView';
 import { FormattedTextBox } from './formattedText/FormattedTextBox';
 import { LinkAnchorBox } from './LinkAnchorBox';
-import { RadialMenu } from './RadialMenu';
 import { PresEffect, PresEffectDirection } from './trails';
 import { PinProps, PresBox } from './trails/PresBox';
 import React = require('react');
@@ -155,7 +151,6 @@ export interface DocumentViewSharedProps {
     ContainingCollectionDoc: Opt<Doc>;
     suppressSetHeight?: boolean;
     thumbShown?: () => boolean;
-    isHovering?: () => boolean;
     setContentView?: (view: DocComponentView) => any;
     CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView;
     PanelWidth: () => number;
@@ -240,7 +235,6 @@ export interface DocumentViewInternalProps extends DocumentViewProps {
     NativeWidth: () => number;
     NativeHeight: () => number;
     isSelected: (outsideReaction?: boolean) => boolean;
-    isHovering: () => boolean;
     select: (ctrlPressed: boolean, shiftPress?: boolean) => void;
     DocumentView: () => DocumentView;
     viewPath: () => DocumentView[];
@@ -289,9 +283,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @computed get thumb() {
         return ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url?.href.replace('.png', '_m.png');
     }
-    @computed get hidden() {
-        return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Hidden);
-    }
     @computed get opacity() {
         return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Opacity);
     }
@@ -379,30 +370,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         Object.values(this._disposers).forEach(disposer => disposer?.());
     }
 
-    @action
-    onRadialMenu = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): void => {
-        const pt = me.touchEvent.touches[me.touchEvent.touches.length - 1];
-        RadialMenu.Instance.openMenu(pt.pageX - 15, pt.pageY - 15);
-
-        // RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), OpenWhere.addRight), icon: "map-pin", selected: -1 });
-        const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
-        (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) &&
-            RadialMenu.Instance.addItem({
-                description: 'Delete',
-                event: () => {
-                    this.props.ContainingCollectionView?.removeDocument(this.props.Document);
-                    RadialMenu.Instance.closeMenu();
-                },
-                icon: 'external-link-square-alt',
-                selected: -1,
-            });
-        // RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, OpenWhere.addRight), icon: "trash", selected: -1 });
-        RadialMenu.Instance.addItem({ description: 'Pin', event: () => this.props.pinToPres(this.props.Document, {}), icon: 'map-pin', selected: -1 });
-        RadialMenu.Instance.addItem({ description: 'Open', event: () => MobileInterface.Instance.handleClick(this.props.Document), icon: 'trash', selected: -1 });
-
-        SelectionManager.DeselectAll();
-    };
-
     startDragging(x: number, y: number, dropAction: dropActionType, hideSource = false) {
         if (this._mainCont.current) {
             const views = SelectionManager.Views().filter(dv => dv.docView?._mainCont.current);
@@ -435,7 +402,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     defaultRestoreTargetView = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: DocFocusOptions) => {
         const targetMatch =
             Doc.AreProtosEqual(anchor, this.rootDoc) || // anchor is this document, so anchor's properties apply to this document
-            (DocCast(anchor)?.unrendered && Doc.AreProtosEqual(DocCast(anchor.annotationOn), this.rootDoc)) // the anchor is an unrendered annotation on this document, so anchor properties applie to this document
+            (DocCast(anchor)?.unrendered && Doc.AreProtosEqual(DocCast(anchor.annotationOn), this.rootDoc)) // the anchor is an unrendered annotation on this document, so anchor properties apply to this document
                 ? true
                 : false;
         return targetMatch && PresBox.restoreTargetDocView(docView, anchor, focusSpeed) ? focusSpeed : undefined;
@@ -573,11 +540,9 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         }
     };
 
-    cancelMoveEvents = () => document.removeEventListener('pointermove', this.onPointerMove);
-
     cleanupPointerEvents = () => {
         this.cleanUpInteractions();
-        this.cancelMoveEvents();
+        document.removeEventListener('pointermove', this.onPointerMove);
         document.removeEventListener('pointerup', this.onPointerUp);
     };
 
@@ -586,7 +551,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         this.cleanupPointerEvents();
         this._longPressSelector && clearTimeout(this._longPressSelector);
 
-        if (this.onPointerUpHandler?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
+        if (this.onPointerUpHandler?.script) {
             this.onPointerUpHandler.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log);
         } else if (e.button === 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
             this._doubleTap = Date.now() - this._lastTap < Utils.CLICK_TIME;
@@ -676,7 +641,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @undoBatch
     @action
     makeIntoPortal = () => {
-        const portalLink = this.allLinks.find(d => d.anchor1 === this.props.Document);
+        const portalLink = this.allLinks.find(d => d.anchor1 === this.props.Document && d.linkRelationship === 'portal to:portal from');
         if (!portalLink) {
             DocUtils.MakeLink(
                 { doc: this.props.Document },
@@ -928,25 +893,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             ? true
             : false;
     };
-    get audioAnnoState() {
-        return this.dataDoc.audioAnnoState ?? 'stopped';
-    }
-    @computed get audioAnnoView() {
-        const audioAnnosCount = Cast(this.dataDoc[this.LayoutFieldKey + '-audioAnnotations'], listSpec(AudioField), null)?.length;
-        const audioTextAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '-audioAnnotations-text'], listSpec('string'), null);
-        const audioIconColors = new Map<string, string>([
-            ['recording', 'red'],
-            ['playing', 'green'],
-            ['stopped', audioAnnosCount ? 'blue' : 'gray'],
-        ]);
-        return this.props.renderDepth === -1 || SnappingManager.GetIsDragging() || (!this.props.isSelected() && !this.props.isHovering() && this.audioAnnoState !== 'recording') || (!audioAnnosCount && this.audioAnnoState === 'stopped') ? null : (
-            <Tooltip title={<div>{audioTextAnnos?.lastElement()}</div>}>
-                <div className="documentView-audioBackground" onPointerDown={this.playAnnotation}>
-                    <FontAwesomeIcon className="documentView-audioFont" style={{ color: audioIconColors.get(StrCast(this.audioAnnoState)) }} icon={!audioAnnosCount ? 'microphone' : 'file-audio'} size="sm" />
-                </div>
-            </Tooltip>
-        );
-    }
     contentPointerEvents = () => (!this.disableClickScriptFunc && this.onClickHandler ? 'none' : this.pointerEvents);
     @computed get contents() {
         TraceMobx();
@@ -965,10 +911,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                         height={this.props.PanelHeight()}
                         onError={(e: any) => {
                             setTimeout(action(() => (this._retryThumb = 0)));
-                            setTimeout(
-                                action(() => (this._retryThumb = 1)),
-                                150
-                            );
+                            // prettier-ignore
+                            setTimeout(action(() => (this._retryThumb = 1)), 150 );
                         }}
                     />
                 )}
@@ -978,7 +922,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     pointerEvents={this.contentPointerEvents}
                     docViewPath={this.props.viewPath}
                     thumbShown={this.thumbShown}
-                    isHovering={this.props.isHovering}
                     setContentView={this.setContentView}
                     NativeDimScaling={this.props.NativeDimScaling}
                     PanelHeight={this.panelHeight}
@@ -992,19 +935,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     layoutKey={this.finalLayoutKey}
                 />
                 {this.layoutDoc.hideAllLinks ? null : this.allLinkEndpoints}
-                {this.audioAnnoView}
             </div>
         );
     }
 
-    get indicatorIcon() {
-        if (this.props.Document['acl-Public'] !== SharingPermissions.None) return 'globe-americas';
-        else if (this.props.Document.numGroupsShared || NumCast(this.props.Document.numUsersShared, 0) > 1) return 'users';
-        else return 'user';
-    }
-
-    @undoBatch
-    hideLinkAnchor = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && (doc.hidden = true), true);
     anchorPanelWidth = () => this.props.PanelWidth() || 1;
     anchorPanelHeight = () => this.props.PanelHeight() || 1;
     anchorStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => {
@@ -1036,12 +970,13 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         TraceMobx();
         return LinkManager.Instance.getAllRelatedLinks(this.rootDoc);
     }
+    hideLink = computedFn((link: Doc) => () => (link.linkDisplay = false));
     @computed get allLinkEndpoints() {
         // the small blue dots that mark the endpoints of links
         TraceMobx();
         if (this.props.hideLinkAnchors || this.layoutDoc.hideLinkAnchors || this.props.dontRegisterView || this.layoutDoc.unrendered) return null;
         const filtered = DocUtils.FilterDocs(this.directLinks, this.props.docFilters?.() ?? [], []).filter(d => d.linkDisplay);
-        return filtered.map((link, i) => (
+        return filtered.map(link => (
             <div className="documentView-anchorCont" key={link[Id]}>
                 <DocumentView
                     {...this.props}
@@ -1055,8 +990,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     hideCaptions={true}
                     hideLinkAnchors={true}
                     fitWidth={returnTrue}
+                    removeDocument={this.hideLink(link)}
                     styleProvider={this.anchorStyleProvider}
-                    removeDocument={this.hideLinkAnchor}
                     LayoutTemplate={undefined}
                     LayoutTemplateString={LinkAnchorBox.LayoutString(`anchor${Doc.LinkEndpoint(link, this.rootDoc)}`)}
                 />
@@ -1064,26 +999,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         ));
     }
 
-    @action
-    playAnnotation = () => {
-        const self = this;
-        const audioAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '-audioAnnotations'], listSpec(AudioField), null);
-        const anno = audioAnnos?.lastElement();
-        if (anno instanceof AudioField && this.audioAnnoState === 'stopped') {
-            new Howl({
-                src: [anno.url.href],
-                format: ['mp3'],
-                autoplay: true,
-                loop: false,
-                volume: 0.5,
-                onend: function () {
-                    runInAction(() => (self.dataDoc.audioAnnoState = 'stopped'));
-                },
-            });
-            this.dataDoc.audioAnnoState = 'playing';
-        }
-    };
-
     static recordAudioAnnotation(dataDoc: Doc, field: string, onRecording?: (stop: () => void) => void, onEnd?: () => void) {
         let gumStream: any;
         let recorder: any;
@@ -1131,6 +1046,23 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 else setTimeout(stopFunc, 5000);
             });
     }
+    playAnnotation = () => {
+        const self = this;
+        const audioAnnoState = this.dataDoc.audioAnnoState ?? 'stopped';
+        const audioAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '-audioAnnotations'], listSpec(AudioField), null);
+        const anno = audioAnnos?.lastElement();
+        if (anno instanceof AudioField && audioAnnoState === 'stopped') {
+            new Howl({
+                src: [anno.url.href],
+                format: ['mp3'],
+                autoplay: true,
+                loop: false,
+                volume: 0.5,
+                onend: action(() => (self.dataDoc.audioAnnoState = 'stopped')),
+            });
+            this.dataDoc.audioAnnoState = 'playing';
+        }
+    };
 
     captionStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps>, property: string) => this.props?.styleProvider?.(doc, props, property + ':caption');
     @computed get innards() {
@@ -1225,7 +1157,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 
     renderDoc = (style: object) => {
         TraceMobx();
-        return !DocCast(this.Document) || GetEffectiveAcl(this.Document[DataSym]) === AclPrivate || this.hidden
+        return !DocCast(this.Document) || GetEffectiveAcl(this.Document[DataSym]) === AclPrivate
             ? null
             : this.docContents ?? (
                   <div
@@ -1280,7 +1212,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     render() {
         TraceMobx();
         const highlighting = this.props.styleProvider?.(this.props.Document, this.props, StyleProp.Highlighting);
-        const borderPath = this.props.styleProvider?.(this.props.Document, this.props, StyleProp.BorderPath) || { path: undefined };
+        const borderPath = this.props.styleProvider?.(this.props.Document, this.props, StyleProp.BorderPath);
         const boxShadow =
             this.props.treeViewDoc || !highlighting
                 ? this.boxShadow
@@ -1292,11 +1224,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             outline: highlighting && !this.borderRounding && !highlighting.highlightStroke ? `${highlighting.highlightColor} ${highlighting.highlightStyle} ${highlighting.highlightIndex}px` : 'solid 0px',
             border: highlighting && this.borderRounding && highlighting.highlightStyle === 'dashed' ? `${highlighting.highlightStyle} ${highlighting.highlightColor} ${highlighting.highlightIndex}px` : undefined,
             boxShadow,
-            clipPath: borderPath.path ? `path('${borderPath.path}')` : undefined,
+            clipPath: borderPath?.clipPath,
         });
 
-        const animRenderDoc = DocumentViewInternal.AnimationEffect(renderDoc, this.rootDoc[AnimationSym], this.rootDoc);
-        return this.hidden ? null : (
+        return (
             <div
                 className={`${DocumentView.ROOT_DIV} docView-hack`}
                 ref={this._mainCont}
@@ -1307,22 +1238,13 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 onPointerOver={e => (!SnappingManager.GetIsDragging() || DragManager.CanEmbed) && Doc.BrushDoc(this.props.Document)}
                 onPointerLeave={e => !isParentOf(this.ContentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.props.Document)}
                 style={{
-                    display: this.hidden ? 'inline' : undefined,
                     borderRadius: this.borderRounding,
                     pointerEvents: this.pointerEvents === 'visiblePainted' ? 'none' : this.pointerEvents,
                 }}>
-                {!borderPath.path ? (
-                    animRenderDoc
-                ) : (
-                    <>
-                        {animRenderDoc}
-                        <div key="border2" className="documentView-customBorder" style={{ pointerEvents: 'none' }}>
-                            <svg style={{ overflow: 'visible', height: '100%' }} viewBox={`0 0 ${this.props.PanelWidth()} ${this.props.PanelHeight()}`}>
-                                <path d={borderPath.path} style={{ stroke: 'black', fill: 'transparent', strokeWidth: borderPath.width }} />
-                            </svg>
-                        </div>
-                    </>
-                )}
+                <>
+                    {DocumentViewInternal.AnimationEffect(renderDoc, this.rootDoc[AnimationSym], this.rootDoc)}
+                    {borderPath?.jsx}
+                </>
             </div>
         );
     }
@@ -1332,6 +1254,11 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 export class DocumentView extends React.Component<DocumentViewProps> {
     public static ROOT_DIV = 'documentView-effectsWrapper';
     @observable public static LongPress = false;
+    @observable public docView: DocumentViewInternal | undefined | null;
+    @observable public textHtmlOverlay: Opt<string>;
+    @observable private _isHovering = false;
+
+    public htmlOverlayEffect = '';
     public get displayName() {
         return 'DocumentView(' + this.props.Document?.title + ')';
     } // this makes mobx trace() statements more descriptive
@@ -1343,6 +1270,10 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         this.ViewTimer && clearTimeout(this.ViewTimer);
         this.rootDoc._viewTransition = undefined;
     };
+    public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this.docView?.startDragging(x, y, dropAction, hideSource);
+
+    public showContextMenu = (pageX: number, pageY: number) => this.docView?.onContextMenu(undefined, pageX, pageY);
+
     public setAnimEffect = (presEffect: Doc, timeInMs: number, afterTrans?: () => void) => {
         this.AnimEffectTimer && clearTimeout(this.AnimEffectTimer);
         this.rootDoc[AnimationSym] = presEffect;
@@ -1374,34 +1305,18 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         );
     }
 
+    // shows a stacking view collection (by default, but the user can change) of all documents linked to the source
     public static showBackLinks(linkSource: Doc) {
         const docId = Doc.CurrentUserEmail + Doc.GetProto(linkSource)[Id] + '-pivotish';
-        DocServer.GetRefField(docId).then(docx => {
-            const rootAlias = () => {
-                const rootAlias = Doc.MakeAlias(linkSource);
-                rootAlias.x = rootAlias.y = 0;
-                return rootAlias;
-            };
-            const linkCollection =
-                (docx instanceof Doc && docx) ||
-                Docs.Create.StackingDocument(
-                    [
-                        /*rootAlias()*/
-                    ],
-                    { title: linkSource.title + '-pivot', _width: 500, _height: 500 },
-                    docId
-                );
-            linkCollection.linkSource = linkSource;
-            if (!linkCollection.reactionScript) linkCollection.reactionScript = ScriptField.MakeScript('updateLinkCollection(self)');
-            LightboxView.SetLightboxDoc(linkCollection);
-        });
+        // prettier-ignore
+        DocServer.GetRefField(docId).then(docx => docx instanceof Doc &&
+            LightboxView.SetLightboxDoc(
+                docx || // reuse existing pivot view of documents, or else create a new collection
+                Docs.Create.StackingDocument([], { title: linkSource.title + '-pivot', _width: 500, _height: 500, linkSource, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(self)') }, docId)
+            )
+        );
     }
 
-    @observable public docView: DocumentViewInternal | undefined | null;
-
-    showContextMenu(pageX: number, pageY: number) {
-        return this.docView?.onContextMenu(undefined, pageX, pageY);
-    }
     get Document() {
         return this.props.Document;
     }
@@ -1409,13 +1324,10 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         return this.props.renderDepth === 0;
     }
     get rootDoc() {
-        return this.docView?.rootDoc || this.Document;
+        return this.docView?.rootDoc ?? this.Document;
     }
     get dataDoc() {
-        return this.docView?.dataDoc || this.Document;
-    }
-    get finalLayoutKey() {
-        return this.docView?.finalLayoutKey || 'layout';
+        return this.docView?.dataDoc ?? this.Document;
     }
     get ContentDiv() {
         return this.docView?.ContentDiv;
@@ -1429,23 +1341,22 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     get LayoutFieldKey() {
         return this.docView?.LayoutFieldKey || 'layout';
     }
-    get fitWidth() {
+    @computed get fitWidth() {
         return this.docView?._componentView?.fitWidth?.() ?? this.props.fitWidth?.(this.rootDoc) ?? this.layoutDoc?.fitWidth;
     }
-
+    @computed get anchorViewDoc() {
+        return this.props.LayoutTemplateString?.includes('anchor2') ? DocCast(this.rootDoc['anchor2']) : this.props.LayoutTemplateString?.includes('anchor1') ? DocCast(this.rootDoc['anchor1']) : undefined;
+    }
     @computed get hideLinkButton() {
         return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HideLinkButton + (this.isSelected() ? ':selected' : ''));
     }
-    linkButtonInverseScaling = () => (this.props.NativeDimScaling?.() || 1) * this.screenToLocalTransform().Scale;
-
     @computed get linkCountView() {
         const hideCount = this.props.renderDepth === -1 || SnappingManager.GetIsDragging() || (this.isSelected() && this.props.renderDepth) || !this._isHovering || this.hideLinkButton;
-        return hideCount ? null : <DocumentLinksButton View={this} scaling={this.linkButtonInverseScaling} OnHover={true} Bottom={this.topMost} ShowCount={true} />;
+        return hideCount ? null : <DocumentLinksButton View={this} scaling={this.scaleToScreenSpace} OnHover={true} Bottom={this.topMost} ShowCount={true} />;
     }
     @computed get hidden() {
         return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Hidden);
     }
-
     @computed get docViewPath(): DocumentView[] {
         return this.props.docViewPath ? [...this.props.docViewPath(), this] : [this];
     }
@@ -1475,7 +1386,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         }
         return Math.max(minTextScale, this.props.PanelHeight() / (this.effectiveNativeHeight || 1)); // height-limited or unscaled
     }
-
     @computed get panelWidth() {
         return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this.props.PanelWidth();
     }
@@ -1500,12 +1410,12 @@ 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.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight());
-    getBounds = () => {
-        if (!this.docView || !this.docView.ContentDiv || this.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) {
+    public toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight());
+    public getBounds = () => {
+        if (!this.docView?.ContentDiv || this.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) {
             return undefined;
         }
-        const xf = this.docView?.props
+        const xf = this.docView.props
             .ScreenToLocalTransform()
             .scale(this.trueNativeWidth() ? this.nativeScaling : 1)
             .inverse();
@@ -1542,7 +1452,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         Doc.setNativeView(this.props.Document);
         custom && DocUtils.makeCustomViewClicked(this.props.Document, Docs.Create.StackingDocument, layout, undefined);
     };
-    switchViews = action((custom: boolean, view: string, finished?: () => void, useExistingLayout = false) => {
+    @action
+    switchViews = (custom: boolean, view: string, finished?: () => void, useExistingLayout = false) => {
         this.docView && (this.docView._animateScalingTo = 0.1); // shrink doc
         setTimeout(
             action(() => {
@@ -1562,14 +1473,9 @@ export class DocumentView extends React.Component<DocumentViewProps> {
             }),
             this.docView ? Math.max(0, this.docView?.animateScaleTime - 10) : 0
         );
-    });
-
-    startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this.docView?.startDragging(x, y, dropAction, hideSource);
+    };
 
-    @observable textHtmlOverlay: Opt<string>;
-    @computed get anchorViewDoc() {
-        return this.props.LayoutTemplateString?.includes('anchor2') ? DocCast(this.rootDoc['anchor2']) : this.props.LayoutTemplateString?.includes('anchor1') ? DocCast(this.rootDoc['anchor1']) : undefined;
-    }
+    scaleToScreenSpace = () => (1 / (this.props.NativeDimScaling?.() || 1)) * this.screenToLocalTransform().Scale;
     docViewPathFunc = () => this.docViewPath;
     isSelected = (outsideReaction?: boolean) => SelectionManager.IsSelected(this, outsideReaction);
     select = (extendSelection: boolean) => SelectionManager.SelectView(this, !SelectionManager.Views().some(v => v.props.Document === this.props.ContainingCollectionDoc) && extendSelection);
@@ -1586,11 +1492,12 @@ export class DocumentView extends React.Component<DocumentViewProps> {
             .translate(-this.centeringX, -this.centeringY)
             .scale(this.trueNativeWidth() ? 1 / this.nativeScaling : 1);
     componentDidMount() {
-        this._disposers.reactionScript = reaction(
-            () => ScriptCast(this.rootDoc.reactionScript)?.script?.run({ this: this.props.Document, self: Cast(this.rootDoc, Doc, null) || this.props.Document }).result,
+        this._disposers.updateContentsScript = reaction(
+            () => ScriptCast(this.rootDoc.updateContentsScript)?.script?.run({ this: this.props.Document, self: Cast(this.rootDoc, Doc, null) || this.props.Document }).result,
             output => output
         );
         this._disposers.height = reaction(
+            // increase max auto height if document has been resized to be greater than current max
             () => NumCast(this.layoutDoc._height),
             action(height => {
                 const docMax = NumCast(this.layoutDoc.docMaxAutoHeight);
@@ -1603,24 +1510,20 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         Object.values(this._disposers).forEach(disposer => disposer?.());
         !BoolCast(this.props.Document.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.RemoveView(this);
     }
-    _hoverTimeout: any = undefined;
-    isHovering = () => this._isHovering;
-    @observable _isHovering = false;
-
-    htmlOverlayEffect = '';
     @computed get htmlOverlay() {
-        const effectProps = {
-            delay: 0,
-            duration: 500,
-        };
-        const highlight = (
-            <div className="webBox-textHighlight">
-                <ObserverJsxParser autoCloseVoidElements={true} key={42} onError={(e: any) => console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this.textHtmlOverlay)} />
-            </div>
-        );
         return !this.textHtmlOverlay ? null : (
             <div className="documentView-htmlOverlay">
-                <div className="documentView-htmlOverlayInner">{<Fade {...effectProps}>{DocumentViewInternal.AnimationEffect(highlight, { presEffect: this.htmlOverlayEffect ?? 'Zoom' } as any as Doc, this.rootDoc)} </Fade>}</div>
+                <div className="documentView-htmlOverlayInner">
+                    <Fade delay={0} duration={500}>
+                        {DocumentViewInternal.AnimationEffect(
+                            <div className="webBox-textHighlight">
+                                <ObserverJsxParser autoCloseVoidElements={true} key={42} onError={(e: any) => console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this.textHtmlOverlay)} />
+                            </div>,
+                            { presEffect: this.htmlOverlayEffect ?? 'Zoom' } as any as Doc,
+                            this.rootDoc
+                        )}{' '}
+                    </Fade>
+                </div>
             </div>
         );
     }
@@ -1631,19 +1534,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         const yshift = Math.abs(this.Yshift) <= 0.001 ? this.props.PanelHeight() : undefined;
 
         return this.hidden ? null : (
-            <div
-                className="contentFittingDocumentView"
-                onPointerEnter={action(() => {
-                    clearTimeout(this._hoverTimeout);
-                    this._isHovering = true;
-                })}
-                onPointerLeave={action(() => {
-                    clearTimeout(this._hoverTimeout);
-                    this._hoverTimeout = setTimeout(
-                        action(() => (this._isHovering = false)),
-                        500
-                    );
-                })}>
+            <div className="contentFittingDocumentView" onPointerEnter={action(() => (this._isHovering = true))} onPointerLeave={action(() => (this._isHovering = false))}>
                 {!this.props.Document || !this.props.PanelWidth() ? null : (
                     <div
                         className="contentFittingDocumentView-previewDoc"
@@ -1667,7 +1558,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
                             NativeDimScaling={this.NativeDimScaling}
                             isSelected={this.isSelected}
                             select={this.select}
-                            isHovering={this.isHovering}
                             ScreenToLocalTransform={this.screenToLocalTransform}
                             focus={this.props.focus || emptyFunction}
                             ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))}
@@ -1682,10 +1572,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     }
 }
 
-export function deiconifyViewFunc(documentView: DocumentView) {
-    documentView.iconify();
-    //StrCast(doc.layoutKey).split("_")[1] === "icon" && setNativeView(doc);
-}
 ScriptingGlobals.add(function deiconifyView(documentView: DocumentView) {
     documentView.iconify();
     documentView.select(false);
-- 
cgit v1.2.3-70-g09d2

