diff options
Diffstat (limited to 'src/client/views')
| -rw-r--r-- | src/client/views/pdf/PDFMenu.tsx | 55 | ||||
| -rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 77 | ||||
| -rw-r--r-- | src/client/views/pdf/Page.tsx | 1 | 
3 files changed, 108 insertions, 25 deletions
| diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx index 2462a5f94..39b15fb11 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -15,13 +15,16 @@ export default class PDFMenu extends React.Component {      @observable private _opacity: number = 1;      @observable private _transition: string = "opacity 0.5s";      @observable private _transitionDelay: string = ""; -    @observable private _pinned: boolean = false; + +    @observable public Pinned: boolean = false;      StartDrag: (e: PointerEvent) => void = emptyFunction;      Highlight: (d: Doc | undefined, color: string | undefined) => void = emptyFunction; -    @observable Highlighting: boolean = false; +    Delete: () => void = emptyFunction; + +    @observable public Highlighting: boolean = false; +    @observable public Status: "pdf" | "annotation" | "" = ""; -    private _timeout: NodeJS.Timeout | undefined;      private _offsetY: number = 0;      private _offsetX: number = 0;      private _mainCont: React.RefObject<HTMLDivElement>; @@ -66,8 +69,8 @@ export default class PDFMenu extends React.Component {      }      @action -    jumpTo = (x: number, y: number) => { -        if (!this._pinned) { +    jumpTo = (x: number, y: number, forceJump: boolean = false) => { +        if (!this.Pinned || forceJump) {              this._transition = this._transitionDelay = "";              this._opacity = 1;              this._left = x; @@ -77,7 +80,7 @@ export default class PDFMenu extends React.Component {      @action      fadeOut = (forceOut: boolean) => { -        if (!this._pinned) { +        if (!this.Pinned) {              if (this._opacity === 0.2) {                  this._transition = "opacity 0.1s";                  this._transitionDelay = ""; @@ -96,7 +99,7 @@ export default class PDFMenu extends React.Component {      @action      pointerLeave = (e: React.PointerEvent) => { -        if (!this._pinned) { +        if (!this.Pinned) {              this._transition = "opacity 0.5s";              this._transitionDelay = "1s";              this._opacity = 0.2; @@ -113,8 +116,8 @@ export default class PDFMenu extends React.Component {      @action      togglePin = (e: React.MouseEvent) => { -        this._pinned = !this._pinned; -        if (!this._pinned) { +        this.Pinned = !this.Pinned; +        if (!this.Pinned) {              this.Highlighting = false;          }      } @@ -150,7 +153,7 @@ export default class PDFMenu extends React.Component {      @action      highlightClicked = (e: React.MouseEvent) => { -        if (!this._pinned) { +        if (!this.Pinned) {              this.Highlight(undefined, "#f4f442");          }          else { @@ -159,11 +162,35 @@ export default class PDFMenu extends React.Component {          }      } +    deleteClicked = (e: React.PointerEvent) => { +        this.Delete(); +    } + +    handleContextMenu = (e: React.MouseEvent) => { +        e.stopPropagation(); +        e.preventDefault(); +    } +      render() { +        let buttons = this.Status === "pdf" ? [ +            <button className="pdfMenu-button" title="Click to Highlight" onClick={this.highlightClicked} +                style={this.Highlighting ? { backgroundColor: "#121212" } : {}}> +                <FontAwesomeIcon icon="highlighter" size="lg" style={{ transition: "transform 0.1s", transform: this.Highlighting ? "" : "rotate(-45deg)" }} /> +            </button>, +            <button className="pdfMenu-button" title="Drag to Annotate" onPointerDown={this.pointerDown}><FontAwesomeIcon icon="comment-alt" size="lg" /></button>, +            <button className="pdfMenu-button" title="Pin Menu" onClick={this.togglePin} +                style={this.Pinned ? { backgroundColor: "#121212" } : {}}> +                <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transition: "transform 0.1s", transform: this.Pinned ? "rotate(45deg)" : "" }} /> +            </button> +        ] : [ +                <button className="pdfMenu-button" title="Delete Anchor" onPointerDown={this.deleteClicked}><FontAwesomeIcon icon="trash-alt" size="lg" /></button> +            ]; +          return ( -            <div className="pdfMenu-cont" onPointerLeave={this.pointerLeave} onPointerEnter={this.pointerEntered} ref={this._mainCont} +            <div className="pdfMenu-cont" onPointerLeave={this.pointerLeave} onPointerEnter={this.pointerEntered} ref={this._mainCont} onContextMenu={this.handleContextMenu}                  style={{ left: this._left, top: this._top, opacity: this._opacity, transition: this._transition, transitionDelay: this._transitionDelay }}> -                <button className="pdfMenu-button" title="Highlight" onClick={this.highlightClicked} +                {buttons} +                {/* <button className="pdfMenu-button" title="Highlight" onClick={this.highlightClicked}                      style={this.Highlighting ? { backgroundColor: "#121212" } : {}}>                      <FontAwesomeIcon icon="highlighter" size="lg" style={{ transition: "transform 0.1s", transform: this.Highlighting ? "" : "rotate(-45deg)" }} />                  </button> @@ -171,8 +198,8 @@ export default class PDFMenu extends React.Component {                  <button className="pdfMenu-button" title="Pin Menu" onClick={this.togglePin}                      style={this._pinned ? { backgroundColor: "#121212" } : {}}>                      <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transition: "transform 0.1s", transform: this._pinned ? "rotate(45deg)" : "" }} /> -                </button> -                <div className="pdfMenu-dragger" onPointerDown={this.dragStart} style={{ width: this._pinned ? "20px" : "0px" }} /> +                </button> */} +                <div className="pdfMenu-dragger" onPointerDown={this.dragStart} style={{ width: this.Pinned ? "20px" : "0px" }} />              </div >          );      } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index f0e55705d..7000352e7 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -7,7 +7,7 @@ import { Dictionary } from "typescript-collections";  import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc";  import { Id } from "../../../new_fields/FieldSymbols";  import { List } from "../../../new_fields/List"; -import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { BoolCast, Cast, NumCast, StrCast, FieldValue } from "../../../new_fields/Types";  import { emptyFunction } from "../../../Utils";  import { DocServer } from "../../DocServer";  import { Docs, DocUtils } from "../../documents/Documents"; @@ -138,6 +138,7 @@ class Viewer extends React.Component<IViewerProps> {      makeAnnotationDocument = (sourceDoc: Doc | undefined, s: number, color: string): Doc => {          let annoDocs: Doc[] = []; +        let mainAnnoDoc = new Doc();          this._savedAnnotations.forEach((key: number, value: HTMLDivElement[]) => {              for (let anno of value) {                  let annoDoc = new Doc(); @@ -147,6 +148,7 @@ class Viewer extends React.Component<IViewerProps> {                  if (anno.style.width) annoDoc.width = parseInt(anno.style.width) / scale;                  annoDoc.page = key;                  annoDoc.target = sourceDoc; +                annoDoc.group = mainAnnoDoc;                  annoDoc.color = color;                  annoDoc.type = AnnotationTypes.Region;                  annoDocs.push(annoDoc); @@ -154,13 +156,12 @@ class Viewer extends React.Component<IViewerProps> {              }          }); -        let annoDoc = new Doc(); -        annoDoc.annotations = new List<Doc>(annoDocs); +        mainAnnoDoc.annotations = new List<Doc>(annoDocs);          if (sourceDoc) { -            DocUtils.MakeLink(sourceDoc, annoDoc, undefined, `Annotation from ${StrCast(this.props.parent.Document.title)}`, "", StrCast(this.props.parent.Document.title)); +            DocUtils.MakeLink(sourceDoc, mainAnnoDoc, undefined, `Annotation from ${StrCast(this.props.parent.Document.title)}`, "", StrCast(this.props.parent.Document.title));          }          this._savedAnnotations.clear(); -        return annoDoc; +        return mainAnnoDoc;      }      drop = async (e: Event, de: DragManager.DropEvent) => { @@ -508,6 +509,59 @@ interface IAnnotationProps {  class RegionAnnotation extends React.Component<IAnnotationProps> {      @observable private _backgroundColor: string = "red"; +    private _reactionDisposer?: IReactionDisposer; +    private _mainCont: React.RefObject<HTMLDivElement>; + +    constructor(props: IAnnotationProps) { +        super(props); + +        this._mainCont = React.createRef(); +    } + +    componentDidMount() { +        this._reactionDisposer = reaction( +            () => BoolCast(this.props.document.delete), +            () => { +                if (BoolCast(this.props.document.delete)) { +                    if (this._mainCont.current) { +                        this._mainCont.current.style.display = "none"; +                    } +                } +            }, +            { fireImmediately: true } +        ); +    } + +    componentWillUnmount() { +        this._reactionDisposer && this._reactionDisposer(); +    } + +    deleteAnnotation = () => { +        let annotation = DocListCast(this.props.parent.props.parent.Document.annotations); +        let group = FieldValue(Cast(this.props.document.group, Doc)); +        if (group && annotation.indexOf(group) !== -1) { +            let newAnnotations = annotation.filter(a => a !== FieldValue(Cast(this.props.document.group, Doc))); +            this.props.parent.props.parent.Document.annotations = new List<Doc>(newAnnotations); +        } + +        if (group) { +            let groupAnnotations = DocListCast(group.annotations); +            groupAnnotations.forEach(anno => anno.delete = true); +        } + +        PDFMenu.Instance.fadeOut(true); +    } + + +    // annotateThis = (e: PointerEvent) => { +    //     e.preventDefault(); +    //     e.stopPropagation(); +    //     // document that this annotation is linked to +    //     let targetDoc = Docs.TextDocument({ width: 200, height: 200, title: "New Annotation" }); +    //     let group = FieldValue(Cast(this.props.document.group, Doc)); +    // } + +    @action      onPointerDown = (e: React.PointerEvent) => {          if (e.button === 0) {              let targetDoc = Cast(this.props.document.target, Doc, null); @@ -515,16 +569,17 @@ class RegionAnnotation extends React.Component<IAnnotationProps> {                  DocumentManager.Instance.jumpToDocument(targetDoc);              }          } -        // if (e.button === 2) { -        //     console.log("right"); -        //     e.stopPropagation(); -        //     e.preventDefault(); -        // } +        if (e.button === 2) { +            PDFMenu.Instance.Status = "annotation"; +            PDFMenu.Instance.Delete = this.deleteAnnotation; +            PDFMenu.Instance.Pinned = false; +            PDFMenu.Instance.jumpTo(e.clientX, e.clientY, true); +        }      }      render() {          return ( -            <div className="pdfViewer-annotationBox" onPointerDown={this.onPointerDown} +            <div className="pdfViewer-annotationBox" onPointerDown={this.onPointerDown} ref={this._mainCont}                  style={{ top: this.props.y * scale, left: this.props.x * scale, width: this.props.width * scale, height: this.props.height * scale, pointerEvents: "all", backgroundColor: StrCast(this.props.document.color) }}></div>          );      } diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx index 39e737c32..734dff7fc 100644 --- a/src/client/views/pdf/Page.tsx +++ b/src/client/views/pdf/Page.tsx @@ -191,6 +191,7 @@ export default class Page extends React.Component<IPageProps> {          else if (e.button === 0) {              PDFMenu.Instance.StartDrag = this.startDrag;              PDFMenu.Instance.Highlight = this.highlight; +            PDFMenu.Instance.Status = "pdf";              PDFMenu.Instance.fadeOut(true);              let target: any = e.target;              if (target && target.parentElement === this._textLayer.current) { | 
