diff options
| author | Sophie Zhang <sophie_zhang@brown.edu> | 2024-01-25 11:35:26 -0500 |
|---|---|---|
| committer | Sophie Zhang <sophie_zhang@brown.edu> | 2024-01-25 11:35:26 -0500 |
| commit | f3dab2a56db5e4a6a3dca58185d94e1ff7d1dc32 (patch) | |
| tree | a7bc895266b53bb620dbd2dd71bad2e83b555446 /src/client/views/pdf/Annotation.tsx | |
| parent | b5c5410b4af5d2c68d2107d3f064f6e3ec4ac3f2 (diff) | |
| parent | 136f3d9f349d54e8bdd73b6380ea47c19e5edebf (diff) | |
Merge branch 'master' into sophie-ai-images
Diffstat (limited to 'src/client/views/pdf/Annotation.tsx')
| -rw-r--r-- | src/client/views/pdf/Annotation.tsx | 86 |
1 files changed, 49 insertions, 37 deletions
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 52904b852..a1f5ce703 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -1,32 +1,37 @@ -import React = require('react'); -import { action, computed } from 'mobx'; +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 { List } from '../../../fields/List'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types'; import { LinkFollower } from '../../util/LinkFollower'; +import { LinkManager } from '../../util/LinkManager'; import { undoBatch } from '../../util/UndoManager'; import { OpenWhere } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { AnchorMenu } from './AnchorMenu'; import './Annotation.scss'; -import { LinkManager } from '../../util/LinkManager'; +import { ObservableReactComponent } from '../ObservableReactComponent'; interface IAnnotationProps extends FieldViewProps { anno: Doc; dataDoc: Doc; fieldKey: string; - showInfo: (anno: Opt<Doc>) => void; + showInfo?: (anno: Opt<Doc>) => void; pointerEvents?: () => Opt<string>; } @observer -export class Annotation extends React.Component<IAnnotationProps> { +export class Annotation extends ObservableReactComponent<IAnnotationProps> { + constructor(props: any) { + super(props); + makeObservable(this); + } render() { return ( - <div style={{ display: this.props.anno.textCopied && !Doc.isBrushedHighlightedDegree(this.props.anno) ? 'none' : undefined }}> - {DocListCast(this.props.anno.text_inlineAnnotations).map(a => ( - <RegionAnnotation pointerEvents={this.props.pointerEvents} {...this.props} document={a} key={a[Id]} /> + <div style={{ display: this._props.anno.textCopied && !Doc.GetBrushHighlightStatus(this._props.anno) ? 'none' : undefined }}> + {DocListCast(this._props.anno.text_inlineAnnotations).map(a => ( + <RegionAnnotation pointerEvents={this._props.pointerEvents} {...this._props} document={a} key={a[Id]} /> ))} </div> ); @@ -38,23 +43,23 @@ interface IRegionAnnotationProps extends IAnnotationProps { pointerEvents?: () => Opt<string>; } @observer -class RegionAnnotation extends React.Component<IRegionAnnotationProps> { +class RegionAnnotation extends ObservableReactComponent<IRegionAnnotationProps> { private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); @computed get annoTextRegion() { - return Cast(this.props.document.annoTextRegion, Doc, null) || this.props.document; + return Cast(this._props.document.annoTextRegion, Doc, null) || this._props.document; } @undoBatch deleteAnnotation = () => { - const docAnnotations = DocListCast(this.props.dataDoc[this.props.fieldKey]); - this.props.dataDoc[this.props.fieldKey] = new List<Doc>(docAnnotations.filter(a => a !== this.annoTextRegion)); + 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); + this._props.select(false); }; @undoBatch - pinToPres = () => this.props.pinToPres(this.annoTextRegion, {}); + pinToPres = () => this._props.pinToPres(this.annoTextRegion, {}); @undoBatch makeTargretToggle = () => (this.annoTextRegion.followLinkToggle = !this.annoTextRegion.followLinkToggle); @@ -65,22 +70,28 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> { const trail = DocCast(anchor.presentationTrail); if (trail) { Doc.ActivePresentation = trail; - this.props.addDocTab(trail, OpenWhere.replaceRight); + this._props.addDocTab(trail, OpenWhere.replaceRight); } }; @action + onContextMenu = (e: React.MouseEvent) => { + AnchorMenu.Instance.Status = 'annotation'; + AnchorMenu.Instance.Delete = this.deleteAnnotation.bind(this); + AnchorMenu.Instance.Pinned = false; + AnchorMenu.Instance.PinToPres = this.pinToPres; + AnchorMenu.Instance.MakeTargetToggle = this.makeTargretToggle; + AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler; + AnchorMenu.Instance.ShowTargetTrail = () => this.showTargetTrail(this.annoTextRegion); + AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true); + e.stopPropagation(); + e.preventDefault(); + }; + @action onPointerDown = (e: React.PointerEvent) => { if (e.button === 2 || e.ctrlKey) { - AnchorMenu.Instance.Status = 'annotation'; - AnchorMenu.Instance.Delete = this.deleteAnnotation.bind(this); - AnchorMenu.Instance.Pinned = false; - AnchorMenu.Instance.PinToPres = this.pinToPres; - AnchorMenu.Instance.MakeTargetToggle = this.makeTargretToggle; - AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler; - AnchorMenu.Instance.ShowTargetTrail = () => this.showTargetTrail(this.annoTextRegion); - AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true); e.stopPropagation(); + e.preventDefault(); } else if (e.button === 0) { e.stopPropagation(); LinkFollower.FollowLink(undefined, this.annoTextRegion, false); @@ -88,36 +99,37 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> { }; @computed get linkHighlighted() { - for (const link of LinkManager.Instance.getAllDirectLinks(this.props.document)) { - const a1 = LinkManager.getOppositeAnchor(link, this.props.document); - if (a1 && Doc.IsBrushedDegreeUnmemoized(DocCast(a1.annotationOn, this.props.document))) return true; + for (const link of LinkManager.Instance.getAllDirectLinks(this._props.document)) { + const a1 = LinkManager.getOppositeAnchor(link, this._props.document); + if (a1 && Doc.GetBrushStatus(DocCast(a1.annotationOn, this._props.document))) return true; } } render() { - const brushed = this.annoTextRegion && Doc.isBrushedHighlightedDegree(this.annoTextRegion); + const brushed = this.annoTextRegion && Doc.GetBrushHighlightStatus(this.annoTextRegion); return ( <div className="htmlAnnotation" ref={this._mainCont} onPointerEnter={action(() => { - Doc.BrushDoc(this.props.anno); - this.props.showInfo(this.props.anno); + Doc.BrushDoc(this._props.anno); + this._props.showInfo?.(this._props.anno); })} onPointerLeave={action(() => { - Doc.UnBrushDoc(this.props.anno); - this.props.showInfo(undefined); + 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), + 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, + pointerEvents: this._props.pointerEvents?.() as any, outline: brushed === Doc.DocBrushStatus.unbrushed && this.linkHighlighted ? 'solid 1px lightBlue' : undefined, - backgroundColor: brushed === Doc.DocBrushStatus.highlighted ? 'orange' : StrCast(this.props.document.backgroundColor), + backgroundColor: brushed === Doc.DocBrushStatus.highlighted ? 'orange' : StrCast(this._props.document.backgroundColor), }} /> ); |
