From d6720fa48d78cc313d6418acd8cbdaeda965285c Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 25 Apr 2024 17:15:20 -0400
Subject: changed marqueeAnnotator to save inline annotations as text strings
 instead of Docs. enabled making image crops of text selections on PDFs. 
 cleaned up webboxrendered lint promses, and Annotation render

---
 src/client/views/pdf/Annotation.tsx | 157 +++++++++++++++++-------------------
 1 file changed, 74 insertions(+), 83 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 38578837a..f1cd1a4f7 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -1,9 +1,8 @@
-/* eslint-disable react/jsx-props-no-spreading */
 import { action, computed, makeObservable } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { Doc, DocListCast, Opt } from '../../../fields/Doc';
-import { Id } from '../../../fields/FieldSymbols';
+import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc';
+import { Highlight } from '../../../fields/DocSymbols';
 import { List } from '../../../fields/List';
 import { BoolCast, DocCast, NumCast, StrCast } from '../../../fields/Types';
 import { LinkFollower } from '../../util/LinkFollower';
@@ -14,13 +13,38 @@ import { OpenWhere } from '../nodes/DocumentView';
 import { FieldViewProps } from '../nodes/FieldView';
 import { AnchorMenu } from './AnchorMenu';
 import './Annotation.scss';
-import { Highlight } from '../../../fields/DocSymbols';
+
+interface IRegionAnnotationProps {
+    x: number;
+    y: number;
+    width: number;
+    height: number;
+    opacity: () => number;
+    background: () => string;
+    outline: () => string | undefined;
+}
+
+const RegionAnnotation = function (props: IRegionAnnotationProps) {
+    return (
+        <div
+            className="htmlAnnotation"
+            style={{
+                left: NumCast(props.x),
+                top: NumCast(props.y),
+                width: NumCast(props.width),
+                height: NumCast(props.height),
+                opacity: props.opacity(),
+                outline: props.outline(),
+                backgroundColor: props.background(),
+            }}
+        />
+    );
+};
 
 interface IAnnotationProps extends FieldViewProps {
-    anno: Doc;
-    dataDoc: Doc;
+    annoDoc: Doc;
+    containerDataDoc: Doc;
     fieldKey: string;
-    showInfo?: (anno: Opt<Doc>) => void;
     pointerEvents?: () => Opt<string>;
 }
 @observer
@@ -31,64 +55,25 @@ export class Annotation extends ObservableReactComponent<IAnnotationProps> {
     }
 
     @computed get linkHighlighted() {
-        const found = LinkManager.Instance.getAllDirectLinks(this._props.anno).find(link => {
-            const a1 = LinkManager.getOppositeAnchor(link, this._props.anno);
+        const found = LinkManager.Instance.getAllDirectLinks(this._props.annoDoc).find(link => {
+            const a1 = LinkManager.getOppositeAnchor(link, this._props.annoDoc);
             return a1 && Doc.GetBrushStatus(DocCast(a1.annotationOn, a1));
         });
         return found;
     }
-    linkHighlightedFunc = () => this.linkHighlighted;
-    highlightedFunc = () => this._props.anno[Highlight];
 
     deleteAnnotation = undoable(() => {
-        const docAnnotations = DocListCast(this._props.dataDoc[this._props.fieldKey]);
-        this._props.dataDoc[this._props.fieldKey] = new List<Doc>(docAnnotations.filter(a => a !== this._props.anno));
+        const docAnnotations = DocListCast(this._props.containerDataDoc[this._props.fieldKey]);
+        this._props.containerDataDoc[this._props.fieldKey] = new List<Doc>(docAnnotations.filter(a => a !== this._props.annoDoc));
         AnchorMenu.Instance.fadeOut(true);
         this._props.select(false);
     }, 'delete annotation');
 
-    pinToPres = undoable(() => this._props.pinToPres(this._props.anno, {}), 'pin to pres');
-
-    render() {
-        return (
-            <div style={{ display: this._props.anno.textCopied && !Doc.GetBrushHighlightStatus(this._props.anno) ? 'none' : undefined }}>
-                {DocListCast(this._props.anno.text_inlineAnnotations).map(a => (
-                    // eslint-disable-next-line no-use-before-define
-                    <RegionAnnotation
-                        pointerEvents={this._props.pointerEvents}
-                        {...this._props}
-                        highlighted={this.highlightedFunc}
-                        linkHighlighted={this.linkHighlightedFunc}
-                        pinToPres={this.pinToPres}
-                        deleteAnnotation={this.deleteAnnotation}
-                        document={a}
-                        key={a[Id]}
-                    />
-                ))}
-            </div>
-        );
-    }
-}
-
-interface IRegionAnnotationProps extends IAnnotationProps {
-    document: Doc;
-    linkHighlighted: () => Doc | undefined;
-    highlighted: () => any;
-    deleteAnnotation: () => void;
-    pinToPres: (...args: any[]) => void;
-    pointerEvents?: () => Opt<string>;
-}
-@observer
-class RegionAnnotation extends ObservableReactComponent<IRegionAnnotationProps> {
-    private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
-
-    @computed get regionDoc() {
-        return DocCast(this._props.document.embedContainer, this._props.document);
-    }
+    pinToPres = undoable(() => this._props.pinToPres(this._props.annoDoc, {}), 'pin to pres');
 
-    makeTargetToggle = undoable(() => { this.regionDoc.followLinkToggle = !this.regionDoc.followLinkToggle }, "set link toggle"); // prettier-ignore
+    makeTargetToggle = undoable(() => { this._props.annoDoc.followLinkToggle = !this._props.annoDoc.followLinkToggle }, "set link toggle"); // prettier-ignore
 
-    isTargetToggler = () => BoolCast(this.regionDoc.followLinkToggle);
+    isTargetToggler = () => BoolCast(this._props.annoDoc.followLinkToggle);
 
     showTargetTrail = undoable((anchor: Doc) => {
         const trail = DocCast(anchor.presentationTrail);
@@ -101,12 +86,12 @@ class RegionAnnotation extends ObservableReactComponent<IRegionAnnotationProps>
     @action
     onContextMenu = (e: React.MouseEvent) => {
         AnchorMenu.Instance.Status = 'annotation';
-        AnchorMenu.Instance.Delete = this._props.deleteAnnotation;
+        AnchorMenu.Instance.Delete = this.deleteAnnotation;
         AnchorMenu.Instance.Pinned = false;
-        AnchorMenu.Instance.PinToPres = this._props.pinToPres;
+        AnchorMenu.Instance.PinToPres = this.pinToPres;
         AnchorMenu.Instance.MakeTargetToggle = this.makeTargetToggle;
         AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler;
-        AnchorMenu.Instance.ShowTargetTrail = () => this.showTargetTrail(this.regionDoc);
+        AnchorMenu.Instance.ShowTargetTrail = () => this.showTargetTrail(this._props.annoDoc);
         AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true);
         e.stopPropagation();
         e.preventDefault();
@@ -118,37 +103,43 @@ class RegionAnnotation extends ObservableReactComponent<IRegionAnnotationProps>
             e.preventDefault();
         } else if (e.button === 0) {
             e.stopPropagation();
-            LinkFollower.FollowLink(undefined, this.regionDoc, false);
+            LinkFollower.FollowLink(undefined, this._props.annoDoc, false);
         }
     };
-
+    brushed = () => this._props.annoDoc && Doc.GetBrushHighlightStatus(this._props.annoDoc);
+    opacity = () => (this.brushed() === Doc.DocBrushStatus.highlighted ? 0.5 : 1);
+    outline = () => (this.linkHighlighted ? 'solid 1px lightBlue' : undefined);
+    background = () => (this._props.annoDoc[Highlight] ? 'orange' : StrCast(this._props.annoDoc.backgroundColor));
     render() {
-        const brushed = this.regionDoc && Doc.GetBrushHighlightStatus(this.regionDoc);
         return (
-            <div
-                className="htmlAnnotation"
-                ref={this._mainCont}
-                onPointerEnter={action(() => {
-                    Doc.BrushDoc(this._props.anno);
-                    this._props.showInfo?.(this._props.anno);
-                })}
-                onPointerLeave={action(() => {
-                    Doc.UnBrushDoc(this._props.anno);
-                    this._props.showInfo?.(undefined);
-                })}
-                onPointerDown={this.onPointerDown}
-                onContextMenu={this.onContextMenu}
-                style={{
-                    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: brushed === Doc.DocBrushStatus.highlighted ? 0.5 : undefined,
-                    pointerEvents: this._props.pointerEvents?.() as any,
-                    outline: this._props.linkHighlighted() ? 'solid 1px lightBlue' : undefined,
-                    backgroundColor: this._props.highlighted() ? 'orange' : StrCast(this._props.document.backgroundColor),
-                }}
-            />
+            <div style={{ display: this._props.annoDoc.textCopied && !Doc.GetBrushHighlightStatus(this._props.annoDoc) ? 'none' : undefined }}>
+                {StrListCast(this._props.annoDoc.text_inlineAnnotations)
+                    .map(a => a.split?.(':'))
+                    .filter(fields => fields)
+                    .map(([x, y, width, height]) => (
+                        <div
+                            key={'' + x + y + width + height}
+                            style={{ pointerEvents: this._props.pointerEvents?.() as any }}
+                            onPointerDown={this.onPointerDown}
+                            onContextMenu={this.onContextMenu}
+                            onPointerEnter={() => {
+                                Doc.BrushDoc(this._props.annoDoc);
+                            }}
+                            onPointerLeave={() => {
+                                Doc.UnBrushDoc(this._props.annoDoc);
+                            }}>
+                            <RegionAnnotation //
+                                x={Number(x)}
+                                y={Number(y)}
+                                width={Number(width)}
+                                height={Number(height)}
+                                outline={this.outline}
+                                background={this.background}
+                                opacity={this.opacity}
+                            />
+                        </div>
+                    ))}
+            </div>
         );
     }
 }
-- 
cgit v1.2.3-70-g09d2

