aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/pdf
diff options
context:
space:
mode:
authoryipstanley <stanley_yip@brown.edu>2019-06-25 13:54:20 -0400
committeryipstanley <stanley_yip@brown.edu>2019-06-25 13:54:20 -0400
commite910a6cd56936234e451994c893d8592e430f828 (patch)
tree6fb76c94d783b31c805ced48b2f1c0c54b74133b /src/client/views/pdf
parent089aaf64964b0f1793a69ef6bf37eb2db41904af (diff)
pdf view specs fixes/changes
Diffstat (limited to 'src/client/views/pdf')
-rw-r--r--src/client/views/pdf/PDFMenu.scss7
-rw-r--r--src/client/views/pdf/PDFMenu.tsx55
-rw-r--r--src/client/views/pdf/PDFViewer.tsx75
3 files changed, 101 insertions, 36 deletions
diff --git a/src/client/views/pdf/PDFMenu.scss b/src/client/views/pdf/PDFMenu.scss
index 22868082a..a4624b1f6 100644
--- a/src/client/views/pdf/PDFMenu.scss
+++ b/src/client/views/pdf/PDFMenu.scss
@@ -22,4 +22,11 @@
height: 100%;
transition: width .2s;
}
+
+ .pdfMenu-addTag {
+ display: grid;
+ width: 200px;
+ padding: 5px;
+ grid-template-columns: 90px 20px 90px;
+ }
} \ No newline at end of file
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index a8e176858..e58ad9ccc 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -1,9 +1,9 @@
import React = require("react");
import "./PDFMenu.scss";
-import { observable, action } from "mobx";
+import { observable, action, runInAction } from "mobx";
import { observer } from "mobx-react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { emptyFunction } from "../../../Utils";
+import { emptyFunction, returnZero, returnTrue, returnFalse } from "../../../Utils";
import { Doc } from "../../../new_fields/Doc";
import { DragManager } from "../../util/DragManager";
import { DocUtils } from "../../documents/Documents";
@@ -23,6 +23,7 @@ export default class PDFMenu extends React.Component {
Highlight: (d: Doc | undefined, color: string | undefined) => void = emptyFunction;
Delete: () => void = emptyFunction;
Snippet: (marquee: { left: number, top: number, width: number, height: number }) => void = emptyFunction;
+ AddTag: (key: string, value: string) => boolean = returnFalse;
@observable public Highlighting: boolean = false;
@observable public Status: "pdf" | "annotation" | "snippet" | "" = "";
@@ -35,6 +36,9 @@ export default class PDFMenu extends React.Component {
private _mainCont: React.RefObject<HTMLDivElement>;
private _dragging: boolean = false;
private _snippetButton: React.RefObject<HTMLButtonElement>;
+ @observable private _keyValue: string = "";
+ @observable private _valueValue: string = "";
+ @observable private _added: boolean = false;;
constructor(props: Readonly<{}>) {
super(props);
@@ -209,35 +213,56 @@ export default class PDFMenu extends React.Component {
e.preventDefault();
}
+ @action
+ keyChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
+ this._keyValue = e.currentTarget.value;
+ }
+
+ @action
+ valueChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
+ 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(
+ () => {
+ runInAction(() => {
+ this._added = false;
+ });
+ }, 1000
+ );
+ }
+ }
+
render() {
let buttons = this.Status === "pdf" || this.Status === "snippet" ? [
- <button className="pdfMenu-button" title="Click to Highlight" onClick={this.highlightClicked}
+ <button className="pdfMenu-button" title="Click to Highlight" onClick={this.highlightClicked} key="1"
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="Drag to Annotate" onPointerDown={this.pointerDown}><FontAwesomeIcon icon="comment-alt" size="lg" key="2" /></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}
+ <button className="pdfMenu-button" title="Pin Menu" onClick={this.togglePin} key="3"
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>
+ <button className="pdfMenu-button" title="Delete Anchor" onPointerDown={this.deleteClicked}><FontAwesomeIcon icon="trash-alt" size="lg" key="1" /></button>,
+ <div className="pdfMenu-addTag" key="2">
+ <input onChange={this.keyChanged} placeholder="Key" style={{ gridColumn: 1 }} />
+ <input onChange={this.valueChanged} placeholder="Value" style={{ gridColumn: 3 }} />
+ </div>,
+ <button className="pdfMenu-button" title={`Add tag: ${this._keyValue} with value: ${this._valueValue}`} onPointerDown={this.addTag}><FontAwesomeIcon style={{ transition: "all .2s" }} color={this._added ? "#42f560" : "white"} icon="check" size="lg" key="3" /></button>,
];
return (
<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 }}>
{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>
- <button className="pdfMenu-button" title="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> */}
<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 1eab13bc5..3df7dd77b 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -20,8 +20,8 @@ import "./PDFViewer.scss";
import React = require("react");
import PDFMenu from "./PDFMenu";
import { UndoManager } from "../../util/UndoManager";
-import { ScriptField } from "../../../fields/ScriptField";
import { CompileScript, CompiledScript, CompileResult } from "../../util/Scripting";
+import { ScriptField } from "../../../new_fields/ScriptField";
export const scale = 2;
interface IPDFViewerProps {
@@ -63,8 +63,6 @@ interface IViewerProps {
url: string;
}
-const PinRadius = 25;
-
/**
* Handles rendering and virtualization of the pdf
*/
@@ -85,14 +83,18 @@ class Viewer extends React.Component<IViewerProps> {
private _annotationReactionDisposer?: IReactionDisposer;
private _dropDisposer?: DragManager.DragDropDisposer;
private _filterReactionDisposer?: IReactionDisposer;
+ private _viewer: React.RefObject<HTMLDivElement>;
+ private _mainCont: React.RefObject<HTMLDivElement>;
+ private _textContent: Pdfjs.TextContent[] = [];
- @action
- constructor(props: IViewerProps) {
- super(props);
+ constructor(props: IViewerProps) {
+ super(props);
- let scriptfield = Cast(this.props.parent.Document.filterScript, ScriptField);
- this._script = scriptfield ? CompileScript(scriptfield.scriptString, { params: { this: Doc.name } }) : CompileScript("return true");;
- }
+ let scriptfield = Cast(this.props.parent.Document.filterScript, ScriptField);
+ this._script = scriptfield ? scriptfield.script : CompileScript("return true");
+ this._viewer = React.createRef();
+ this._mainCont = React.createRef();
+ }
componentDidUpdate = (prevProps: IViewerProps) => {
if (this.scrollY !== prevProps.scrollY) {
@@ -118,21 +120,37 @@ class Viewer extends React.Component<IViewerProps> {
if (this.props.parent.props.ContainingCollectionView) {
this._filterReactionDisposer = reaction(
- () => this.props.parent.Document.filterScript || this.props.parent.props.ContainingCollectionView!.props.Document.filterScript,
+ () => this.props.parent.Document.filterScript,
() => {
runInAction(() => {
let scriptfield = Cast(this.props.parent.Document.filterScript, ScriptField);
- this._script = scriptfield ? CompileScript(scriptfield.scriptString, { params: { this: Doc.name } }) : CompileScript("return true");;
+ this._script = scriptfield ? scriptfield.script : CompileScript("return true");
+ if (this.props.parent.props.ContainingCollectionView) {
+ let ccvAnnos = DocListCast(this.props.parent.props.ContainingCollectionView.props.Document.annotations);
+ ccvAnnos.forEach(d => {
+ if (this._script && this._script.compiled) {
+ let run = this._script.run(d);
+ if (run.success) {
+ d.opacity = run.result ? 1 : 0;
+ }
+ }
+ })
+ }
});
}
);
}
+
+ if (this._mainCont.current) {
+ this._dropDisposer = this._mainCont.current && DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } });
+ }
}
componentWillUnmount = () => {
this._reactionDisposer && this._reactionDisposer();
this._annotationReactionDisposer && this._annotationReactionDisposer();
this._filterReactionDisposer && this._filterReactionDisposer();
+ this._dropDisposer && this._dropDisposer();
}
@action
@@ -140,10 +158,14 @@ class Viewer extends React.Component<IViewerProps> {
if (this._pageSizes.length === 0) {
let pageSizes = Array<{ width: number, height: number }>(this.props.pdf.numPages);
this._isPage = Array<string>(this.props.pdf.numPages);
+ this._textContent = Array<Pdfjs.TextContent>(this.props.pdf.numPages);
for (let i = 0; i < this.props.pdf.numPages; i++) {
await this.props.pdf.getPage(i + 1).then(page => runInAction(() => {
// pageSizes[i] = { width: page.view[2] * scale, height: page.view[3] * scale };
let x = page.getViewport(scale);
+ page.getTextContent().then((text: Pdfjs.TextContent) => {
+ this._textContent[i] = text;
+ })
pageSizes[i] = { width: x.width, height: x.height };
}));
}
@@ -162,13 +184,6 @@ class Viewer extends React.Component<IViewerProps> {
}
}
- private mainCont = (div: HTMLDivElement | null) => {
- this._dropDisposer && this._dropDisposer();
- if (div) {
- this._dropDisposer = div && DragManager.MakeDropTarget(div, { handlers: { drop: this.drop.bind(this) } });
- }
- }
-
makeAnnotationDocument = (sourceDoc: Doc | undefined, s: number, color: string): Doc => {
let annoDocs: Doc[] = [];
let mainAnnoDoc = Docs.CreateInstance(new Doc(), "", {});
@@ -222,6 +237,7 @@ class Viewer extends React.Component<IViewerProps> {
pageLoaded = (index: number, page: Pdfjs.PDFPageViewport): void => {
this.props.loaded(page.width, page.height, this.props.pdf.numPages);
}
+
@action
getPlaceholderPage = (page: number) => {
if (this._isPage[page] !== "none") {
@@ -232,6 +248,7 @@ class Viewer extends React.Component<IViewerProps> {
);
}
}
+
@action
getRenderedPage = (page: number) => {
if (this._isPage[page] !== "page") {
@@ -374,11 +391,16 @@ class Viewer extends React.Component<IViewerProps> {
return res;
}
+ pointerDown = () => {
+
+ let x = this._textContent;
+ }
+
render() {
let compiled = this._script;
return (
- <div ref={this.mainCont} style={{ pointerEvents: "all" }}>
- <div className="viewer">
+ <div ref={this._mainCont} style={{ pointerEvents: "all" }} onPointerDown={this.pointerDown}>
+ <div className="viewer" ref={this._viewer}>
{this._visibleElements}
</div>
<div className="pdfViewer-annotationLayer"
@@ -472,12 +494,23 @@ class RegionAnnotation extends React.Component<IAnnotationProps> {
}
if (e.button === 2) {
PDFMenu.Instance.Status = "annotation";
- PDFMenu.Instance.Delete = this.deleteAnnotation;
+ PDFMenu.Instance.Delete = this.deleteAnnotation.bind(this);
PDFMenu.Instance.Pinned = false;
+ PDFMenu.Instance.AddTag = this.addTag.bind(this);
PDFMenu.Instance.jumpTo(e.clientX, e.clientY, true);
}
}
+ addTag = (key: string, value: string): boolean => {
+ let group = FieldValue(Cast(this.props.document.group, Doc));
+ if (group) {
+ let valNum = parseInt(value);
+ group[key] = isNaN(valNum) ? value : valNum;
+ return true;
+ }
+ return false;
+ }
+
render() {
return (
<div className="pdfViewer-annotationBox" onPointerDown={this.onPointerDown} ref={this._mainCont}