aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts2
-rw-r--r--src/client/views/MainView.tsx4
-rw-r--r--src/client/views/nodes/PDFBox.scss68
-rw-r--r--src/client/views/nodes/PDFBox.tsx111
-rw-r--r--src/client/views/pdf/PDFMenu.tsx45
-rw-r--r--src/client/views/pdf/PDFViewer.tsx196
-rw-r--r--src/client/views/pdf/Page.tsx31
7 files changed, 291 insertions, 166 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index b04fc401a..cc67c68e9 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -199,7 +199,7 @@ export namespace Docs {
return audioProto;
}
- function CreateInstance(proto: Doc, data: Field, options: DocumentOptions, delegId?: string) {
+ export function CreateInstance(proto: Doc, data: Field, options: DocumentOptions, delegId?: string) {
const { omit: protoProps, extract: delegateProps } = OmitKeys(options, delegateKeys);
if (!("author" in protoProps)) {
protoProps.author = CurrentUserUtils.email;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 51630c29b..226eb458b 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, faCheck, 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,8 +91,10 @@ export class MainView extends React.Component {
library.add(faFilm);
library.add(faMusic);
library.add(faTree);
+ library.add(faCut);
library.add(faCommentAlt);
library.add(faThumbtack);
+ library.add(faCheck);
this.initEventListeners();
this.initAuthenticationRouters();
}
diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index 8bcae4f1e..5edff69f3 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -36,12 +36,15 @@
pointer-events: none;
display: flex;
flex-direction: row;
+
.textlayer {
pointer-events: none;
+
span {
pointer-events: none !important;
}
}
+
.page-cont {
pointer-events: none;
}
@@ -51,6 +54,7 @@
pointer-events: all;
display: flex;
flex-direction: row;
+
.textlayer {
span {
pointer-events: all !important;
@@ -62,4 +66,68 @@
.pdfBox-contentContainer {
position: absolute;
transform-origin: left top;
+}
+
+.pdfBox-settingsCont {
+ position: absolute;
+ right: 0;
+ top: 0;
+
+ .pdfBox-settingsButton {
+ border-bottom-left-radius: 50%;
+ display: flex;
+ justify-content: space-evenly;
+ align-items: center;
+ height: 70px;
+ background: none;
+ padding: 0;
+
+ .pdfBox-settingsButton-arrow {
+ width: 0;
+ height: 0;
+ border-top: 25px solid transparent;
+ border-bottom: 25px solid transparent;
+ border-right: 25px solid #121721;
+ transition: all 0.5s;
+ }
+
+ .pdfBox-settingsButton-iconCont {
+ background: #121721;
+ height: 50px;
+ width: 70px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-left: -2px;
+ border-radius: 3px;
+ }
+ }
+
+ .pdfBox-settingsButton:hover {
+ background: none;
+ }
+
+ .pdfBox-settingsFlyout {
+ width: 600px;
+ position: absolute;
+ background: #323232;
+ box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.25);
+ left: -400px;
+ border-radius: 7px;
+ padding: 20px;
+ display: flex;
+ flex-direction: column;
+ font-size: 30px;
+ transition: all 0.5s;
+
+ .pdfBox-settingsFlyout-title {
+ color: white;
+ }
+
+ .pdfBox-settingsFlyout-kvpInput {
+ margin-top: 20px;
+ display: grid;
+ grid-template-columns: 47.5% 5% 47.5%;
+ }
+ }
} \ No newline at end of file
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index d2de1cb1c..aa421ff9c 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -1,7 +1,7 @@
import { action, IReactionDisposer, observable, reaction, trace, untracked } from 'mobx';
import { observer } from "mobx-react";
import 'react-image-lightbox/style.css';
-import { WidthSym } from "../../../new_fields/Doc";
+import { WidthSym, Doc } from "../../../new_fields/Doc";
import { makeInterface } from "../../../new_fields/Schema";
import { Cast, NumCast } from "../../../new_fields/Types";
import { PdfField } from "../../../new_fields/URLField";
@@ -17,6 +17,10 @@ import { FieldView, FieldViewProps } from './FieldView';
import { pageSchema } from "./ImageBox";
import "./PDFBox.scss";
import React = require("react");
+import { CompileScript } from '../../util/Scripting';
+import { ScriptField } from '../../../fields/ScriptField';
+import { Flyout, anchorPoints } from '../DocumentDecorations';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
type PdfDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>;
const PdfDocument = makeInterface(positionSchema, pageSchema);
@@ -27,12 +31,40 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
@observable private _alt = false;
@observable private _scrollY: number = 0;
+ @observable private _flyout: boolean = false;
+ private _mainCont: React.RefObject<HTMLDivElement>;
private _reactionDisposer?: IReactionDisposer;
+ private _keyValue: string = "";
+ private _valueValue: string = "";
+ private _scriptValue: string = "";
+
+ 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: "auto" });
+ }
+ }
+ );
+
+ let script = CompileScript("return this.page === 0", { params: { this: Doc.name } });
+ if (script.compiled) {
+ this.props.Document.filterScript = new ScriptField(script);
+ }
+ }
componentDidMount() {
if (this.props.setPdfBox) this.props.setPdfBox(this);
}
+ componentWillUnmount() {
+ this._reactionDisposer && this._reactionDisposer();
+ }
+
public GetPage() {
return Math.floor(NumCast(this.props.Document.scrollY) / NumCast(this.Document.pdfHeight)) + 1;
}
@@ -59,11 +91,75 @@ 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" });
- });
+ private newKeyChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ this._keyValue = e.currentTarget.value;
+ }
+
+ private newValueChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ this._valueValue = e.currentTarget.value;
+ }
+
+ private newScriptChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ this._scriptValue = e.currentTarget.value;
+ }
+
+ private applyFilter = (e: React.MouseEvent<HTMLButtonElement>) => {
+ let scriptText = "";
+ if (this._scriptValue.length > 0) {
+ scriptText = this._scriptValue;
+ } else if (this._keyValue.length > 0 && this._valueValue.length > 0) {
+ scriptText = `return this.${this._keyValue} === ${this._valueValue}`;
+ }
+ let script = CompileScript(scriptText, { params: { this: Doc.name } });
+ if (script.compiled) {
+ this.props.Document.filterScript = new ScriptField(script);
+ }
+ }
+
+ @action
+ private toggleFlyout = () => {
+ this._flyout = !this._flyout;
+ }
+
+ settingsPanel() {
+ return !this.props.active() ? (null) :
+ (
+ <div className="pdfBox-settingsCont" onPointerDown={(e) => e.stopPropagation()}>
+ <button className="pdfBox-settingsButton" onClick={this.toggleFlyout}
+ style={{ marginTop: `${NumCast(this.props.ContainingCollectionView!.props.Document.panY)}px` }}>
+ <div className="pdfBox-settingsButton-arrow"
+ style={{
+ borderTop: `25px solid ${this._flyout ? "#121721" : "transparent"}`,
+ borderBottom: `25px solid ${this._flyout ? "#121721" : "transparent"}`,
+ borderRight: `25px solid ${this._flyout ? "transparent" : "#121721"}`,
+ transform: `scaleX(${this._flyout ? -1 : 1})`
+ }}></div>
+ <div className="pdfBox-settingsButton-iconCont">
+ <FontAwesomeIcon style={{ color: "white" }} icon="cog" size="3x" />
+ </div>
+ </button>
+ <div className="pdfBox-settingsFlyout" style={{ left: `${this._flyout ? -600 : 100}px` }} >
+ <div className="pdfBox-settingsFlyout-title">
+ Annotation View Settings
+ </div>
+ <div className="pdfBox-settingsFlyout-kvpInput">
+ <input placeholder="Key" className="pdfBox-settingsFlyout-input" onChange={this.newKeyChange}
+ style={{ gridColumn: 1 }} />
+ <input placeholder="Value" className="pdfBox-settingsFlyout-input" onChange={this.newValueChange}
+ style={{ gridColumn: 3 }} />
+ </div>
+ <div className="pdfBox-settingsFlyout-kvpInput">
+ <input placeholder="Custom Script" onChange={this.newScriptChange} style={{ gridColumn: "1 / 4" }} />
+ </div>
+ <div className="pdfBox-settingsFlyout-kvpInput">
+ <button style={{ gridColumn: 3 }} onClick={this.applyFilter}>
+ <FontAwesomeIcon style={{ color: "white" }} icon="check" size="lg" />
+ &nbsp; Apply
+ </button>
+ </div>
+ </div>
+ </div>
+ );
}
loaded = (nw: number, nh: number, np: number) => {
@@ -105,12 +201,13 @@ 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}>
<PDFViewer url={pdfUrl.url.pathname} loaded={this.loaded} scrollY={this._scrollY} parent={this} />
{/* <div style={{ width: "100px", height: "300px" }}></div> */}
+ {this.settingsPanel()}
</div>
);
}
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 6adead626..1eab13bc5 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -10,7 +10,7 @@ import { List } from "../../../new_fields/List";
import { BoolCast, Cast, NumCast, StrCast, FieldValue } from "../../../new_fields/Types";
import { emptyFunction } from "../../../Utils";
import { DocServer } from "../../DocServer";
-import { Docs, DocUtils } from "../../documents/Documents";
+import { Docs, DocUtils, DocumentOptions } from "../../documents/Documents";
import { DocumentManager } from "../../util/DocumentManager";
import { DragManager } from "../../util/DragManager";
import { DocumentView } from "../nodes/DocumentView";
@@ -20,6 +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";
export const scale = 2;
interface IPDFViewerProps {
@@ -75,12 +77,22 @@ class Viewer extends React.Component<IViewerProps> {
@observable private _pageSizes: { width: number, height: number }[] = [];
@observable private _annotations: Doc[] = [];
@observable private _savedAnnotations: Dictionary<number, HTMLDivElement[]> = new Dictionary<number, HTMLDivElement[]>();
+ @observable private _script: CompileResult | undefined;
private _pageBuffer: number = 1;
private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
private _reactionDisposer?: IReactionDisposer;
private _annotationReactionDisposer?: IReactionDisposer;
private _dropDisposer?: DragManager.DragDropDisposer;
+ private _filterReactionDisposer?: IReactionDisposer;
+
+ @action
+ 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");;
+ }
componentDidUpdate = (prevProps: IViewerProps) => {
if (this.scrollY !== prevProps.scrollY) {
@@ -103,11 +115,24 @@ class Viewer extends React.Component<IViewerProps> {
(annotations: Doc[]) =>
annotations && annotations.length && this.renderAnnotations(annotations, true),
{ fireImmediately: true });
+
+ if (this.props.parent.props.ContainingCollectionView) {
+ this._filterReactionDisposer = reaction(
+ () => this.props.parent.Document.filterScript || this.props.parent.props.ContainingCollectionView!.props.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");;
+ });
+ }
+ );
+ }
}
componentWillUnmount = () => {
this._reactionDisposer && this._reactionDisposer();
this._annotationReactionDisposer && this._annotationReactionDisposer();
+ this._filterReactionDisposer && this._filterReactionDisposer();
}
@action
@@ -126,6 +151,14 @@ class Viewer extends React.Component<IViewerProps> {
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);
// 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);
+ let ccv = this.props.parent.props.ContainingCollectionView;
+ if (ccv) {
+ ccv.props.Document.panY = startY;
+ }
+ this.props.parent.Document.scrollY = 0;
+ this.props.parent.Document.scrollY = startY + 1;
}
}
@@ -138,7 +171,9 @@ class Viewer extends React.Component<IViewerProps> {
makeAnnotationDocument = (sourceDoc: Doc | undefined, s: number, color: string): Doc => {
let annoDocs: Doc[] = [];
- let mainAnnoDoc = new Doc();
+ let mainAnnoDoc = Docs.CreateInstance(new Doc(), "", {});
+
+ mainAnnoDoc.page = Math.round(Math.random());
this._savedAnnotations.forEach((key: number, value: HTMLDivElement[]) => {
for (let anno of value) {
let annoDoc = new Doc();
@@ -216,7 +251,7 @@ class Viewer extends React.Component<IViewerProps> {
createAnnotation={this.createAnnotation}
sendAnnotations={this.receiveAnnotations}
makeAnnotationDocuments={this.makeAnnotationDocument}
- receiveAnnotations={this.sendAnnotations}
+ getScrollFromPage={this.getScrollFromPage}
{...this.props} />
);
}
@@ -288,28 +323,6 @@ class Viewer extends React.Component<IViewerProps> {
return this._savedAnnotations.getValue(page);
}
- // createPinAnnotation = (x: number, y: number, page: number): void => {
- // let targetDoc = Docs.TextDocument({ width: 100, height: 50, title: "New Pin Annotation" });
- // let pinAnno = new Doc();
- // pinAnno.x = x;
- // pinAnno.y = y + this.getScrollFromPage(page);
- // pinAnno.width = pinAnno.height = PinRadius;
- // pinAnno.page = page;
- // pinAnno.target = targetDoc;
- // pinAnno.type = AnnotationTypes.Pin;
- // // this._annotations.push(pinAnno);
- // let annoDoc = new Doc();
- // annoDoc.annotations = new List<Doc>([pinAnno]);
- // let annotations = DocListCast(this.props.parent.Document.annotations);
- // if (annotations && annotations.length) {
- // annotations.push(annoDoc);
- // this.props.parent.Document.annotations = new List<Doc>(annotations);
- // }
- // else {
- // this.props.parent.Document.annotations = new List<Doc>([annoDoc]);
- // }
- // }
-
// get the page index that the vertical offset passed in is on
getPageFromScroll = (vOffset: number) => {
let index = 0;
@@ -362,6 +375,7 @@ class Viewer extends React.Component<IViewerProps> {
}
render() {
+ let compiled = this._script;
return (
<div ref={this.mainCont} style={{ pointerEvents: "all" }}>
<div className="viewer">
@@ -373,7 +387,15 @@ class Viewer extends React.Component<IViewerProps> {
pointerEvents: this.props.parent.props.active() ? "none" : "all"
}}>
<div className="pdfViewer-annotationLayer-subCont" ref={this._annotationLayer}>
- {this._annotations.map(anno => this.renderAnnotation(anno))}
+ {this._annotations.filter(anno => {
+ if (compiled && compiled.compiled) {
+ let run = compiled.run({ this: anno });
+ if (run.success) {
+ return run.result;
+ }
+ }
+ return true;
+ }).map(anno => this.renderAnnotation(anno))}
</div>
</div>
</div >
@@ -394,119 +416,6 @@ interface IAnnotationProps {
document: Doc;
}
-// @observer
-// class PinAnnotation extends React.Component<IAnnotationProps> {
-// @observable private _backgroundColor: string = "green";
-// @observable private _display: string = "initial";
-
-// private _mainCont: React.RefObject<HTMLDivElement>;
-
-// constructor(props: IAnnotationProps) {
-// super(props);
-// this._mainCont = React.createRef();
-// }
-
-// componentDidMount = () => {
-// let selected = this.props.document.selected;
-// if (!BoolCast(selected)) {
-// runInAction(() => {
-// this._backgroundColor = "red";
-// this._display = "none";
-// });
-// }
-// if (selected) {
-// if (BoolCast(selected)) {
-// runInAction(() => {
-// this._backgroundColor = "green";
-// this._display = "initial";
-// });
-// }
-// else {
-// runInAction(() => {
-// this._backgroundColor = "red";
-// this._display = "none";
-// });
-// }
-// }
-// else {
-// runInAction(() => {
-// this._backgroundColor = "red";
-// this._display = "none";
-// });
-// }
-// }
-
-// @action
-// pointerDown = (e: React.PointerEvent) => {
-// let selected = this.props.document.selected;
-// if (selected && BoolCast(selected)) {
-// this._backgroundColor = "red";
-// this._display = "none";
-// this.props.document.selected = false;
-// }
-// else {
-// this._backgroundColor = "green";
-// this._display = "initial";
-// this.props.document.selected = true;
-// }
-// e.preventDefault();
-// e.stopPropagation();
-// }
-
-// @action
-// doubleClick = (e: React.MouseEvent) => {
-// if (this._mainCont.current) {
-// let annotations = DocListCast(this.props.parent.props.parent.Document.annotations);
-// if (annotations && annotations.length) {
-// let index = annotations.indexOf(this.props.document);
-// annotations.splice(index, 1);
-// this.props.parent.props.parent.Document.annotations = new List<Doc>(annotations);
-// }
-// // this._mainCont.current.childNodes.forEach(e => e.remove());
-// this._mainCont.current.style.display = "none";
-// // if (this._mainCont.current.parentElement) {
-// // this._mainCont.current.remove();
-// // }
-// }
-// e.stopPropagation();
-// }
-
-// render() {
-// let targetDoc = Cast(this.props.document.target, Doc);
-// if (targetDoc instanceof Doc) {
-// return (
-// <div className="pdfViewer-pinAnnotation" onPointerDown={this.pointerDown}
-// onDoubleClick={this.doubleClick} ref={this._mainCont}
-// style={{
-// top: this.props.y * scale - PinRadius / 2, left: this.props.x * scale - PinRadius / 2, width: PinRadius,
-// height: PinRadius, pointerEvents: "all", backgroundColor: this._backgroundColor
-// }}>
-// <div style={{
-// position: "absolute", top: "25px", left: "25px", transform: "scale(3)", transformOrigin: "top left",
-// display: this._display, width: targetDoc[WidthSym](), height: targetDoc[HeightSym]()
-// }}>
-// <DocumentView Document={targetDoc}
-// ContainingCollectionView={undefined}
-// ScreenToLocalTransform={this.props.parent.props.parent.props.ScreenToLocalTransform}
-// isTopMost={false}
-// ContentScaling={() => 1}
-// PanelWidth={() => NumCast(this.props.parent.props.parent.Document.nativeWidth)}
-// PanelHeight={() => NumCast(this.props.parent.props.parent.Document.nativeHeight)}
-// focus={emptyFunction}
-// selectOnLoad={false}
-// parentActive={this.props.parent.props.parent.props.active}
-// whenActiveChanged={this.props.parent.props.parent.props.whenActiveChanged}
-// bringToFront={emptyFunction}
-// addDocTab={this.props.parent.props.parent.props.addDocTab}
-// />
-// </div>
-// </div >
-// );
-// }
-// return null;
-// }
-// }
-
class RegionAnnotation extends React.Component<IAnnotationProps> {
@observable private _backgroundColor: string = "red";
@@ -553,15 +462,6 @@ class RegionAnnotation extends React.Component<IAnnotationProps> {
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) {
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index b6f362702..2b69bc47c 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 {
@@ -29,9 +30,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
@@ -178,6 +179,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
@@ -192,6 +205,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;
@@ -281,10 +295,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();
@@ -298,7 +313,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);
@@ -306,6 +321,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);
}