aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/MainView.tsx3
-rw-r--r--src/client/views/nodes/PDFBox.tsx20
-rw-r--r--src/client/views/pdf/PDFMenu.tsx45
-rw-r--r--src/client/views/pdf/PDFViewer.tsx6
-rw-r--r--src/client/views/pdf/Page.tsx31
5 files changed, 89 insertions, 16 deletions
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index e3d4ff8b5..2645e2789 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,5 +1,5 @@
import { IconName, library } from '@fortawesome/fontawesome-svg-core';
-import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faThumbtack, faRedoAlt, faTable, faTree, faUndoAlt, faBell, faCommentAlt } from '@fortawesome/free-solid-svg-icons';
+import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faThumbtack, faRedoAlt, faTable, faTree, faUndoAlt, faBell, faCommentAlt, faCut } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, configure, observable, runInAction, trace } from 'mobx';
import { observer } from 'mobx-react';
@@ -91,6 +91,7 @@ export class MainView extends React.Component {
library.add(faFilm);
library.add(faMusic);
library.add(faTree);
+ library.add(faCut);
library.add(faCommentAlt);
library.add(faThumbtack);
this.initEventListeners();
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index d2de1cb1c..0aeb9afc8 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -27,8 +27,22 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
@observable private _alt = false;
@observable private _scrollY: number = 0;
+ private _mainCont: React.RefObject<HTMLDivElement>;
private _reactionDisposer?: IReactionDisposer;
+ constructor(props: FieldViewProps) {
+ super(props);
+
+ this._mainCont = React.createRef();
+ this._reactionDisposer = reaction(
+ () => this.props.Document.scrollY,
+ () => {
+ if (this._mainCont.current) {
+ this._mainCont.current && this._mainCont.current.scrollTo({ top: NumCast(this.Document.scrollY), behavior: "smooth" });
+ }
+ });
+ }
+
componentDidMount() {
if (this.props.setPdfBox) this.props.setPdfBox(this);
}
@@ -60,10 +74,6 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
}
createRef = (ele: HTMLDivElement | null) => {
- if (this._reactionDisposer) this._reactionDisposer();
- this._reactionDisposer = reaction(() => this.props.Document.scrollY, () => {
- ele && ele.scrollTo({ top: NumCast(this.Document.scrollY), behavior: "auto" });
- });
}
loaded = (nw: number, nh: number, np: number) => {
@@ -105,7 +115,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
overflowY: "scroll", overflowX: "hidden",
marginTop: `${NumCast(this.props.ContainingCollectionView!.props.Document.panY)}px`
}}
- ref={this.createRef}
+ ref={this._mainCont}
onWheel={(e: React.WheelEvent) => {
e.stopPropagation();
}} className={classname}>
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index 39b15fb11..a8e176858 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -5,6 +5,8 @@ import { observer } from "mobx-react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { emptyFunction } from "../../../Utils";
import { Doc } from "../../../new_fields/Doc";
+import { DragManager } from "../../util/DragManager";
+import { DocUtils } from "../../documents/Documents";
@observer
export default class PDFMenu extends React.Component {
@@ -16,19 +18,23 @@ export default class PDFMenu extends React.Component {
@observable private _transition: string = "opacity 0.5s";
@observable private _transitionDelay: string = "";
- @observable public Pinned: boolean = false;
StartDrag: (e: PointerEvent) => void = emptyFunction;
Highlight: (d: Doc | undefined, color: string | undefined) => void = emptyFunction;
Delete: () => void = emptyFunction;
+ Snippet: (marquee: { left: number, top: number, width: number, height: number }) => void = emptyFunction;
@observable public Highlighting: boolean = false;
- @observable public Status: "pdf" | "annotation" | "" = "";
+ @observable public Status: "pdf" | "annotation" | "snippet" | "" = "";
+ @observable public Pinned: boolean = false;
+
+ public Marquee: { left: number; top: number; width: number; height: number; } | undefined;
private _offsetY: number = 0;
private _offsetX: number = 0;
private _mainCont: React.RefObject<HTMLDivElement>;
private _dragging: boolean = false;
+ private _snippetButton: React.RefObject<HTMLButtonElement>;
constructor(props: Readonly<{}>) {
super(props);
@@ -36,6 +42,7 @@ export default class PDFMenu extends React.Component {
PDFMenu.Instance = this;
this._mainCont = React.createRef();
+ this._snippetButton = React.createRef();
}
pointerDown = (e: React.PointerEvent) => {
@@ -171,13 +178,45 @@ export default class PDFMenu extends React.Component {
e.preventDefault();
}
+ snippetStart = (e: React.PointerEvent) => {
+ document.removeEventListener("pointermove", this.snippetDrag);
+ document.addEventListener("pointermove", this.snippetDrag);
+ document.removeEventListener("pointerup", this.snippetEnd);
+ document.addEventListener("pointerup", this.snippetEnd);
+
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+ snippetDrag = (e: PointerEvent) => {
+ e.stopPropagation();
+ e.preventDefault();
+ if (this._dragging) {
+ return;
+ }
+ this._dragging = true;
+
+ if (this.Marquee) {
+ this.Snippet(this.Marquee);
+ }
+ }
+
+ snippetEnd = (e: PointerEvent) => {
+ this._dragging = false;
+ document.removeEventListener("pointermove", this.snippetDrag);
+ document.removeEventListener("pointerup", this.snippetEnd);
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
render() {
- let buttons = this.Status === "pdf" ? [
+ let buttons = this.Status === "pdf" || this.Status === "snippet" ? [
<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>,
+ this.Status === "snippet" ? <button className="pdfMenu-button" title="Drag to Snippetize Selection" onPointerDown={this.snippetStart} ref={this._snippetButton}><FontAwesomeIcon icon="cut" size="lg" /></button> : undefined,
<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)" : "" }} />
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 7000352e7..015d8f878 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -125,6 +125,10 @@ class Viewer extends React.Component<IViewerProps> {
runInAction(() =>
Array.from(Array((this._pageSizes = pageSizes).length).keys()).map(this.getPlaceholderPage));
this.props.loaded(Math.max(...pageSizes.map(i => i.width)), pageSizes[0].height, this.props.pdf.numPages);
+
+ let startY = NumCast(this.props.parent.Document.startY);
+ this.props.parent.Document.scrollY = startY;
+ console.log(startY);
// this.props.loaded(Math.max(...pageSizes.map(i => i.width)), pageSizes[0].height, this.props.pdf.numPages);
}
}
@@ -215,7 +219,7 @@ class Viewer extends React.Component<IViewerProps> {
createAnnotation={this.createAnnotation}
sendAnnotations={this.receiveAnnotations}
makeAnnotationDocuments={this.makeAnnotationDocument}
- receiveAnnotations={this.sendAnnotations}
+ getScrollFromPage={this.getScrollFromPage}
{...this.props} />
);
}
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index 734dff7fc..984d38681 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -16,6 +16,7 @@ import { menuBar } from "prosemirror-menu";
import { AnnotationTypes, PDFViewer, scale } from "./PDFViewer";
import PDFMenu from "./PDFMenu";
import { UndoManager } from "../../util/UndoManager";
+import { copy } from "typescript-collections/dist/lib/arrays";
interface IPageProps {
@@ -28,9 +29,9 @@ interface IPageProps {
renderAnnotations: (annotations: Doc[], removeOld: boolean) => void;
makePin: (x: number, y: number, page: number) => void;
sendAnnotations: (annotations: HTMLDivElement[], page: number) => void;
- receiveAnnotations: (page: number) => HTMLDivElement[] | undefined;
createAnnotation: (div: HTMLDivElement, page: number) => void;
makeAnnotationDocuments: (doc: Doc | undefined, scale: number, color: string) => Doc;
+ getScrollFromPage: (page: number) => number;
}
@observer
@@ -177,6 +178,18 @@ export default class Page extends React.Component<IPageProps> {
e.stopPropagation();
}
+ createSnippet = (marquee: { left: number, top: number, width: number, height: number }): void => {
+ let doc = this.props.parent.Document;
+ let view = Doc.MakeAlias(doc);
+ let data = Doc.MakeDelegate(doc.proto!);
+ view.proto = data;
+ view.nativeHeight = marquee.height;
+ view.startY = marquee.top + this.props.getScrollFromPage(this.props.page);
+ view.width = doc[WidthSym]();
+ let dragData = new DragManager.DocumentDragData([view]);
+ DragManager.StartDocumentDrag([], dragData, 0, 0);
+ }
+
@action
onPointerDown = (e: React.PointerEvent): void => {
// if alt+left click, drag and annotate
@@ -191,6 +204,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.Snippet = this.createSnippet;
PDFMenu.Instance.Status = "pdf";
PDFMenu.Instance.fadeOut(true);
let target: any = e.target;
@@ -280,10 +294,11 @@ export default class Page extends React.Component<IPageProps> {
if (this._marquee.current) {
let copy = document.createElement("div");
// make a copy of the marquee
- copy.style.left = this._marquee.current.style.left;
- copy.style.top = this._marquee.current.style.top;
- copy.style.width = this._marquee.current.style.width;
- copy.style.height = this._marquee.current.style.height;
+ let style = this._marquee.current.style;
+ copy.style.left = style.left;
+ copy.style.top = style.top;
+ copy.style.width = style.width;
+ copy.style.height = style.height;
// apply the appropriate background, opacity, and transform
let { background, opacity, transform } = this.getCurlyTransform();
@@ -297,7 +312,7 @@ export default class Page extends React.Component<IPageProps> {
copy.appendChild(img);
}
else {
- copy.style.opacity = this._marquee.current.style.opacity;
+ copy.style.opacity = style.opacity;
}
copy.className = this._marquee.current.className;
this.props.createAnnotation(copy, this.props.page);
@@ -305,6 +320,10 @@ export default class Page extends React.Component<IPageProps> {
}
if (this._marqueeWidth > 10 || this._marqueeHeight > 10) {
+ if (!e.ctrlKey) {
+ PDFMenu.Instance.Status = "snippet";
+ PDFMenu.Instance.Marquee = { left: this._marqueeX, top: this._marqueeY, width: this._marqueeWidth, height: this._marqueeHeight };
+ }
PDFMenu.Instance.jumpTo(e.clientX, e.clientY);
}