aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/MainView.tsx6
-rw-r--r--src/client/views/nodes/PDFBox.tsx10
-rw-r--r--src/client/views/pdf/PDFMenu.scss18
-rw-r--r--src/client/views/pdf/PDFMenu.tsx49
-rw-r--r--src/client/views/pdf/PDFViewer.tsx6
-rw-r--r--src/client/views/pdf/Page.tsx164
6 files changed, 207 insertions, 46 deletions
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 879c2aca0..384cd2860 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, faRedoAlt, faTable, faTree, faUndoAlt, faBell } from '@fortawesome/free-solid-svg-icons';
+import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faTree, faUndoAlt, faBell, faCommentAlt } 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';
@@ -33,6 +33,7 @@ import { listSpec } from '../../new_fields/Schema';
import { Id } from '../../new_fields/FieldSymbols';
import { HistoryUtil } from '../util/History';
import { CollectionBaseView } from './collections/CollectionBaseView';
+import PDFMenu from './pdf/PDFMenu';
import { InkTool } from '../../new_fields/InkField';
@@ -90,6 +91,7 @@ export class MainView extends React.Component {
library.add(faFilm);
library.add(faMusic);
library.add(faTree);
+ library.add(faCommentAlt);
this.initEventListeners();
this.initAuthenticationRouters();
}
@@ -323,6 +325,8 @@ export class MainView extends React.Component {
<ContextMenu />
{this.nodesMenu()}
{this.miscButtons}
+ <InkingControl />
+ <PDFMenu />
<MainOverlayTextBox />
</div>
);
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index cce7b2631..a3c818c91 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -34,8 +34,16 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
loaded = (nw: number, nh: number) => {
if (this.props.Document) {
let doc = this.props.Document.proto ? this.props.Document.proto : this.props.Document;
+ let oldnw = NumCast(doc.nativeWidth);
doc.nativeWidth = nw;
- doc.nativeHeight = nh;
+ if (!doc.nativeHeight) {
+ doc.nativeHeight = nh;
+ }
+ else {
+ let oldnh = NumCast(doc.nativeHeight);
+ let aspect = oldnh / oldnw;
+ doc.nativeHeight = nw * aspect;
+ }
let ccv = this.props.ContainingCollectionView;
if (ccv) {
ccv.props.Document.pdfHeight = nh;
diff --git a/src/client/views/pdf/PDFMenu.scss b/src/client/views/pdf/PDFMenu.scss
new file mode 100644
index 000000000..b84ebc12d
--- /dev/null
+++ b/src/client/views/pdf/PDFMenu.scss
@@ -0,0 +1,18 @@
+.pdfMenu-cont {
+ position: absolute;
+ z-index: 10000;
+ width: 100px;
+ height: 30px;
+ background: #323232;
+ box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.25);
+ border-radius: 0px 4px 4px 4px;
+ overflow: hidden;
+
+ .pdfMenu-button {
+ background-color: transparent;
+ }
+
+ .pdfMenu-button:hover {
+ background-color: #121212;
+ }
+} \ No newline at end of file
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
new file mode 100644
index 000000000..a0230113b
--- /dev/null
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -0,0 +1,49 @@
+import React = require("react");
+import "./PDFMenu.scss";
+import { observable } from "mobx";
+import { observer } from "mobx-react";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { emptyFunction } from "../../../Utils";
+import { Doc } from "../../../new_fields/Doc";
+
+@observer
+export default class PDFMenu extends React.Component {
+ static Instance: PDFMenu;
+
+ @observable Top: number = 0;
+ @observable Left: number = 0;
+ StartDrag: (e: PointerEvent) => void = emptyFunction;
+ Highlight: (d: Doc | undefined) => void = emptyFunction;
+
+ constructor(props: Readonly<{}>) {
+ super(props);
+
+ PDFMenu.Instance = this;
+ }
+
+ pointerDown = (e: React.PointerEvent) => {
+ document.removeEventListener("pointermove", this.StartDrag);
+ document.addEventListener("pointermove", this.StartDrag);
+ document.removeEventListener("pointerup", this.pointerUp)
+ document.addEventListener("pointerup", this.pointerUp)
+
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+ pointerUp = (e: PointerEvent) => {
+ document.removeEventListener("pointermove", this.StartDrag);
+ document.removeEventListener("pointerup", this.pointerUp);
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+ render() {
+ return (
+ <div className="pdfMenu-cont" style={{ left: this.Left, top: this.Top }}>
+ <button className="pdfMenu-button" title="Highlight" onClick={() => this.Highlight(undefined)}><FontAwesomeIcon icon="highlighter" size="sm" /></button>
+ <button className="pdfMenu-button" title="Annotate" onPointerDown={this.pointerDown}><FontAwesomeIcon icon="comment-alt" size="sm" /></button>
+ </div>
+ )
+ }
+} \ No newline at end of file
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 440a20e8e..17f65c7a6 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -151,7 +151,7 @@ class Viewer extends React.Component<IViewerProps> {
}
}
- makeAnnotationDocument = (sourceDoc: Doc): Doc => {
+ makeAnnotationDocument = (sourceDoc: Doc | undefined): Doc => {
let annoDocs: Doc[] = [];
this._savedAnnotations.forEach((key: number, value: HTMLDivElement[]) => {
for (let anno of value) {
@@ -170,7 +170,9 @@ class Viewer extends React.Component<IViewerProps> {
let annoDoc = new Doc();
annoDoc.annotations = new List<Doc>(annoDocs);
- DocUtils.MakeLink(sourceDoc, annoDoc, undefined, `Annotation from ${StrCast(this.props.parent.Document.title)}`, "", StrCast(this.props.parent.Document.title));
+ if (sourceDoc) {
+ DocUtils.MakeLink(sourceDoc, annoDoc, undefined, `Annotation from ${StrCast(this.props.parent.Document.title)}`, "", StrCast(this.props.parent.Document.title));
+ }
this._savedAnnotations.clear();
return annoDoc;
}
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index fa3f7baca..44c502a04 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -14,6 +14,7 @@ import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
import { listSpec } from "../../../new_fields/Schema";
import { menuBar } from "prosemirror-menu";
import { AnnotationTypes } from "./PDFViewer";
+import PDFMenu from "./PDFMenu";
interface IPageProps {
pdf: Opt<Pdfjs.PDFDocumentProxy>;
@@ -27,7 +28,7 @@ interface IPageProps {
sendAnnotations: (annotations: HTMLDivElement[], page: number) => void;
receiveAnnotations: (page: number) => HTMLDivElement[] | undefined;
createAnnotation: (div: HTMLDivElement, page: number) => void;
- makeAnnotationDocuments: (doc: Doc) => Doc;
+ makeAnnotationDocuments: (doc: Doc | undefined) => Doc;
}
@observer
@@ -131,6 +132,20 @@ export default class Page extends React.Component<IPageProps> {
}
}
+ highlight = (targetDoc: Doc | undefined) => {
+ // creates annotation documents for current highlights
+ let annotationDoc = this.props.makeAnnotationDocuments(targetDoc);
+ let targetAnnotations = DocListCast(this.props.parent.Document.annotations);
+ if (targetAnnotations) {
+ targetAnnotations.push(annotationDoc);
+ this.props.parent.Document.annotations = new List<Doc>(targetAnnotations);
+ }
+ else {
+ this.props.parent.Document.annotations = new List<Doc>([annotationDoc]);
+ }
+ return annotationDoc;
+ }
+
/**
* This is temporary for creating annotations from highlights. It will
* start a drag event and create or put the necessary info into the drag event.
@@ -148,16 +163,7 @@ export default class Page extends React.Component<IPageProps> {
// document that this annotation is linked to
let targetDoc = Docs.TextDocument({ width: 200, height: 200, title: "New Annotation" });
targetDoc.targetPage = this.props.page;
- // creates annotation documents for current highlights
- let annotationDoc = this.props.makeAnnotationDocuments(targetDoc);
- let targetAnnotations = DocListCast(this.props.parent.Document.annotations);
- if (targetAnnotations) {
- targetAnnotations.push(annotationDoc);
- this.props.parent.Document.annotations = new List<Doc>(targetAnnotations);
- }
- else {
- this.props.parent.Document.annotations = new List<Doc>([annotationDoc]);
- }
+ let annotationDoc = this.highlight(targetDoc);
// create dragData and star tdrag
let dragData = new DragManager.AnnotationDragData(thisDoc, annotationDoc, targetDoc);
if (this._textLayer.current) {
@@ -172,8 +178,8 @@ export default class Page extends React.Component<IPageProps> {
// cleans up events and boolean
endDrag = (e: PointerEvent): void => {
- document.removeEventListener("pointermove", this.startDrag);
- document.removeEventListener("pointerup", this.endDrag);
+ // document.removeEventListener("pointermove", this.startDrag);
+ // document.removeEventListener("pointerup", this.endDrag);
this._dragging = false;
e.stopPropagation();
}
@@ -184,10 +190,10 @@ export default class Page extends React.Component<IPageProps> {
if (e.altKey && e.button === 0) {
e.stopPropagation();
- document.removeEventListener("pointermove", this.startDrag);
- document.addEventListener("pointermove", this.startDrag);
- document.removeEventListener("pointerup", this.endDrag);
- document.addEventListener("pointerup", this.endDrag);
+ // document.removeEventListener("pointermove", this.startDrag);
+ // document.addEventListener("pointermove", this.startDrag);
+ // document.removeEventListener("pointerup", this.endDrag);
+ // document.addEventListener("pointerup", this.endDrag);
}
else if (e.button === 0) {
let target: any = e.target;
@@ -271,7 +277,7 @@ export default class Page extends React.Component<IPageProps> {
}
@action
- onSelectEnd = (): void => {
+ onSelectEnd = (e: PointerEvent): void => {
if (this._marqueeing) {
this._marqueeing = false;
if (this._marquee.current) {
@@ -298,44 +304,118 @@ export default class Page extends React.Component<IPageProps> {
}
copy.className = this._marquee.current.className;
this.props.createAnnotation(copy, this.props.page);
+ PDFMenu.Instance.StartDrag = this.startDrag;
+ PDFMenu.Instance.Highlight = this.highlight;
this._marquee.current.style.opacity = "0";
}
this._marqueeHeight = this._marqueeWidth = 0;
+ PDFMenu.Instance.Left = e.clientX;
+ PDFMenu.Instance.Top = e.clientY;
}
else {
let sel = window.getSelection();
- // if selecting over a range of things
if (sel && sel.type === "Range") {
- let clientRects = sel.getRangeAt(0).getClientRects();
- if (this._textLayer.current) {
- let boundingRect = this._textLayer.current.getBoundingClientRect();
- for (let i = 0; i < clientRects.length; i++) {
- let rect = clientRects.item(i);
- if (rect) {
- let annoBox = document.createElement("div");
- annoBox.className = "pdfViewer-annotationBox";
- // transforms the positions from screen onto the pdf div
- annoBox.style.top = ((rect.top - boundingRect.top) * (this._textLayer.current.offsetHeight / boundingRect.height)).toString();
- annoBox.style.left = ((rect.left - boundingRect.left) * (this._textLayer.current.offsetWidth / boundingRect.width)).toString();
- annoBox.style.width = (rect.width * this._textLayer.current.offsetWidth / boundingRect.width).toString();
- annoBox.style.height = (rect.height * this._textLayer.current.offsetHeight / boundingRect.height).toString();
- this.props.createAnnotation(annoBox, this.props.page);
- }
- }
- }
- // clear selection
- if (sel.empty) { // Chrome
- sel.empty();
- } else if (sel.removeAllRanges) { // Firefox
- sel.removeAllRanges();
- }
+ PDFMenu.Instance.StartDrag = this.startDrag;
+ PDFMenu.Instance.Highlight = this.highlight;
+ this.createTextAnnotation(sel);
+ PDFMenu.Instance.Left = e.clientX;
+ PDFMenu.Instance.Top = e.clientY;
}
}
+ // let x = (e.clientX - boundingRect.left) * (current.offsetWidth / boundingRect.width);
+ // let y = (e.clientY - boundingRect.top) * (current.offsetHeight / boundingRect.height);
+ // if (this._marqueeing) {
+ // this._marqueeing = false;
+ // 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;
+
+ // // apply the appropriate background, opacity, and transform
+ // let { background, opacity, transform } = this.getCurlyTransform();
+ // copy.style.background = background;
+ // // if curly bracing, add a curly brace
+ // if (opacity === "1" && this._curly.current) {
+ // copy.style.opacity = opacity;
+ // let img = this._curly.current.cloneNode();
+ // (img as any).style.opacity = opacity;
+ // (img as any).style.transform = transform;
+ // copy.appendChild(img);
+ // }
+ // else {
+ // copy.style.opacity = this._marquee.current.style.opacity;
+ // }
+ // copy.className = this._marquee.current.className;
+ // this.props.createAnnotation(copy, this.props.page);
+ // this._marquee.current.style.opacity = "0";
+ // }
+
+ // this._marqueeHeight = this._marqueeWidth = 0;
+ // }
+ // else {
+ // let sel = window.getSelection();
+ // // if selecting over a range of things
+ // if (sel && sel.type === "Range") {
+ // let clientRects = sel.getRangeAt(0).getClientRects();
+ // if (this._textLayer.current) {
+ // let boundingRect = this._textLayer.current.getBoundingClientRect();
+ // for (let i = 0; i < clientRects.length; i++) {
+ // let rect = clientRects.item(i);
+ // if (rect) {
+ // let annoBox = document.createElement("div");
+ // annoBox.className = "pdfViewer-annotationBox";
+ // // transforms the positions from screen onto the pdf div
+ // annoBox.style.top = ((rect.top - boundingRect.top) * (this._textLayer.current.offsetHeight / boundingRect.height)).toString();
+ // annoBox.style.left = ((rect.left - boundingRect.left) * (this._textLayer.current.offsetWidth / boundingRect.width)).toString();
+ // annoBox.style.width = (rect.width * this._textLayer.current.offsetWidth / boundingRect.width).toString();
+ // annoBox.style.height = (rect.height * this._textLayer.current.offsetHeight / boundingRect.height).toString();
+ // this.props.createAnnotation(annoBox, this.props.page);
+ // }
+ // }
+ // }
+ // // clear selection
+ // if (sel.empty) { // Chrome
+ // sel.empty();
+ // } else if (sel.removeAllRanges) { // Firefox
+ // sel.removeAllRanges();
+ // }
+ // }
+ // }
document.removeEventListener("pointermove", this.onSelectStart);
document.removeEventListener("pointerup", this.onSelectEnd);
}
+ @action
+ createTextAnnotation = (sel: Selection) => {
+ let clientRects = sel.getRangeAt(0).getClientRects();
+ if (this._textLayer.current) {
+ let boundingRect = this._textLayer.current.getBoundingClientRect();
+ for (let i = 0; i < clientRects.length; i++) {
+ let rect = clientRects.item(i);
+ if (rect) {
+ let annoBox = document.createElement("div");
+ annoBox.className = "pdfViewer-annotationBox";
+ // transforms the positions from screen onto the pdf div
+ annoBox.style.top = ((rect.top - boundingRect.top) * (this._textLayer.current.offsetHeight / boundingRect.height)).toString();
+ annoBox.style.left = ((rect.left - boundingRect.left) * (this._textLayer.current.offsetWidth / boundingRect.width)).toString();
+ annoBox.style.width = (rect.width * this._textLayer.current.offsetWidth / boundingRect.width).toString();
+ annoBox.style.height = (rect.height * this._textLayer.current.offsetHeight / boundingRect.height).toString();
+ this.props.createAnnotation(annoBox, this.props.page);
+ }
+ }
+ }
+ // clear selection
+ if (sel.empty) { // Chrome
+ sel.empty();
+ } else if (sel.removeAllRanges) { // Firefox
+ sel.removeAllRanges();
+ }
+ }
+
doubleClick = (e: React.MouseEvent) => {
let target: any = e.target;
// if double clicking text