From 68785a97178d229935c0429791081d7c09312dc3 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 20 Jan 2021 18:35:58 -0500 Subject: moved PDFMenu to AnchorMenu. added AnchorMenu to formattedTextBox. Fixed following links from text box huyperlinks when there are multiple different huypertext links on the document. --- src/client/views/pdf/AnchorMenu.scss | 25 ++++++ src/client/views/pdf/AnchorMenu.tsx | 157 +++++++++++++++++++++++++++++++++++ src/client/views/pdf/Annotation.tsx | 20 ++--- src/client/views/pdf/PDFMenu.scss | 25 ------ src/client/views/pdf/PDFMenu.tsx | 157 ----------------------------------- src/client/views/pdf/PDFViewer.tsx | 18 ++-- 6 files changed, 202 insertions(+), 200 deletions(-) create mode 100644 src/client/views/pdf/AnchorMenu.scss create mode 100644 src/client/views/pdf/AnchorMenu.tsx delete mode 100644 src/client/views/pdf/PDFMenu.scss delete mode 100644 src/client/views/pdf/PDFMenu.tsx (limited to 'src/client/views/pdf') diff --git a/src/client/views/pdf/AnchorMenu.scss b/src/client/views/pdf/AnchorMenu.scss new file mode 100644 index 000000000..b7afb26a5 --- /dev/null +++ b/src/client/views/pdf/AnchorMenu.scss @@ -0,0 +1,25 @@ +.anchorMenu-addTag { + display: grid; + width: 200px; + padding: 5px; + grid-template-columns: 90px 20px 90px; +} + +.color-wrapper { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + + button.color-button { + width: 20px; + height: 20px; + border-radius: 15px !important; + margin: 3px; + border: 2px solid transparent !important; + padding: 3px; + + &.active { + border: 2px solid white; + } + } +} \ No newline at end of file diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx new file mode 100644 index 000000000..e2bd5a73d --- /dev/null +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -0,0 +1,157 @@ +import React = require("react"); +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Tooltip } from "@material-ui/core"; +import { action, computed, observable } from "mobx"; +import { observer } from "mobx-react"; +import { ColorState } from "react-color"; +import { Doc, Opt } from "../../../fields/Doc"; +import { returnFalse, setupMoveUpEvents, unimplementedFunction, Utils } from "../../../Utils"; +import { AntimodeMenu, AntimodeMenuProps } from "../AntimodeMenu"; +import { ButtonDropdown } from "../nodes/formattedText/RichTextMenu"; +import "./AnchorMenu.scss"; + +@observer +export class AnchorMenu extends AntimodeMenu { + static Instance: AnchorMenu; + + private _commentCont = React.createRef(); + private _palette = [ + "rgba(208, 2, 27, 0.8)", + "rgba(238, 0, 0, 0.8)", + "rgba(245, 166, 35, 0.8)", + "rgba(248, 231, 28, 0.8)", + "rgba(245, 230, 95, 0.616)", + "rgba(139, 87, 42, 0.8)", + "rgba(126, 211, 33, 0.8)", + "rgba(65, 117, 5, 0.8)", + "rgba(144, 19, 254, 0.8)", + "rgba(238, 169, 184, 0.8)", + "rgba(224, 187, 228, 0.8)", + "rgba(225, 223, 211, 0.8)", + "rgba(255, 255, 255, 0.8)", + "rgba(155, 155, 155, 0.8)", + "rgba(0, 0, 0, 0.8)"]; + + @observable private _keyValue: string = ""; + @observable private _valueValue: string = ""; + @observable private _added: boolean = false; + @observable private highlightColor: string = "rgba(245, 230, 95, 0.616)"; + + @observable public _colorBtn = false; + @observable public Highlighting: boolean = false; + @observable public Status: "marquee" | "annotation" | "" = ""; + + public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction; + public Highlight: (color: string) => Opt = (color: string) => undefined; + public Delete: () => void = unimplementedFunction; + public AddTag: (key: string, value: string) => boolean = returnFalse; + public PinToPres: () => void = unimplementedFunction; + public MakePushpin: () => void = unimplementedFunction; + public IsPushpin: () => boolean = returnFalse; + public Marquee: { left: number; top: number; width: number; height: number; } | undefined; + public get Active() { return this._left > 0; } + + constructor(props: Readonly<{}>) { + super(props); + + AnchorMenu.Instance = this; + AnchorMenu.Instance._canFade = false; + } + + pointerDown = (e: React.PointerEvent) => { + setupMoveUpEvents(this, e, (e: PointerEvent) => { + this.StartDrag(e, this._commentCont.current!); + return true; + }, returnFalse, returnFalse); + } + + @action + highlightClicked = (e: React.MouseEvent) => { + if (!this.Highlight(this.highlightColor) && this.Pinned) { + this.Highlighting = !this.Highlighting; + } + } + + @computed get highlighter() { + const button = + ; + + const dropdownContent = +
+

Change highlighter color:

+
+ {this._palette.map(color => { + if (color) { + return this.highlightColor === color ? + : + ; + } + })} +
+
; + return ( + {"Click to Highlight"}}> + + + ); + } + + @action changeHighlightColor = (color: string, e: React.PointerEvent) => { + const col: ColorState = { + hex: color, hsl: { a: 0, h: 0, s: 0, l: 0, source: "" }, hsv: { a: 0, h: 0, s: 0, v: 0, source: "" }, + rgb: { a: 0, r: 0, b: 0, g: 0, source: "" }, oldHue: 0, source: "", + }; + e.preventDefault(); + e.stopPropagation(); + this.highlightColor = Utils.colorString(col); + } + + @action keyChanged = (e: React.ChangeEvent) => { this._keyValue = e.currentTarget.value; }; + @action valueChanged = (e: React.ChangeEvent) => { this._valueValue = e.currentTarget.value; }; + @action addTag = (e: React.PointerEvent) => { + if (this._keyValue.length > 0 && this._valueValue.length > 0) { + this._added = this.AddTag(this._keyValue, this._valueValue); + setTimeout(action(() => this._added = false), 1000); + } + } + + render() { + const buttons = this.Status === "marquee" ? + [ + this.highlighter, + + {"Drag to Place Annotation"}}> + + , + ] : [ + {"Remove Link Anchor"}}> + + , + {"Pin to Presentation"}}> + + , + {"toggle pushpin behavior"}}> + + , + //
+ // + // + //
, + // , + ]; + + return this.getElement(buttons); + } +} \ No newline at end of file diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 5ef57f986..85dd65901 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -8,7 +8,7 @@ import { BoolCast, Cast, FieldValue, NumCast, PromiseValue, StrCast } from "../. import { LinkManager } from "../../util/LinkManager"; import { undoBatch } from "../../util/UndoManager"; import "./Annotation.scss"; -import { PDFMenu } from "./PDFMenu"; +import { AnchorMenu } from "./AnchorMenu"; interface IAnnotationProps { anno: Doc; @@ -84,7 +84,7 @@ class RegionAnnotation extends React.Component { DocListCast(group.annotations).forEach(anno => anno.delete = true); } - PDFMenu.Instance.fadeOut(true); + AnchorMenu.Instance.fadeOut(true); } @undoBatch @@ -105,14 +105,14 @@ class RegionAnnotation extends React.Component { @action onPointerDown = (e: React.PointerEvent) => { if (e.button === 2 || e.ctrlKey) { - PDFMenu.Instance.Status = "annotation"; - PDFMenu.Instance.Delete = this.deleteAnnotation.bind(this); - PDFMenu.Instance.Pinned = false; - PDFMenu.Instance.AddTag = this.addTag.bind(this); - PDFMenu.Instance.PinToPres = this.pinToPres; - PDFMenu.Instance.MakePushpin = this.makePushpin; - PDFMenu.Instance.IsPushpin = this.isPushpin; - PDFMenu.Instance.jumpTo(e.clientX, e.clientY, true); + AnchorMenu.Instance.Status = "annotation"; + AnchorMenu.Instance.Delete = this.deleteAnnotation.bind(this); + AnchorMenu.Instance.Pinned = false; + AnchorMenu.Instance.AddTag = this.addTag.bind(this); + AnchorMenu.Instance.PinToPres = this.pinToPres; + AnchorMenu.Instance.MakePushpin = this.makePushpin; + AnchorMenu.Instance.IsPushpin = this.isPushpin; + AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true); e.stopPropagation(); } else if (e.button === 0) { diff --git a/src/client/views/pdf/PDFMenu.scss b/src/client/views/pdf/PDFMenu.scss deleted file mode 100644 index fa43a99b2..000000000 --- a/src/client/views/pdf/PDFMenu.scss +++ /dev/null @@ -1,25 +0,0 @@ -.pdfMenu-addTag { - display: grid; - width: 200px; - padding: 5px; - grid-template-columns: 90px 20px 90px; -} - -.color-wrapper { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - - button.color-button { - width: 20px; - height: 20px; - border-radius: 15px !important; - margin: 3px; - border: 2px solid transparent !important; - padding: 3px; - - &.active { - border: 2px solid white; - } - } -} \ No newline at end of file diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx deleted file mode 100644 index 603e26021..000000000 --- a/src/client/views/pdf/PDFMenu.tsx +++ /dev/null @@ -1,157 +0,0 @@ -import React = require("react"); -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Tooltip } from "@material-ui/core"; -import { action, computed, observable } from "mobx"; -import { observer } from "mobx-react"; -import { ColorState } from "react-color"; -import { Doc, Opt } from "../../../fields/Doc"; -import { returnFalse, setupMoveUpEvents, unimplementedFunction, Utils } from "../../../Utils"; -import { AntimodeMenu, AntimodeMenuProps } from "../AntimodeMenu"; -import { ButtonDropdown } from "../nodes/formattedText/RichTextMenu"; -import "./PDFMenu.scss"; - -@observer -export class PDFMenu extends AntimodeMenu { - static Instance: PDFMenu; - - private _commentCont = React.createRef(); - private _palette = [ - "rgba(208, 2, 27, 0.8)", - "rgba(238, 0, 0, 0.8)", - "rgba(245, 166, 35, 0.8)", - "rgba(248, 231, 28, 0.8)", - "rgba(245, 230, 95, 0.616)", - "rgba(139, 87, 42, 0.8)", - "rgba(126, 211, 33, 0.8)", - "rgba(65, 117, 5, 0.8)", - "rgba(144, 19, 254, 0.8)", - "rgba(238, 169, 184, 0.8)", - "rgba(224, 187, 228, 0.8)", - "rgba(225, 223, 211, 0.8)", - "rgba(255, 255, 255, 0.8)", - "rgba(155, 155, 155, 0.8)", - "rgba(0, 0, 0, 0.8)"]; - - @observable private _keyValue: string = ""; - @observable private _valueValue: string = ""; - @observable private _added: boolean = false; - @observable private highlightColor: string = "rgba(245, 230, 95, 0.616)"; - - @observable public _colorBtn = false; - @observable public Highlighting: boolean = false; - @observable public Status: "marquee" | "annotation" | "" = ""; - - public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction; - public Highlight: (color: string) => Opt = (color: string) => undefined; - public Delete: () => void = unimplementedFunction; - public AddTag: (key: string, value: string) => boolean = returnFalse; - public PinToPres: () => void = unimplementedFunction; - public MakePushpin: () => void = unimplementedFunction; - public IsPushpin: () => boolean = returnFalse; - public Marquee: { left: number; top: number; width: number; height: number; } | undefined; - public get Active() { return this._left > 0; } - - constructor(props: Readonly<{}>) { - super(props); - - PDFMenu.Instance = this; - PDFMenu.Instance._canFade = false; - } - - pointerDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, (e: PointerEvent) => { - this.StartDrag(e, this._commentCont.current!); - return true; - }, returnFalse, returnFalse); - } - - @action - highlightClicked = (e: React.MouseEvent) => { - if (!this.Highlight(this.highlightColor) && this.Pinned) { - this.Highlighting = !this.Highlighting; - } - } - - @computed get highlighter() { - const button = - ; - - const dropdownContent = -
-

Change highlighter color:

-
- {this._palette.map(color => { - if (color) { - return this.highlightColor === color ? - : - ; - } - })} -
-
; - return ( - {"Click to Highlight"}}> - - - ); - } - - @action changeHighlightColor = (color: string, e: React.PointerEvent) => { - const col: ColorState = { - hex: color, hsl: { a: 0, h: 0, s: 0, l: 0, source: "" }, hsv: { a: 0, h: 0, s: 0, v: 0, source: "" }, - rgb: { a: 0, r: 0, b: 0, g: 0, source: "" }, oldHue: 0, source: "", - }; - e.preventDefault(); - e.stopPropagation(); - this.highlightColor = Utils.colorString(col); - } - - @action keyChanged = (e: React.ChangeEvent) => { this._keyValue = e.currentTarget.value; }; - @action valueChanged = (e: React.ChangeEvent) => { this._valueValue = e.currentTarget.value; }; - @action addTag = (e: React.PointerEvent) => { - if (this._keyValue.length > 0 && this._valueValue.length > 0) { - this._added = this.AddTag(this._keyValue, this._valueValue); - setTimeout(action(() => this._added = false), 1000); - } - } - - render() { - const buttons = this.Status === "marquee" ? - [ - this.highlighter, - - {"Drag to Place Annotation"}}> - - , - ] : [ - {"Remove Link Anchor"}}> - - , - {"Pin to Presentation"}}> - - , - {"toggle pushpin behavior"}}> - - , - //
- // - // - //
, - // , - ]; - - return this.getElement(buttons); - } -} \ No newline at end of file diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index f9139220b..f2052d454 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -26,7 +26,7 @@ import { FieldViewProps } from "../nodes/FieldView"; import { FormattedTextBoxComment } from "../nodes/formattedText/FormattedTextBoxComment"; import { LinkDocPreview } from "../nodes/LinkDocPreview"; import { Annotation } from "./Annotation"; -import { PDFMenu } from "./PDFMenu"; +import { AnchorMenu } from "./AnchorMenu"; import "./PDFViewer.scss"; const pdfjs = require('pdfjs-dist/es5/build/pdf.js'); import React = require("react"); @@ -137,7 +137,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent v.forEach(a => a.remove())); this._savedAnnotations.keys().forEach(k => this._savedAnnotations.setValue(k, [])); - PDFMenu.Instance.fadeOut(true); + AnchorMenu.Instance.fadeOut(true); } (SelectionManager.Views().length === 1) && this.setupPdfJsViewer(); }, @@ -384,30 +384,32 @@ export class PDFViewer extends ViewBoxAnnotatableComponent v.forEach(a => a.remove())); this._savedAnnotations.clear(); this._styleRule = addStyleSheetRule(PDFViewer._annotationStyle, "pdfAnnotation", { "pointer-events": "none" }); - document.addEventListener("pointermove", this.onSelectMove); document.addEventListener("pointerup", this.onSelectEnd); } + document.addEventListener("pointermove", this.onSelectMove); } } @action finishMarquee = () => { this._marqueeing = undefined; + document.removeEventListener("pointermove", this.onSelectMove); this.props.select(false); } @action onSelectMove = (e: PointerEvent): void => { - if (e.target && (e.target as any).parentElement === this._mainCont.current) e.stopPropagation(); + // if (e.target && (e.target as any).parentElement === this._mainCont.current) + e.stopPropagation(); } @action @@ -421,7 +423,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent