aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.DS_Storebin0 -> 6148 bytes
-rw-r--r--src/Main.tsx14
-rw-r--r--src/Utils.ts2
-rw-r--r--src/documents/Documents.ts28
-rw-r--r--src/fields/ImageField.ts4
-rw-r--r--src/fields/PDFField.ts17
-rw-r--r--src/typings/index.d.ts322
-rw-r--r--src/views/nodes/ImageBox.tsx234
-rw-r--r--src/views/nodes/PDFBox.scss0
-rw-r--r--src/views/nodes/PDFBox.tsx102
-rw-r--r--src/views/nodes/Sticky.tsx90
11 files changed, 772 insertions, 41 deletions
diff --git a/src/.DS_Store b/src/.DS_Store
new file mode 100644
index 000000000..96930b780
--- /dev/null
+++ b/src/.DS_Store
Binary files differ
diff --git a/src/Main.tsx b/src/Main.tsx
index 6730cf799..dd8313ac1 100644
--- a/src/Main.tsx
+++ b/src/Main.tsx
@@ -14,6 +14,7 @@ import { ContextMenu } from './views/ContextMenu';
import { DocumentView } from './views/nodes/DocumentView';
import { CompileScript } from './util/Scripting';
+//pdf url: https://arxiv.org/pdf/1708.08021.pdf
configure({
enforceActions: "observed"
@@ -44,8 +45,12 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) {
doc2.Set(KS.X, new NumberField(150));
doc2.Set(KS.Y, new NumberField(20));
let doc3 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", {
- x: 450, y: 500, title: "cat 1"
+ x:0, y: 0, width: 500, height: 500,title: "cat 1"
});
+
+ //let PDFDoc = Documents.PDFDocument("https://arxiv.org/pdf/1708.08021.pdf", {
+ //x: 450, y: 500, title: "PDF!"
+ //})
// const schemaDocs = Array.from(Array(5).keys()).map(v => Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", {
// x: 50 + 100 * v, y: 50, width: 100, height: 100, title: "cat" + v
// }));
@@ -53,10 +58,14 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) {
// schemaDocs[4].SetData(KS.Author, "Bob", TextField);
// schemaDocs.push(doc2);
// const doc7 = Documents.SchemaDocument(schemaDocs)
- const docset = [doc3]; // [doc1, doc2, doc3, doc7];
+
+
+
+ const docset = [doc3]; //pdfDoc
let doc4 = Documents.CollectionDocument(docset, {
x: 0, y: 400, title: "mini collection"
});
+
// let doc5 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", {
// x: 650, y: 500, width: 600, height: 600, title: "cat 2"
// });
@@ -72,6 +81,7 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) {
// mainNodes.Data.push(doc2);
mainNodes.Data.push(doc4);
mainNodes.Data.push(doc3);
+ //mainNodes.Data.push(PDFDoc);
// mainNodes.Data.push(doc5);
// mainNodes.Data.push(doc1);
//mainNodes.Data.push(doc2);
diff --git a/src/Utils.ts b/src/Utils.ts
index cc1d8f6c6..e2b4309bb 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -19,4 +19,6 @@ export class Utils {
return { scale, translateX, translateY };
}
+
+ public static pdf_example = require('../deploy/test.pdf');
} \ No newline at end of file
diff --git a/src/documents/Documents.ts b/src/documents/Documents.ts
index 90124d36c..cca6f50e9 100644
--- a/src/documents/Documents.ts
+++ b/src/documents/Documents.ts
@@ -11,6 +11,8 @@ import { ImageField } from "../fields/ImageField";
import { ImageBox } from "../views/nodes/ImageBox";
import { CollectionFreeFormView } from "../views/collections/CollectionFreeFormView";
import { FIELD_ID } from "../fields/Field";
+import { PDFBox } from "../views/nodes/PDFBox";
+import { PDFField } from "../fields/PDFField";
interface DocumentOptions {
x?: number;
@@ -126,6 +128,32 @@ export namespace Documents {
return Server.GetDocument(imageProtoId, true)!;
}
+ let PDFProtoId: FIELD_ID;
+ function GetPDFPrototype(): Document {
+ if (PDFProtoId === undefined) {
+ let PDFProto = new Document();
+ PDFProtoId = PDFProto.Id;
+ PDFProto.Set(KeyStore.Title, new TextField("PDF PROTO"));
+ PDFProto.Set(KeyStore.X, new NumberField(0));
+ PDFProto.Set(KeyStore.Y, new NumberField(0));
+ PDFProto.Set(KeyStore.Width, new NumberField(300));
+ PDFProto.Set(KeyStore.Height, new NumberField(300));
+ PDFProto.Set(KeyStore.Layout, new TextField(PDFBox.LayoutString()));
+ PDFProto.Set(KeyStore.LayoutKeys, new ListField([KeyStore.Data]));
+ Server.AddDocument(PDFProto);
+ return PDFProto;
+ }
+ return Server.GetDocument(PDFProtoId, true)!;
+ }
+
+ export function PDFDocument(url: string, options: DocumentOptions = {}): Document{
+ let doc = GetPDFPrototype().MakeDelegate();
+ setupOptions(doc, options);
+ doc.Set(KeyStore.Data, new PDFField(new URL(url)));
+ Server.AddDocument(doc);
+ return Server.GetDocument(doc.Id, true);
+ }
+
export function ImageDocument(url: string, options: DocumentOptions = {}): Document {
let doc = GetImagePrototype().MakeDelegate();
setupOptions(doc, options);
diff --git a/src/fields/ImageField.ts b/src/fields/ImageField.ts
index bc2e7cdf4..b7470b657 100644
--- a/src/fields/ImageField.ts
+++ b/src/fields/ImageField.ts
@@ -1,5 +1,6 @@
import { BasicField } from "./BasicField";
import { Field } from "./Field";
+import {observable} from "mobx"
export class ImageField extends BasicField<URL> {
constructor(data: URL | undefined = undefined) {
@@ -13,5 +14,8 @@ export class ImageField extends BasicField<URL> {
Copy(): Field {
return new ImageField(this.Data);
}
+
+ @observable
+ Page:Number = 1;
} \ No newline at end of file
diff --git a/src/fields/PDFField.ts b/src/fields/PDFField.ts
new file mode 100644
index 000000000..fe74cd99e
--- /dev/null
+++ b/src/fields/PDFField.ts
@@ -0,0 +1,17 @@
+import { BasicField } from "./BasicField";
+import { Field } from "./Field";
+
+export class PDFField extends BasicField<URL> {
+ constructor(data: URL | undefined = undefined) {
+ super(data == undefined ? new URL("") : data);
+ }
+
+ toString(): string {
+ return this.Data.href;
+ }
+
+ Copy(): Field {
+ return new PDFField(this.Data);
+ }
+
+} \ No newline at end of file
diff --git a/src/typings/index.d.ts b/src/typings/index.d.ts
new file mode 100644
index 000000000..e4a66f7f2
--- /dev/null
+++ b/src/typings/index.d.ts
@@ -0,0 +1,322 @@
+/// <reference types="node" />
+
+declare module '@react-pdf/renderer' {
+ import * as React from 'react';
+
+ namespace ReactPDF {
+ interface Style {
+ [property: string]: any;
+ }
+ interface Styles {
+ [key: string]: Style;
+ }
+ type Orientation = 'portrait' | 'landscape';
+
+ interface DocumentProps {
+ title?: string;
+ author?: string;
+ subject?: string;
+ keywords?: string;
+ creator?: string;
+ producer?: string;
+ onRender?: () => any;
+ }
+
+ /**
+ * This component represent the PDF document itself. It must be the root
+ * of your tree element structure, and under no circumstances should it be
+ * used as children of another react-pdf component. In addition, it should
+ * only have childs of type <Page />.
+ */
+ class Document extends React.Component<DocumentProps> {}
+
+ interface NodeProps {
+ style?: Style | Style[];
+ /**
+ * Render component in all wrapped pages.
+ * @see https://react-pdf.org/advanced#fixed-components
+ */
+ fixed?: boolean;
+ /**
+ * Force the wrapping algorithm to start a new page when rendering the
+ * element.
+ * @see https://react-pdf.org/advanced#page-breaks
+ */
+ break?: boolean;
+ }
+
+ interface PageProps extends NodeProps {
+ /**
+ * Enable page wrapping for this page.
+ * @see https://react-pdf.org/components#page-wrapping
+ */
+ wrap?: boolean;
+ debug?: boolean;
+ size?: string | [number, number] | {width: number; height: number};
+ orientation?: Orientation;
+ ruler?: boolean;
+ rulerSteps?: number;
+ verticalRuler?: boolean;
+ verticalRulerSteps?: number;
+ horizontalRuler?: boolean;
+ horizontalRulerSteps?: number;
+ ref?: Page;
+ }
+
+ /**
+ * Represents single page inside the PDF document, or a subset of them if
+ * using the wrapping feature. A <Document /> can contain as many pages as
+ * you want, but ensure not rendering a page inside any component besides
+ * Document.
+ */
+ class Page extends React.Component<PageProps> {}
+
+ interface ViewProps extends NodeProps {
+ /**
+ * Enable/disable page wrapping for element.
+ * @see https://react-pdf.org/components#page-wrapping
+ */
+ wrap?: boolean;
+ debug?: boolean;
+ render?: (props: {pageNumber: number}) => React.ReactNode;
+ children?: React.ReactNode;
+ }
+
+ /**
+ * The most fundamental component for building a UI and is designed to be
+ * nested inside other views and can have 0 to many children.
+ */
+ class View extends React.Component<ViewProps> {}
+
+ interface ImageProps extends NodeProps {
+ debug?: boolean;
+ src: string | {data: Buffer; format: 'png' | 'jpg'};
+ cache?: boolean;
+ }
+
+ /**
+ * A React component for displaying network or local (Node only) JPG or
+ * PNG images, as well as base64 encoded image strings.
+ */
+ class Image extends React.Component<ImageProps> {}
+
+ interface TextProps extends NodeProps {
+ /**
+ * Enable/disable page wrapping for element.
+ * @see https://react-pdf.org/components#page-wrapping
+ */
+ wrap?: boolean;
+ debug?: boolean;
+ render?: (
+ props: {pageNumber: number; totalPages: number},
+ ) => React.ReactNode;
+ children?: React.ReactNode;
+ /**
+ * How much hyphenated breaks should be avoided.
+ */
+ hyphenationCallback?: number;
+ }
+
+ /**
+ * A React component for displaying text. Text supports nesting of other
+ * Text or Link components to create inline styling.
+ */
+ class Text extends React.Component<TextProps> {}
+
+ interface LinkProps extends NodeProps {
+ /**
+ * Enable/disable page wrapping for element.
+ * @see https://react-pdf.org/components#page-wrapping
+ */
+ wrap?: boolean;
+ debug?: boolean;
+ src: string;
+ children?: React.ReactNode;
+ }
+
+ /**
+ * A React component for displaying an hyperlink. Link’s can be nested
+ * inside a Text component, or being inside any other valid primitive.
+ */
+ class Link extends React.Component<LinkProps> {}
+
+ interface NoteProps extends NodeProps {
+ children: string;
+ }
+
+ class Note extends React.Component<NoteProps> {}
+
+ interface BlobProviderParams {
+ blob: Blob | null;
+ url: string | null;
+ loading: boolean;
+ error: Error | null;
+ }
+ interface BlobProviderProps {
+ document: React.ReactElement<DocumentProps>;
+ children: (params: BlobProviderParams) => React.ReactNode;
+ }
+
+ /**
+ * Easy and declarative way of getting document's blob data without
+ * showing it on screen.
+ * @see https://react-pdf.org/advanced#on-the-fly-rendering
+ * @platform web
+ */
+ class BlobProvider extends React.Component<BlobProviderProps> {}
+
+ interface PDFViewerProps {
+ width?: number;
+ height?: number;
+ style?: Style | Style[];
+ className?: string;
+ children?: React.ReactElement<DocumentProps>;
+ }
+
+ /**
+ * Iframe PDF viewer for client-side generated documents.
+ * @platform web
+ */
+ class PDFViewer extends React.Component<PDFViewerProps> {}
+
+ interface PDFDownloadLinkProps {
+ document: React.ReactElement<DocumentProps>;
+ fileName?: string;
+ style?: Style | Style[];
+ className?: string;
+ children?:
+ | React.ReactNode
+ | ((params: BlobProviderParams) => React.ReactNode);
+ }
+
+ /**
+ * Anchor tag to enable generate and download PDF documents on the fly.
+ * @see https://react-pdf.org/advanced#on-the-fly-rendering
+ * @platform web
+ */
+ class PDFDownloadLink extends React.Component<PDFDownloadLinkProps> {}
+
+ interface EmojiSource {
+ url: string;
+ format: string;
+ }
+ interface RegisteredFont {
+ src: string;
+ loaded: boolean;
+ loading: boolean;
+ data: any;
+ [key: string]: any;
+ }
+ type HyphenationCallback = (
+ words: string[],
+ glyphString: {[key: string]: any},
+ ) => string[];
+
+ const Font: {
+ register: (
+ src: string,
+ options: {family: string; [key: string]: any},
+ ) => void;
+ getEmojiSource: () => EmojiSource;
+ getRegisteredFonts: () => string[];
+ registerEmojiSource: (emojiSource: EmojiSource) => void;
+ registerHyphenationCallback: (
+ hyphenationCallback: HyphenationCallback,
+ ) => void;
+ getHyphenationCallback: () => HyphenationCallback;
+ getFont: (fontFamily: string) => RegisteredFont | undefined;
+ load: (
+ fontFamily: string,
+ document: React.ReactElement<DocumentProps>,
+ ) => Promise<void>;
+ clear: () => void;
+ reset: () => void;
+ };
+
+ const StyleSheet: {
+ hairlineWidth: number;
+ create: <TStyles>(styles: TStyles) => TStyles;
+ resolve: (
+ style: Style,
+ container: {
+ width: number;
+ height: number;
+ orientation: Orientation;
+ },
+ ) => Style;
+ flatten: (...styles: Style[]) => Style;
+ absoluteFillObject: {
+ position: 'absolute';
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ };
+ };
+
+ const version: any;
+
+ const PDFRenderer: any;
+
+ const createInstance: (
+ element: {
+ type: string;
+ props: {[key: string]: any};
+ },
+ root?: any,
+ ) => any;
+
+ const pdf: (
+ document: React.ReactElement<DocumentProps>,
+ ) => {
+ isDirty: () => boolean;
+ updateContainer: (document: React.ReactElement<any>) => void;
+ toBuffer: () => NodeJS.ReadableStream;
+ toBlob: () => Blob;
+ toString: () => string;
+ };
+
+ const renderToStream: (
+ document: React.ReactElement<DocumentProps>,
+ ) => NodeJS.ReadableStream;
+
+ const renderToFile: (
+ document: React.ReactElement<DocumentProps>,
+ filePath: string,
+ callback?: (output: NodeJS.ReadableStream, filePath: string) => any,
+ ) => Promise<NodeJS.ReadableStream>;
+
+ const render: typeof renderToFile;
+ }
+
+ const Document: typeof ReactPDF.Document;
+ const Page: typeof ReactPDF.Page;
+ const View: typeof ReactPDF.View;
+ const Image: typeof ReactPDF.Image;
+ const Text: typeof ReactPDF.Text;
+ const Link: typeof ReactPDF.Link;
+ const Note: typeof ReactPDF.Note;
+ const Font: typeof ReactPDF.Font;
+ const StyleSheet: typeof ReactPDF.StyleSheet;
+ const createInstance: typeof ReactPDF.createInstance;
+ const PDFRenderer: typeof ReactPDF.PDFRenderer;
+ const version: typeof ReactPDF.version;
+ const pdf: typeof ReactPDF.pdf;
+
+ export default ReactPDF;
+ export {
+ Document,
+ Page,
+ View,
+ Image,
+ Text,
+ Link,
+ Note,
+ Font,
+ StyleSheet,
+ createInstance,
+ PDFRenderer,
+ version,
+ pdf,
+ };
+ } \ No newline at end of file
diff --git a/src/views/nodes/ImageBox.tsx b/src/views/nodes/ImageBox.tsx
index 123c76d19..2f7cbbcc4 100644
--- a/src/views/nodes/ImageBox.tsx
+++ b/src/views/nodes/ImageBox.tsx
@@ -10,15 +10,29 @@ import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView
import { FieldWaiting } from '../../fields/Field';
import { observer } from "mobx-react"
import { observable, action } from 'mobx';
+import 'react-pdf/dist/Page/AnnotationLayer.css'
+//@ts-ignore
+import { Document, Page, PDFPageProxy, PageAnnotation} from "react-pdf";
+import { Utils } from '../../Utils';
+import { any } from 'prop-types';
+import { Sticky } from './Sticky';
@observer
export class ImageBox extends React.Component<FieldViewProps> {
public static LayoutString() { return FieldView.LayoutString("ImageBox"); }
+
private _ref: React.RefObject<HTMLDivElement>;
+
+ private _mainDiv = React.createRef<HTMLDivElement>()
+
private _downX: number = 0;
private _downY: number = 0;
private _lastTap: number = 0;
+
+ @observable
+ private stickies:any[] = []
+
@observable private _photoIndex: number = 0;
@observable private _isOpen: boolean = false;
@@ -38,55 +52,197 @@ export class ImageBox extends React.Component<FieldViewProps> {
componentWillUnmount() {
}
- onPointerDown = (e: React.PointerEvent): void => {
- if (Date.now() - this._lastTap < 300) {
- if (e.buttons === 1 && this.props.DocumentViewForField instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(this.props.DocumentViewForField)) {
- e.stopPropagation();
- this._downX = e.clientX;
- this._downY = e.clientY;
- document.removeEventListener("pointerup", this.onPointerUp);
- document.addEventListener("pointerup", this.onPointerUp);
- }
- } else {
- this._lastTap = Date.now();
+
+
+ @action
+ onPageBack = () => {
+ if (this.page > 1){
+ this.page -= 1;
+ this.stickies = this.stickiesPerPage[this.page - 1];
}
}
+
@action
- onPointerUp = (e: PointerEvent): void => {
- document.removeEventListener("pointerup", this.onPointerUp);
- if (Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2) {
- this._isOpen = true;
+ onPageForward = () => {
+ if (this.page < this.numPage){
+ this.page += 1;
+ this.stickies = this.stickiesPerPage[this.page - 1];
}
- e.stopPropagation();
}
- lightbox = (path: string) => {
- const images = [path, "http://www.cs.brown.edu/~bcz/face.gif"];
- if (this._isOpen && this.props.DocumentViewForField instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(this.props.DocumentViewForField)) {
- return (<Lightbox
- mainSrc={images[this._photoIndex]}
- nextSrc={images[(this._photoIndex + 1) % images.length]}
- prevSrc={images[(this._photoIndex + images.length - 1) % images.length]}
- onCloseRequest={() => this.setState({ isOpen: false })}
- onMovePrevRequest={action(() =>
- this._photoIndex = (this._photoIndex + images.length - 1) % images.length
- )}
- onMoveNextRequest={action(() =>
- this._photoIndex = (this._photoIndex + 1) % images.length
- )}
- />)
+
+ @observable
+ searchText:string = '';
+
+ @observable
+ page:number = 1; //default is the first page.
+
+ @observable
+ numPage:number = 1; //default number of pages
+
+ @observable
+ stickiesPerPage: any = [...Array(this.numPage)].map(() => Array(1)); //makes 2d array for storage
+
+ private textContent:any = null;
+
+ private initX:number = 0;
+ private initY:number = 0;
+
+ private _toolOn:boolean = false;
+
+
+ selectionTool = () => {
+ this._toolOn = true;
+ }
+
+ private _highlighter:boolean = false;
+
+
+ onPointerDown = (e: React.PointerEvent) => {
+
+ if (this._toolOn){
+ let mouse = e.nativeEvent;
+ this.initX = mouse.offsetX;
+ this.initY = mouse.offsetY;
+ }
+ if (this._highlighter){
+
}
}
- render() {
- let field = this.props.doc.Get(this.props.fieldKey);
- let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" :
- field instanceof ImageField ? field.Data.href : "http://www.cs.brown.edu/~bcz/face.gif";
+ makeEditableAndHighlight = (colour:string) => {
+ var range, sel = window.getSelection();
+ if (sel.rangeCount && sel.getRangeAt) {
+ range = sel.getRangeAt(0);
+ }
+ document.designMode = "on";
+ if (range) {
+ sel.removeAllRanges();
+ sel.addRange(range);
+ }
+ if (!document.execCommand("HiliteColor", false, colour)) {
+ document.execCommand("HIliteColor", false, colour);
+ }
+ document.designMode = "off";
+ }
+
+
+ highlight = (colour:string) => {
+ var range, sel;
+ if (window.getSelection()) {
+ try {
+ console.log(document.getSelection())
+
+
+ if (!document.execCommand("HiliteColor", false, colour)) {
+ this.makeEditableAndHighlight(colour);
+ } else if (document.execCommand("HiliteColor", false, "rgba(76, 175, 80, 0.3)")) {
+ this.makeEditableAndHighlight("black");
+ }
+ } catch (ex) {
+ this.makeEditableAndHighlight(colour)
+ }
+
+ }
+ }
+
+ @action
+ onPointerUp = (e:React.PointerEvent) => {
+ this.highlight("rgba(76, 175, 80, 0.3)");
+
+ if (this._toolOn){
+
+ let mouse = e.nativeEvent;
+ let finalX = mouse.offsetX;
+ let finalY = mouse.offsetY;
+ let width = Math.abs(finalX - this.initX);
+ let height = Math.abs(finalY - this.initY);
+
+ if (this._mainDiv.current){
+ let sticky = <Sticky key ={Utils.GenerateGuid()}Height = {height} Width = {width} X = {this.initX} Y = {this.initY}/>
+ this.stickies.push(sticky);
+ //this.stickiesPerPage[this.page - 1].push(sticky);
+ }
+
+ this._toolOn = false;
+ }
+
+ }
+
+
+ displaySticky = () => {
+ try{
+ this.stickies.filter( () => {
+ return this.stickies[this.stickies.length - 1]
+ }).map( (element: any) => {
+ return element
+ })
+ } catch (ex) {
+ console.log(ex); //should be null
+ }
+ }
+ render() {
return (
- <div className="imageBox-cont" onPointerDown={this.onPointerDown} ref={this._ref} >
- <img src={path} width="100%" alt="Image not found" />
- {this.lightbox(path)}
- </div>)
+ <div ref = {this._mainDiv}
+ onPointerDown ={this.onPointerDown}
+ onPointerUp = {this.onPointerUp}
+ >
+ { this.stickies.filter( () => {
+ return this.stickies[this.stickies.length - 1]
+ }).map( (element: any) => {
+ return element
+ })
+ }
+
+
+
+ }
+ }
+
+
+ <button onClick = {this.onPageBack}>{"<"}</button>
+ <button onClick = {this.onPageForward}>{">"}</button>
+ <button onClick ={this.selectionTool}>{"Area"}</button>
+ <Document
+ file={Utils.pdf_example}
+
+ onLoadError={
+ (error: any) => {
+ console.log(error);
+ }
+ }
+ >
+ <Page
+ pageNumber={this.page}
+
+ onLoadSuccess={
+ (page: PDFPageProxy) => {
+ page.getTextContent().then((obj:any) => {
+ this.textContent = obj
+ });
+ this.numPage = page.transport.numPages
+
+ }
+ }
+
+ onGetAnnotationSuccess = {
+ (anno: any) => {
+ console.log(anno)
+ }
+ }
+
+
+
+ />
+
+
+
+
+ </Document>
+
+
+ </div>
+ );
}
} \ No newline at end of file
diff --git a/src/views/nodes/PDFBox.scss b/src/views/nodes/PDFBox.scss
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/views/nodes/PDFBox.scss
diff --git a/src/views/nodes/PDFBox.tsx b/src/views/nodes/PDFBox.tsx
new file mode 100644
index 000000000..6d881d530
--- /dev/null
+++ b/src/views/nodes/PDFBox.tsx
@@ -0,0 +1,102 @@
+import Lightbox from 'react-image-lightbox';
+import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
+import { SelectionManager } from "../../util/SelectionManager";
+import "./ImageBox.scss";
+import React = require("react")
+import { PDFField } from '../../fields/PDFField';
+import { FieldViewProps, FieldView } from './FieldView';
+import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView';
+import { FieldWaiting } from '../../fields/Field';
+import { observer } from "mobx-react"
+
+const {PdfLoader,
+ PdfHighlighter,
+ Tip,
+ Highlight,
+ Popup,
+ Spinner,
+ AreaHighlight} = require( "react-pdf-highlighter" )
+
+import { observable, action } from 'mobx';
+
+@observer
+export class PDFBox extends React.Component<FieldViewProps> {
+
+ public static LayoutString() { return FieldView.LayoutString("ImageBox"); }
+ private _ref: React.RefObject<HTMLDivElement>;
+ private _downX: number = 0;
+ private _downY: number = 0;
+ private _lastTap: number = 0;
+ @observable private _photoIndex: number = 0;
+ @observable private _isOpen: boolean = false;
+
+ constructor(props: FieldViewProps) {
+ super(props);
+
+ this._ref = React.createRef();
+ this.state = {
+ photoIndex: 0,
+ isOpen: false,
+
+ };
+ }
+
+ componentDidMount() {
+ }
+
+ componentWillUnmount() {
+ }
+
+ onPointerDown = (e: React.PointerEvent): void => {
+ if (Date.now() - this._lastTap < 300) {
+ if (e.buttons === 1 && this.props.DocumentViewForField instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(this.props.DocumentViewForField)) {
+ e.stopPropagation();
+ this._downX = e.clientX;
+
+ this._downY = e.clientY;
+ document.removeEventListener("pointerup", this.onPointerUp);
+ document.addEventListener("pointerup", this.onPointerUp);
+ }
+ } else {
+ this._lastTap = Date.now();
+ }
+ }
+ @action
+ onPointerUp = (e: PointerEvent): void => {
+ document.removeEventListener("pointerup", this.onPointerUp);
+ if (Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2) {
+ this._isOpen = true;
+ }
+ e.stopPropagation();
+ }
+
+ lightbox = (path: string) => {
+ const images = [path, "http://www.cs.brown.edu/~bcz/face.gif"];
+ if (this._isOpen && this.props.DocumentViewForField instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(this.props.DocumentViewForField)) {
+ return (<Lightbox
+ mainSrc={images[this._photoIndex]}
+ nextSrc={images[(this._photoIndex + 1) % images.length]}
+ prevSrc={images[(this._photoIndex + images.length - 1) % images.length]}
+ onCloseRequest={() => this.setState({ isOpen: false })}
+ onMovePrevRequest={action(() =>
+ this._photoIndex = (this._photoIndex + images.length - 1) % images.length
+ )}
+ onMoveNextRequest={action(() =>
+ this._photoIndex = (this._photoIndex + 1) % images.length
+ )}
+ />)
+ }
+ }
+
+ render() {
+ let field = this.props.doc.Get(this.props.fieldKey);
+ let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" :
+ field instanceof PDFField ? field.Data.href : "http://www.cs.brown.edu/~bcz/face.gif";
+
+ return (
+ <div className="imageBox-cont" onPointerDown={this.onPointerDown} ref={this._ref} >
+ <PdfLoader url={"https://arxiv.org/pdf/1708.08021.pdf"}/>
+
+ </div>)
+ }
+} \ No newline at end of file
diff --git a/src/views/nodes/Sticky.tsx b/src/views/nodes/Sticky.tsx
new file mode 100644
index 000000000..254c410c2
--- /dev/null
+++ b/src/views/nodes/Sticky.tsx
@@ -0,0 +1,90 @@
+import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
+import { SelectionManager } from "../../util/SelectionManager";
+import "./ImageBox.scss";
+import React = require("react")
+import { FieldViewProps, FieldView } from './FieldView';
+import { observer } from "mobx-react"
+import { observable, action } from 'mobx';
+import 'react-pdf/dist/Page/AnnotationLayer.css'
+//@ts-ignore
+import { Document, Page, PDFPageProxy, PageAnnotation} from "react-pdf";
+import { Utils } from '../../Utils';
+
+
+interface IProps{
+ Height:number;
+ Width:number;
+ X:number;
+ Y:number;
+}
+
+
+
+@observer
+export class Sticky extends React.Component<IProps> {
+
+
+ private initX:number = 0;
+ private initY:number = 0;
+
+ private _ref = React.createRef<HTMLCanvasElement>();
+ private ctx:any;
+
+
+
+ drawDown = (e:React.PointerEvent) => {
+ if (this._ref.current){
+ this.ctx = this._ref.current.getContext("2d");
+ let mouse = e.nativeEvent;
+ this.initX = mouse.offsetX;
+ this.initY = mouse.offsetY;
+
+ //do thiiissss
+ this.ctx.lineWidth;
+
+ this.ctx.beginPath();
+ this.ctx.lineTo(this.initX, this.initY);
+ this.ctx.strokeStyle = "black";
+
+ document.addEventListener("pointermove", this.drawMove);
+ document.addEventListener("pointerup", this.drawUp);
+ }
+ }
+
+ //when user drags
+ drawMove = (e: PointerEvent):void =>{
+ //x and y mouse movement
+ let x = this.initX += e.movementX,
+ y = this.initY += e.movementY;
+ //connects the point
+ this.ctx.lineTo(x, y);
+ this.ctx.stroke();
+ }
+
+ drawUp = (e:PointerEvent) => {
+ this.ctx.closePath();
+ document.removeEventListener("pointermove", this.drawMove);
+ }
+
+
+
+ render() {
+ return (
+ <div onPointerDown = {this.drawDown}>
+ <canvas ref = {this._ref} height = {this.props.Height} width = {this.props.Width}
+
+ style = {{position:"absolute",
+ top: "20px",
+ left: "0px",
+ zIndex: 1,
+ background: "yellow",
+ transform: `translate(${this.props.X}px, ${this.props.Y}px)`,
+ opacity: 0.4
+ }}
+
+ />
+
+ </div>
+ );
+ }
+} \ No newline at end of file