From 524806c57b5582c6ed8893d38d79c55603ced834 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 9 Mar 2021 15:49:24 -0500
Subject: some cleanup for inlineTextAnnotations to use a better named field.
 removing some unused code.

---
 src/client/views/pdf/Annotation.tsx | 73 ++++++++++++-------------------------
 1 file changed, 23 insertions(+), 50 deletions(-)

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

diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 4e3721e2b..913cfdcc2 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -1,15 +1,15 @@
 import React = require("react");
-import { action, IReactionDisposer, observable, reaction, runInAction } from "mobx";
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
 import { Id } from "../../../fields/FieldSymbols";
 import { List } from "../../../fields/List";
-import { BoolCast, Cast, FieldValue, NumCast, PromiseValue, StrCast } from "../../../fields/Types";
+import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
 import { LinkManager } from "../../util/LinkManager";
 import { undoBatch } from "../../util/UndoManager";
-import "./Annotation.scss";
+import { FieldViewProps } from "../nodes/FieldView";
 import { AnchorMenu } from "./AnchorMenu";
-import { FieldViewProps, FieldView } from "../nodes/FieldView";
+import "./Annotation.scss";
 
 interface IAnnotationProps extends FieldViewProps {
     anno: Doc;
@@ -21,7 +21,7 @@ interface IAnnotationProps extends FieldViewProps {
 export
     class Annotation extends React.Component<IAnnotationProps> {
     render() {
-        return DocListCast(this.props.anno.annotations).map(a =>
+        return DocListCast(this.props.anno.textInlineAnnotations).map(a =>
             <RegionAnnotation {...this.props} showInfo={this.props.showInfo} document={a} x={NumCast(a.x)} y={NumCast(a.y)} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />);
     }
 }
@@ -35,59 +35,38 @@ interface IRegionAnnotationProps extends IAnnotationProps {
 }
 @observer
 class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
-    private _reactionDisposer?: IReactionDisposer;
-    private _brushDisposer?: IReactionDisposer;
+    private _disposers: { [name: string]: IReactionDisposer } = {};
     private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
 
-    @observable private _brushed: boolean = false;
+    @observable _brushed: boolean = false;
+    @computed get annoTextRegion() { return Cast(this.props.document.annoTextRegion, Doc, null) || this.props.document; }
 
     componentDidMount() {
-        this._reactionDisposer = reaction(
-            () => this.props.document.delete,
-            (del) => del && this._mainCont.current && (this._mainCont.current.style.display = "none"),
-            { fireImmediately: true }
-        );
-
-        this._brushDisposer = reaction(
-            () => FieldValue(Cast(this.props.document.group, Doc)) && Doc.isBrushedHighlightedDegree(FieldValue(Cast(this.props.document.group, Doc))!),
+        this._disposers.brush = reaction(
+            () => this.annoTextRegion && Doc.isBrushedHighlightedDegree(this.annoTextRegion),
             brushed => brushed !== undefined && runInAction(() => this._brushed = brushed !== 0)
         );
     }
 
     componentWillUnmount() {
-        this._brushDisposer?.();
-        this._reactionDisposer?.();
+        Object.values(this._disposers).forEach(disposer => disposer?.());
     }
 
     @undoBatch
     deleteAnnotation = () => {
-        const annotation = DocListCast(this.props.dataDoc[this.props.fieldKey + "-annotations"]);
-        const group = FieldValue(Cast(this.props.document.group, Doc));
-        if (group) {
-            if (annotation.indexOf(group) !== -1) {
-                const newAnnotations = annotation.filter(a => a !== FieldValue(Cast(this.props.document.group, Doc)));
-                this.props.dataDoc[this.props.fieldKey + "-annotations"] = new List<Doc>(newAnnotations);
-            }
-
-            DocListCast(group.annotations).forEach(anno => anno.delete = true);
-        }
+        const docAnnotations = DocListCast(this.props.dataDoc[this.props.fieldKey]);
+        this.props.dataDoc[this.props.fieldKey] = new List<Doc>(docAnnotations.filter(a => a !== this.annoTextRegion));
         AnchorMenu.Instance.fadeOut(true);
         this.props.select(false);
     }
 
     @undoBatch
-    pinToPres = () => {
-        const group = FieldValue(Cast(this.props.document.group, Doc));
-        group && this.props.pinToPres(group);
-    }
+    pinToPres = () => this.props.pinToPres(this.annoTextRegion);
 
     @undoBatch
-    makePushpin = action(() => {
-        const group = Cast(this.props.document.group, Doc, null);
-        group.isPushpin = !group.isPushpin;
-    });
+    makePushpin = () => this.annoTextRegion.isPushpin = !this.annoTextRegion.isPushpin;
 
-    isPushpin = () => BoolCast(Cast(this.props.document.group, Doc, null)?.isPushpin);
+    isPushpin = () => BoolCast(this.annoTextRegion.isPushpin);
 
     @action
     onPointerDown = (e: React.PointerEvent) => {
@@ -102,32 +81,26 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
             AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true);
             e.stopPropagation();
         }
-        else if (e.button === 0 && this.props.document.group instanceof Doc) {
+        else if (e.button === 0) {
             e.stopPropagation();
-            LinkManager.FollowLink(undefined, this.props.document.group, this.props, false);
+            LinkManager.FollowLink(undefined, this.annoTextRegion, this.props, false);
         }
     }
 
-
     addTag = (key: string, value: string): boolean => {
-        const group = FieldValue(Cast(this.props.document.group, Doc));
-        if (group) {
-            const valNum = parseInt(value);
-            group[key] = isNaN(valNum) ? value : valNum;
-            return true;
-        }
-        return false;
+        const valNum = parseInt(value);
+        this.annoTextRegion[key] = isNaN(valNum) ? value : valNum;
+        return true;
     }
 
-    @observable _showInfo = false;
     render() {
-        return (<div className="pdfAnnotation" onPointerEnter={action(() => this.props.showInfo(this.props.anno))} onPointerLeave={action(() => this.props.showInfo(undefined))} onPointerDown={this.onPointerDown} ref={this._mainCont}
+        return (<div className="pdfAnnotation" onPointerEnter={() => this.props.showInfo(this.props.anno)} onPointerLeave={() => this.props.showInfo(undefined)} onPointerDown={this.onPointerDown} ref={this._mainCont}
             style={{
                 top: this.props.y,
                 left: this.props.x,
                 width: this.props.width,
                 height: this.props.height,
-                opacity: !this._showInfo && this._brushed ? 0.5 : undefined,
+                opacity: this._brushed ? 0.5 : undefined,
                 backgroundColor: this._brushed ? "orange" : StrCast(this.props.document.backgroundColor),
             }} >
         </div>);
-- 
cgit v1.2.3-70-g09d2


From 9e04c57cab8095277398cbcee6fa4ebd904dcf85 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 9 Mar 2021 20:56:29 -0500
Subject: changed field unchanged -> googleDocUnchanged.  cleaned up some other
 code.

---
 src/client/views/DocumentButtonBar.tsx             |   6 +-
 src/client/views/PropertiesButtons.tsx             |   6 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx | 138 +++++++++------------
 src/client/views/pdf/Annotation.tsx                |  17 +--
 src/client/views/pdf/PDFViewer.tsx                 | 109 +++++++---------
 5 files changed, 117 insertions(+), 159 deletions(-)

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

diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index a9cd7b4a9..5ebf29603 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -131,7 +131,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
         const title = (() => {
             switch (this.openHover) {
                 default:
-                case UtilityButtonState.Default: return `${!dataDoc?.unchanged ? "Pull from" : "Fetch"} Google Docs`;
+                case UtilityButtonState.Default: return `${!dataDoc?.googleDocUnchanged ? "Pull from" : "Fetch"} Google Docs`;
                 case UtilityButtonState.OpenRight: return "Open in Right Split";
                 case UtilityButtonState.OpenExternally: return "Open in new Browser Tab";
             }
@@ -167,7 +167,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                         this.clearPullColor();
                         DocumentButtonBar.hasPulledHack = false;
                         targetDoc[Pulls] = NumCast(targetDoc[Pulls]) + 1;
-                        dataDoc.unchanged && runInAction(() => this.isAnimatingFetch = true);
+                        dataDoc.googleDocUnchanged && runInAction(() => this.isAnimatingFetch = true);
                     }
                 }}>
                 <FontAwesomeIcon className="documentdecorations-icon" size="sm"
@@ -175,7 +175,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                     icon={(() => {
                         switch (this.openHover) {
                             default:
-                            case UtilityButtonState.Default: return dataDoc.unchanged === false ? (this.pullIcon as any) : fetch;
+                            case UtilityButtonState.Default: return dataDoc.googleDocUnchanged === false ? (this.pullIcon as any) : fetch;
                             case UtilityButtonState.OpenRight: return "arrow-alt-circle-right";
                             case UtilityButtonState.OpenExternally: return "share";
                         }
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index e418a6f3c..bf72dbdba 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -131,7 +131,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
         const title = (() => {
             switch (this.openHover) {
                 default:
-                case UtilityButtonState.Default: return `${!dataDoc?.unchanged ? "Pull from" : "Fetch"} Google Docs`;
+                case UtilityButtonState.Default: return `${!dataDoc?.googleDocUnchanged ? "Pull from" : "Fetch"} Google Docs`;
                 case UtilityButtonState.OpenRight: return "Open in Right Split";
                 case UtilityButtonState.OpenExternally: return "Open in new Browser Tab";
             }
@@ -165,7 +165,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                             this.clearPullColor();
                             PropertiesButtons.hasPulledHack = false;
                             targetDoc[Pulls] = NumCast(targetDoc[Pulls]) + 1;
-                            dataDoc.unchanged && runInAction(() => this.isAnimatingFetch = true);
+                            dataDoc.googleDocUnchanged && runInAction(() => this.isAnimatingFetch = true);
                         }
                     }}>
                     <FontAwesomeIcon className="documentdecorations-icon" size="lg" color="black"
@@ -173,7 +173,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                         icon={(() => {
                             switch (this.openHover) {
                                 default:
-                                case UtilityButtonState.Default: return dataDoc.unchanged === false ? (this.pullIcon as any) : fetch;
+                                case UtilityButtonState.Default: return dataDoc.googleDocUnchanged === false ? (this.pullIcon as any) : fetch;
                                 case UtilityButtonState.OpenRight: return "arrow-alt-circle-right";
                                 case UtilityButtonState.OpenExternally: return "share";
                             }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 29f6e2bd8..89df7a98a 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -15,7 +15,7 @@ import { DataSym, Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, Wid
 import { documentSchema } from '../../../../fields/documentSchemas';
 import applyDevTools = require("prosemirror-dev-tools");
 import { removeMarkWithAttrs } from "./prosemirrorPatches";
-import { Id, Copy } from '../../../../fields/FieldSymbols';
+import { Id } from '../../../../fields/FieldSymbols';
 import { InkTool } from '../../../../fields/InkField';
 import { PrefetchProxy } from '../../../../fields/Proxy';
 import { RichTextField } from "../../../../fields/RichTextField";
@@ -90,8 +90,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     public static get DefaultLayout() {
         return Cast(Doc.UserDoc().defaultTextLayout, Doc, null) || StrCast(Doc.UserDoc().defaultTextLayout, null);
     }
-    public static CanAnnotate = true;
     public static Instance: FormattedTextBox;
+    static _highlights: string[] = ["Audio Tags", "Text from Others", "Todo Items", "Important Items", "Disagree Items", "Ignore Items"];
+    static _highlightStyleSheet: any = addStyleSheet();
+    static _bulletStyleSheet: any = addStyleSheet();
+    static _userStyleSheet: any = addStyleSheet();
+    static _canAnnotate = true;
+    static _hadSelection: boolean = false;
+    public static LiveTextUndo: UndoManager.Batch | undefined;
     public ProseRef?: HTMLDivElement;
     public get EditorView() { return this._editorView; }
     public get SidebarKey() { return this.fieldKey + "-sidebar"; }
@@ -111,6 +117,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     private _focusSpeed: Opt<number>;
     private _keymap: any = undefined;
     private _rules: RichTextRules | undefined;
+    private _forceUncollapse = true; // if the cursor doesn't move between clicks, then the selection will disappear for some reason.  This flags the 2nd click as happening on a selection which allows bullet points to toggle
+    private _forceDownNode: Node | undefined;
+    private _downEvent: any;
+    private _downX = 0;
+    private _downY = 0;
+    private _break = false;
 
     @computed get sidebarWidthPercent() { return StrCast(this.layoutDoc._sidebarWidthPercent, "0%"); }
     @computed get sidebarColor() { return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "#e4e4e4")); }
@@ -121,10 +133,26 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     @computed get titleHeight() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin) || 0; }
     @computed get _recording() { return this.dataDoc?.audioState === "recording"; }
     set _recording(value) { this.dataDoc.audioState = value ? "recording" : undefined; }
+    @computed get config() {
+        this._keymap = buildKeymap(schema, this.props);
+        this._rules = new RichTextRules(this.props.Document, this);
+        return {
+            schema,
+            plugins: [
+                inputRules(this._rules.inpRules),
+                this.richTextMenuPlugin(),
+                history(),
+                keymap(this._keymap),
+                keymap(baseKeymap),
+                new Plugin({ props: { attributes: { class: "ProseMirror-example-setup-style" } } }),
+                new Plugin({ view(editorView) { return new FormattedTextBoxComment(editorView); } })
+            ]
+        };
+    }
 
     public static FocusedBox: FormattedTextBox | undefined;
-    public static SelectOnLoad = "";
     public static PasteOnLoad: ClipboardEvent | undefined;
+    public static SelectOnLoad = "";
     public static SelectOnLoadChar = "";
     public static IsFragment(html: string) { return html.indexOf("data-pm-slice") !== -1; }
     public static GetHref(html: string): string {
@@ -314,7 +342,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     }
 
     // needs a better API for taking in a set of words with target documents instead of just one target
-    public hyperlinkTerms = (terms: string[], target: Doc) => {
+    hyperlinkTerms = (terms: string[], target: Doc) => {
         if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
             const res1 = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
             let tr = this._editorView.state.tr;
@@ -334,7 +362,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             this._editorView.dispatch(tr);
         }
     }
-    public highlightSearchTerms = (terms: string[], backward: boolean) => {
+    highlightSearchTerms = (terms: string[], backward: boolean) => {
         if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
             const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
             const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true });
@@ -363,7 +391,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         }
     }
 
-    public unhighlightSearchTerms = () => {
+    unhighlightSearchTerms = () => {
         if (window.screen.width < 600) null;
         else if (this._editorView && (this._editorView as any).docView) {
             const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
@@ -409,7 +437,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 target._fitToBox = true;
                 const node = schema.nodes.dashDoc.create({
                     width: target[WidthSym](), height: target[HeightSym](),
-                    title: "dashDoc", docid: target[Id],
+                    title: "dashDoc",
+                    docid: target[Id],
                     float: "right"
                 });
                 const view = this._editorView!;
@@ -463,7 +492,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         return ret;
     }
 
-    static _highlights: string[] = ["Audio Tags", "Text from Others", "Todo Items", "Important Items", "Disagree Items", "Ignore Items"];
     updateHighlights = () => {
         clearStyleSheetRules(FormattedTextBox._userStyleSheet);
         if (FormattedTextBox._highlights.indexOf("Audio Tags") === -1) {
@@ -548,7 +576,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             }));
 
         const uicontrols: ContextMenuProps[] = [];
-        uicontrols.push({ description: `${FormattedTextBox.CanAnnotate ? "Hide" : "Show"} Annotation Bar`, event: () => FormattedTextBox.CanAnnotate = !FormattedTextBox.CanAnnotate, icon: "expand-arrows-alt" });
+        uicontrols.push({ description: `${FormattedTextBox._canAnnotate ? "Hide" : "Show"} Annotation Bar`, event: () => FormattedTextBox._canAnnotate = !FormattedTextBox._canAnnotate, icon: "expand-arrows-alt" });
         uicontrols.push({ description: !this.Document._noSidebar ? "Hide Sidebar Handle" : "Show Sidebar Handle", event: () => this.layoutDoc._noSidebar = !this.layoutDoc._noSidebar, icon: "expand-arrows-alt" });
         uicontrols.push({ description: `${this.layoutDoc._showAudio ? "Hide" : "Show"} Dictation Icon`, event: () => this.layoutDoc._showAudio = !this.layoutDoc._showAudio, icon: "expand-arrows-alt" });
         uicontrols.push({ description: "Show Highlights...", noexpand: true, subitems: highlighting, icon: "hand-point-right" });
@@ -637,26 +665,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         }
     }
 
-    @computed get config() {
-        this._keymap = buildKeymap(schema, this.props);
-        this._rules = new RichTextRules(this.props.Document, this);
-        return {
-            schema,
-            plugins: [
-                inputRules(this._rules.inpRules),
-                this.richTextMenuPlugin(),
-                history(),
-                keymap(this._keymap),
-                keymap(baseKeymap),
-                new Plugin({
-                    props: {
-                        attributes: { class: "ProseMirror-example-setup-style" }
-                    }
-                }), new Plugin({ view(editorView) { return new FormattedTextBoxComment(editorView); } })
-            ]
-        };
-    }
-
     makeLinkAnchor(anchorDoc?: Doc, location?: string, targetHref?: string, title?: string) {
         const state = this._editorView?.state;
         if (state) {
@@ -761,7 +769,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             instance => {
                 if (instance) {
                     this.pullFromGoogleDoc(this.checkState);
-                    this.dataDoc[GoogleRef] && this.dataDoc.unchanged && runInAction(() => instance.isAnimatingFetch = true);
+                    this.dataDoc[GoogleRef] && this.dataDoc.googleDocUnchanged && runInAction(() => instance.isAnimatingFetch = true);
                 }
             }
         );
@@ -791,7 +799,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             () => {
                 if (!DocumentButtonBar.hasPulledHack) {
                     DocumentButtonBar.hasPulledHack = true;
-                    this.pullFromGoogleDoc(this.dataDoc.unchanged ? this.checkState : this.updateState);
+                    this.pullFromGoogleDoc(this.dataDoc.googleDocUnchanged ? this.checkState : this.updateState);
                 }
             }
         );
@@ -866,7 +874,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     const response = await GoogleApiClientUtils.Docs.write({ reference, content, mode });
                     response && (this.dataDoc[GoogleRef] = response.documentId);
                     const pushSuccess = response !== undefined && !("errors" in response);
-                    dataDoc.unchanged = pushSuccess;
+                    dataDoc.googleDocUnchanged = pushSuccess;
                     DocumentButtonBar.Instance.startPushOutcome(pushSuccess);
                 }
             };
@@ -911,7 +919,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             }, 0);
             dataDoc.title = exportState.title;
             this.dataDoc["title-custom"] = true;
-            dataDoc.unchanged = true;
+            dataDoc.googleDocUnchanged = true;
         } else {
             delete dataDoc[GoogleRef];
         }
@@ -923,7 +931,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             const equalContent = isEqual(this._editorView.state.doc, exportState.state.doc);
             const equalTitles = dataDoc.title === exportState.title;
             const unchanged = equalContent && equalTitles;
-            dataDoc.unchanged = unchanged;
+            dataDoc.googleDocUnchanged = unchanged;
             DocumentButtonBar.Instance.setPullState(unchanged);
         }
     }
@@ -1100,11 +1108,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "none");
     }
 
-    _downEvent: any;
-    _downX = 0;
-    _downY = 0;
-    _break = false;
-    _collapsed = false;
     onPointerDown = (e: React.PointerEvent): void => {
         if ((e.target as any).tagName === "AUDIOTAG") {
             e.preventDefault();
@@ -1152,9 +1155,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         document.removeEventListener("pointerup", this.onSelectEnd);
         document.removeEventListener("pointermove", this.onSelectMove);
     }
-
     onPointerUp = (e: React.PointerEvent): void => {
-        if (!this._editorView?.state.selection.empty && FormattedTextBox.CanAnnotate) this.setupAnchorMenu();
+        if (!this._editorView?.state.selection.empty && FormattedTextBox._canAnnotate) this.setupAnchorMenu();
         if (!this._downEvent) return;
         this._downEvent = false;
         if (!(e.nativeEvent as any).formattedHandled && this.active(true)) {
@@ -1171,7 +1173,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             e.stopPropagation();
         }
     }
-
     @action
     onDoubleClick = (e: React.MouseEvent): void => {
         FormattedTextBoxComment.textBox = this;
@@ -1191,7 +1192,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             e.stopPropagation();
         }
     }
-
     @action
     onFocused = (e: React.FocusEvent): void => {
         FormattedTextBox.FocusedBox = this;
@@ -1223,12 +1223,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             e.stopPropagation();
         }
     }
-
-    static _highlightStyleSheet: any = addStyleSheet();
-    static _bulletStyleSheet: any = addStyleSheet();
-    static _userStyleSheet: any = addStyleSheet();
-    _forceUncollapse = true; // if the cursor doesn't move between clicks, then the selection will disappear for some reason.  This flags the 2nd click as happening on a selection which allows bullet points to toggle
-    _forceDownNode: Node | undefined;
     onClick = (e: React.MouseEvent): void => {
         if (Math.abs(e.clientX - this._downX) > 4 || Math.abs(e.clientY - this._downY) > 4) {
             this._forceDownNode = undefined;
@@ -1264,7 +1258,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         this._forceUncollapse = !(this._editorView!.root as any).getSelection().isCollapsed;
         this._forceDownNode = (this._editorView!.state.selection as NodeSelection)?.node;
     }
-
     // this hackiness handles clicking on the list item bullets to do expand/collapse.  the bullets are ::before pseudo elements so there's no real way to hit test against them.
     hitBulletTargets(x: number, y: number, collapse: boolean, highlightOnly: boolean, downNode: Node | undefined = undefined, selectOrderedList: boolean = false) {
         this._forceUncollapse = false;
@@ -1314,24 +1307,20 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             view.root.addEventListener("mouseup", view.mouseDown.up);
         }
     }
-
-    public startUndoTypingBatch() {
+    startUndoTypingBatch() {
         !this._undoTyping && (this._undoTyping = UndoManager.StartBatch("undoTyping"));
     }
-
     public endUndoTypingBatch() {
         const wasUndoing = this._undoTyping;
         this._undoTyping?.end();
         this._undoTyping = undefined;
         return wasUndoing;
     }
-    public static LiveTextUndo: UndoManager.Batch | undefined;
-    public static HadSelection: boolean = false;
     onBlur = (e: any) => {
         if (RichTextMenu.Instance?.view === this._editorView && !this.props.isSelected(true)) {
             RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined);
         }
-        FormattedTextBox.HadSelection = window.getSelection()?.toString() !== "";
+        FormattedTextBox._hadSelection = window.getSelection()?.toString() !== "";
         this.endUndoTypingBatch();
 
         FormattedTextBox.LiveTextUndo?.end();
@@ -1350,7 +1339,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             this._lastText = curText;
         }
     }
-
     onKeyDown = (e: React.KeyboardEvent) => {
         // single line text boxes need to pass through tab/enter/backspace so that their containers can respond (eg, an outline container)
         if (this.rootDoc._singleLine && ((e.key === "Backspace" && !this.dataDoc[this.fieldKey]?.Text) || ["Tab", "Enter"].includes(e.key))) {
@@ -1372,29 +1360,27 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             this._rules!.EnteringStyle = false;
         }
         e.stopPropagation();
-        if (e.key === "Escape") {
-            this._editorView!.dispatch(state.tr.setSelection(TextSelection.create(state.doc, state.selection.from, state.selection.from)));
-            (document.activeElement as any).blur?.();
-            SelectionManager.DeselectAll();
-            RichTextMenu.Instance.updateMenu(undefined, undefined, undefined);
-        } else {
-            if (e.key === "Tab" || e.key === "Enter") {
-                if (e.key === "Enter") this.insertTime();
-                e.preventDefault();
-            }
-            if (e.key === " " || this._lastTimedMark?.attrs.userid !== Doc.CurrentUserEmail) {
-                const mark = schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) });
-                this._editorView!.dispatch(this._editorView!.state.tr.removeStoredMark(schema.marks.user_mark.create({})).addStoredMark(mark));
-            }
-            this.startUndoTypingBatch();
+        switch (e.key) {
+            case "Escape":
+                this._editorView!.dispatch(state.tr.setSelection(TextSelection.create(state.doc, state.selection.from, state.selection.from)));
+                (document.activeElement as any).blur?.();
+                SelectionManager.DeselectAll();
+                RichTextMenu.Instance.updateMenu(undefined, undefined, undefined);
+                return;
+            case "Enter": this.insertTime();
+            case "Tab": e.preventDefault(); break;
+            default: if (this._lastTimedMark?.attrs.userid === Doc.CurrentUserEmail) break;
+            case " ":
+                this._editorView!.dispatch(this._editorView!.state.tr.removeStoredMark(schema.marks.user_mark.create({}))
+                    .addStoredMark(schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })));
         }
+        this.startUndoTypingBatch();
     }
-
-    ondrop = (eve: React.DragEvent) => {
+    ondrop = (e: React.DragEvent) => {
         this._editorView!.dispatch(updateBullets(this._editorView!.state.tr, this._editorView!.state.schema));
-        eve.stopPropagation(); // drag n drop of text within text note will generate a new note if not caughst, as will dragging in from outside of Dash.
+        e.stopPropagation(); // drag n drop of text within text note will generate a new note if not caughst, as will dragging in from outside of Dash.
     }
-    onScroll = (ev: React.UIEvent) => {
+    onScroll = (e: React.UIEvent) => {
         if (!LinkDocPreview.LinkInfo && this._scrollRef.current) {
             this._ignoreScroll = true;
             this.layoutDoc._scrollTop = this._scrollRef.current.scrollTop;
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 913cfdcc2..05d81f40f 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -1,7 +1,7 @@
 import React = require("react");
 import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
+import { Doc, DocListCast, Opt } from "../../../fields/Doc";
 import { Id } from "../../../fields/FieldSymbols";
 import { List } from "../../../fields/List";
 import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
@@ -21,16 +21,11 @@ interface IAnnotationProps extends FieldViewProps {
 export
     class Annotation extends React.Component<IAnnotationProps> {
     render() {
-        return DocListCast(this.props.anno.textInlineAnnotations).map(a =>
-            <RegionAnnotation {...this.props} showInfo={this.props.showInfo} document={a} x={NumCast(a.x)} y={NumCast(a.y)} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />);
+        return DocListCast(this.props.anno.textInlineAnnotations).map(a => <RegionAnnotation {...this.props} document={a} key={a[Id]} />);
     }
 }
 
 interface IRegionAnnotationProps extends IAnnotationProps {
-    x: number;
-    y: number;
-    width: number;
-    height: number;
     document: Doc;
 }
 @observer
@@ -96,10 +91,10 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
     render() {
         return (<div className="pdfAnnotation" onPointerEnter={() => this.props.showInfo(this.props.anno)} onPointerLeave={() => this.props.showInfo(undefined)} onPointerDown={this.onPointerDown} ref={this._mainCont}
             style={{
-                top: this.props.y,
-                left: this.props.x,
-                width: this.props.width,
-                height: this.props.height,
+                left: NumCast(this.props.document.x),
+                top: NumCast(this.props.document.y),
+                width: NumCast(this.props.document._width),
+                height: NumCast(this.props.document._height),
                 opacity: this._brushed ? 0.5 : undefined,
                 backgroundColor: this._brushed ? "orange" : StrCast(this.props.document.backgroundColor),
             }} >
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 28d7b0954..73aea9737 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -8,8 +8,7 @@ import { documentSchema } from "../../../fields/documentSchemas";
 import { Id } from "../../../fields/FieldSymbols";
 import { InkTool } from "../../../fields/InkField";
 import { createSchema, makeInterface } from "../../../fields/Schema";
-import { ScriptField } from "../../../fields/ScriptField";
-import { Cast, NumCast, StrCast } from "../../../fields/Types";
+import { Cast, NumCast, StrCast, ScriptCast } from "../../../fields/Types";
 import { PdfField } from "../../../fields/URLField";
 import { TraceMobx } from "../../../fields/util";
 import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, OmitKeys, smoothScroll, Utils } from "../../../Utils";
@@ -66,12 +65,12 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
     @observable private _pageSizes: { width: number, height: number }[] = [];
     @observable private _savedAnnotations: Dictionary<number, HTMLDivElement[]> = new Dictionary<number, HTMLDivElement[]>();
     @observable private _script: CompiledScript = CompileScript("return true") as CompiledScript;
-    @observable private Index: number = -1;
     @observable private _marqueeing: number[] | undefined;
     @observable private _showWaiting = true;
     @observable private _showCover = false;
     @observable private _zoomed = 1;
     @observable private _overlayAnnoInfo: Opt<Doc>;
+    @observable private Index: number = -1;
 
     private _pdfViewer: any;
     private _styleRule: any; // stylesheet rule for making hyperlinks clickable
@@ -89,7 +88,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
     private _viewerIsSetup = false;
     private _ignoreScroll = false;
     private _initialScroll: Opt<number>;
-    private _smoothScrolling = true;
+    private _forcedScroll = true;
 
     @computed get allAnnotations() {
         return DocUtils.FilterDocs(DocListCast(this.dataDoc[this.props.fieldKey + "-annotations"]), this.props.docFilters(), this.props.docRangeFilters(), undefined);
@@ -158,12 +157,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
 
     copy = (e: ClipboardEvent) => {
         if (this.active() && e.clipboardData) {
-            //const annoDoc = this.makeAnnotationDocument("rgba(3,144,152,0.3)");  // copied text markup color (blueish)
-            //if (annoDoc) {
             e.clipboardData.setData("text/plain", this._selectionText);
-            // e.clipboardData.setData("dash/pdfOrigin", this.props.Document[Id]);
-            // e.clipboardData.setData("dash/pdfRegion", annoDoc[Id]);
-            //}
             e.preventDefault();
         }
     }
@@ -174,12 +168,13 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
             this._pageSizes = Array<{ width: number, height: number }>(this.props.pdf.numPages);
             await Promise.all(this._pageSizes.map<Pdfjs.PDFPromise<any>>((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[page.rotate === 0 || page.rotate === 180 ? 2 : 3] - page.view[page.rotate === 0 || page.rotate === 180 ? 0 : 1]),
-                        height: (page.view[page.rotate === 0 || page.rotate === 180 ? 3 : 2] - page.view[page.rotate === 0 || page.rotate === 180 ? 1 : 0])
+                        width: (page.view[page0or180 ? 2 : 3] - page.view[page0or180 ? 0 : 1]),
+                        height: (page.view[page0or180 ? 3 : 2] - page.view[page0or180 ? 1 : 0])
                     });
-                    i === this.props.pdf.numPages - 1 && this.props.loaded?.((page.view[page.rotate === 0 || page.rotate === 180 ? 2 : 3] - page.view[page.rotate === 0 || page.rotate === 180 ? 0 : 1]),
-                        (page.view[page.rotate === 0 || page.rotate === 180 ? 3 : 2] - page.view[page.rotate === 0 || page.rotate === 180 ? 1 : 0]), i);
+                    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]), i);
                 }))));
             this.Document.scrollHeight = this._pageSizes.reduce((size, page) => size + page.height, 0) * 96 / 72;
         }
@@ -207,13 +202,13 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
     @action
     setupPdfJsViewer = async () => {
         if (this._viewerIsSetup) return;
-        else this._viewerIsSetup = true;
+        this._viewerIsSetup = true;
         this._showWaiting = true;
         this.props.setPdfViewer(this);
         await this.initialLoad();
 
         this._disposers.filterScript = reaction(
-            () => Cast(this.Document.filterScript, ScriptField),
+            () => ScriptCast(this.Document.filterScript),
             action(scriptField => {
                 const oldScript = this._script.originalScript;
                 this._script = scriptField?.script.compiled ? scriptField.script : CompileScript("return true") as CompiledScript;
@@ -234,25 +229,23 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
         document.removeEventListener("pagesinit", this.pagesinit);
         var quickScroll: string | undefined = this._initialScroll ? this._initialScroll.toString() : "";
         this._disposers.scroll = reaction(
-            () => NumCast(this.Document._scrollTop),
+            () => Math.abs(NumCast(this.Document._scrollTop)),
             (pos) => {
                 if (!this._ignoreScroll) {
                     (this._showCover || this._showWaiting) && this.setupPdfJsViewer();
                     const viewTrans = quickScroll ?? StrCast(this.Document._viewTransition);
-                    const delay = this._mainCont.current ? 0 : 250; // wait for mainCont and try again to scroll
                     const durationMiliStr = viewTrans.match(/([0-9]*)ms/);
                     const durationSecStr = viewTrans.match(/([0-9.]*)s/);
                     const duration = durationMiliStr ? Number(durationMiliStr[1]) : durationSecStr ? Number(durationSecStr[1]) * 1000 : 0;
+                    this._forcedScroll = true;
                     if (duration) {
-                        this._smoothScrolling = true;
                         setTimeout(() => {
-                            this._mainCont.current && smoothScroll(duration, this._mainCont.current, Math.abs(pos || 0));
-                            setTimeout(() => this._smoothScrolling = false, duration);
-                        }, delay);
+                            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._smoothScrolling = true;
-                        this._mainCont.current?.scrollTo({ top: Math.abs(pos || 0) });
-                        this._smoothScrolling = false;
+                        this._mainCont.current?.scrollTo({ top: pos });
+                        this._forcedScroll = false;
                     }
                 }
             },
@@ -267,8 +260,10 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
 
     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._retries < 5) {
                 this._retries++;
+                console.log("PDFViewer- retry num:" + this._retries);
                 setTimeout(() => this.createPdfViewer(), 1000);
             }
             return;
@@ -277,9 +272,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
         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("pagerendered", action(() => this._showWaiting = false));
         const pdfLinkService = new PDFJSViewer.PDFLinkService({ eventBus });
         const pdfFindController = new PDFJSViewer.PDFFindController({ linkService: pdfLinkService, eventBus });
         this._pdfViewer = new PDFJSViewer.PDFViewer({
@@ -324,8 +317,8 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
     }
 
     onScroll = (e: React.UIEvent<HTMLElement>) => {
-        if (this._mainCont.current && !this._smoothScrolling) {
-            this._ignoreScroll = true;
+        if (this._mainCont.current && !this._forcedScroll) {
+            this._ignoreScroll = true; // the pdf scrolled, so we need to tell the Doc to scroll but we don't want the doc to then try to set the PDF scroll pos (which would interfere with the smooth scroll animation)
             if (!LinkDocPreview.LinkInfo) {
                 this.layoutDoc._scrollTop = this._mainCont.current.scrollTop;
             }
@@ -343,32 +336,24 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
         return index;
     }
 
-
     @action
     search = (searchString: string, fwd: boolean, clear: boolean = false) => {
+        const findOpts = {
+            caseSensitive: false,
+            findPrevious: !fwd,
+            highlightAll: true,
+            phraseSearch: true,
+            query: searchString
+        };
         if (clear) {
             this._pdfViewer?.findController.executeCommand('reset', { query: "" });
         } else if (!searchString) {
             fwd ? this.nextAnnotation() : this.prevAnnotation();
         } else if (this._pdfViewer?.pageViewsReady) {
-            this._pdfViewer.findController.executeCommand('findagain', {
-                caseSensitive: false,
-                findPrevious: !fwd,
-                highlightAll: true,
-                phraseSearch: true,
-                query: searchString
-            });
+            this._pdfViewer.findController.executeCommand('findagain', findOpts);
         }
         else if (this._mainCont.current) {
-            const executeFind = () => {
-                this._pdfViewer.findController.executeCommand('find', {
-                    caseSensitive: false,
-                    findPrevious: !fwd,
-                    highlightAll: true,
-                    phraseSearch: true,
-                    query: searchString
-                });
-            };
+            const executeFind = () => this._pdfViewer.findController.executeCommand('find', findOpts);
             this._mainCont.current.addEventListener("pagesloaded", executeFind);
             this._mainCont.current.addEventListener("pagerendered", executeFind);
         }
@@ -376,7 +361,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
 
     @action
     onPointerDown = (e: React.PointerEvent): void => {
-        const hit = document.elementFromPoint(e.clientX, e.clientY);
+        // const hit = document.elementFromPoint(e.clientX, e.clientY);
         // bcz: Change. drag selecting requires that preventDefault is NOT called.  This used to happen in DocumentView,
         //      but that's changed, so this shouldn't be needed.
         // if (hit && hit.localName === "span" && this.annotationsActive(true)) {  // drag selecting text stops propagation
@@ -414,11 +399,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
         this.props.select(false);
     }
 
-    @action
-    onSelectMove = (e: PointerEvent): void => {
-        // if (e.target && (e.target as any).parentElement === this._mainCont.current) 
-        e.stopPropagation();
-    }
+    onSelectMove = (e: PointerEvent) => e.stopPropagation();
 
     @action
     onSelectEnd = (e: PointerEvent): void => {
@@ -429,8 +410,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
 
         const sel = window.getSelection();
         if (sel?.type === "Range") {
-            const selRange = sel.getRangeAt(0);
-            this.createTextAnnotation(sel, selRange);
+            this.createTextAnnotation(sel, sel.getRangeAt(0));
             AnchorMenu.Instance.jumpTo(e.clientX, e.clientY);
         }
     }
@@ -442,18 +422,16 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
             const clientRects = selRange.getClientRects();
             for (let i = 0; i < clientRects.length; i++) {
                 const rect = clientRects.item(i);
-                if (rect) {
+                if (rect && rect.width !== this._mainCont.current.clientWidth) {
                     const scaleX = this._mainCont.current.offsetWidth / boundingRect.width;
-                    if (rect.width !== this._mainCont.current.clientWidth) {
-                        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 / this._zoomed + this._mainCont.current.scrollTop).toString();
-                        annoBox.style.left = ((rect.left - boundingRect.left) * scaleX / this._zoomed).toString();
-                        annoBox.style.width = (rect.width * this._mainCont.current.offsetWidth / boundingRect.width / this._zoomed).toString();
-                        annoBox.style.height = (rect.height * this._mainCont.current.offsetHeight / boundingRect.height / this._zoomed).toString();
-                        this._annotationLayer.current && MarqueeAnnotator.previewNewAnnotation(this._savedAnnotations, this._annotationLayer.current, annoBox, this.getPageFromScroll(rect.top));
-                    }
+                    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 / this._zoomed + this._mainCont.current.scrollTop).toString();
+                    annoBox.style.left = ((rect.left - boundingRect.left) * scaleX / this._zoomed).toString();
+                    annoBox.style.width = (rect.width * this._mainCont.current.offsetWidth / boundingRect.width / this._zoomed).toString();
+                    annoBox.style.height = (rect.height * this._mainCont.current.offsetHeight / boundingRect.height / this._zoomed).toString();
+                    this._annotationLayer.current && MarqueeAnnotator.previewNewAnnotation(this._savedAnnotations, this._annotationLayer.current, annoBox, this.getPageFromScroll(rect.top));
                 }
             }
         }
@@ -509,7 +487,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
     }
 
     @computed get annotationLayer() {
-        TraceMobx();
         return <div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this.Document), transform: `scale(${this._zoomed})` }} ref={this._annotationLayer}>
             {this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno =>
                 <Annotation {...this.props} fieldKey={this.fieldKey + "-annotations"} showInfo={this.showInfo} dataDoc={this.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} />)
-- 
cgit v1.2.3-70-g09d2

