aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/pdf/Annotation.tsx
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-04-25 17:15:20 -0400
committerbobzel <zzzman@gmail.com>2024-04-25 17:15:20 -0400
commitd6720fa48d78cc313d6418acd8cbdaeda965285c (patch)
treed9cec7f7b031b20bfc5423bc48f8791074b2d5c1 /src/client/views/pdf/Annotation.tsx
parentbd3b34cce2ad85bfc96c16304b532d1510fd359e (diff)
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
Diffstat (limited to 'src/client/views/pdf/Annotation.tsx')
-rw-r--r--src/client/views/pdf/Annotation.tsx157
1 files changed, 74 insertions, 83 deletions
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>
);
}
}