aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/pdf/Annotation.tsx
diff options
context:
space:
mode:
authorSophie Zhang <sophie_zhang@brown.edu>2024-01-25 11:35:26 -0500
committerSophie Zhang <sophie_zhang@brown.edu>2024-01-25 11:35:26 -0500
commitf3dab2a56db5e4a6a3dca58185d94e1ff7d1dc32 (patch)
treea7bc895266b53bb620dbd2dd71bad2e83b555446 /src/client/views/pdf/Annotation.tsx
parentb5c5410b4af5d2c68d2107d3f064f6e3ec4ac3f2 (diff)
parent136f3d9f349d54e8bdd73b6380ea47c19e5edebf (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.tsx86
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),
}}
/>
);