diff options
author | bobzel <zzzman@gmail.com> | 2024-04-25 17:15:20 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2024-04-25 17:15:20 -0400 |
commit | d6720fa48d78cc313d6418acd8cbdaeda965285c (patch) | |
tree | d9cec7f7b031b20bfc5423bc48f8791074b2d5c1 /src/client/views/pdf/Annotation.tsx | |
parent | bd3b34cce2ad85bfc96c16304b532d1510fd359e (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.tsx | 157 |
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> ); } } |