diff options
-rw-r--r-- | package-lock.json | 33 | ||||
-rw-r--r-- | package.json | 3 | ||||
-rw-r--r-- | src/client/util/DragManager.ts | 18 | ||||
-rw-r--r-- | src/client/views/nodes/PDFNode.tsx | 40 | ||||
-rw-r--r-- | src/fields/KeyStore.ts | 1 |
5 files changed, 67 insertions, 28 deletions
diff --git a/package-lock.json b/package-lock.json index 4c26734f6..b8f18acbc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3412,14 +3412,12 @@ "balanced-match": { "version": "1.0.0", "resolved": false, - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "optional": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "brace-expansion": { "version": "1.1.11", "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3434,20 +3432,17 @@ "code-point-at": { "version": "1.1.0", "resolved": false, - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "optional": true + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "concat-map": { "version": "0.0.1", "resolved": false, - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "optional": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "console-control-strings": { "version": "1.1.0", "resolved": false, - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "optional": true + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "core-util-is": { "version": "1.0.2", @@ -3564,8 +3559,7 @@ "inherits": { "version": "2.0.3", "resolved": false, - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "optional": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.5", @@ -3577,7 +3571,6 @@ "version": "1.0.0", "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3592,7 +3585,6 @@ "version": "3.0.4", "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3600,14 +3592,12 @@ "minimist": { "version": "0.0.8", "resolved": false, - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "optional": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "minipass": { "version": "2.3.5", "resolved": false, "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3626,7 +3616,6 @@ "version": "0.5.1", "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "optional": true, "requires": { "minimist": "0.0.8" } @@ -3707,8 +3696,7 @@ "number-is-nan": { "version": "1.0.1", "resolved": false, - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "optional": true + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "object-assign": { "version": "4.1.1", @@ -3720,7 +3708,6 @@ "version": "1.4.0", "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "optional": true, "requires": { "wrappy": "1" } @@ -3842,7 +3829,6 @@ "version": "1.0.2", "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4332,6 +4318,11 @@ "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", "dev": true }, + "html-to-image": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/html-to-image/-/html-to-image-0.1.0.tgz", + "integrity": "sha512-/VLH+jjGQgLDs+BlVDVAzI1rdghYfFWFcPmFHChiD3UHMmckyDuvJpH3N3lli0elJkWfyv/EKrWNXTxm3mg4oQ==" + }, "http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", diff --git a/package.json b/package.json index 7112d3672..271acfd0b 100644 --- a/package.json +++ b/package.json @@ -67,8 +67,8 @@ "@types/socket.io-client": "^1.4.32", "@types/typescript": "^2.0.0", "@types/uuid": "^3.4.4", - "babel-runtime": "^6.26.0", "@types/webpack": "^4.4.24", + "babel-runtime": "^6.26.0", "bcrypt-nodejs": "0.0.3", "bluebird": "^3.5.3", "body-parser": "^1.18.3", @@ -80,6 +80,7 @@ "expressjs": "^1.0.1", "flexlayout-react": "^0.3.3", "golden-layout": "^1.5.9", + "html-to-image": "^0.1.0", "i": "^0.3.6", "jsonwebtoken": "^8.4.0", "jsx-to-string": "^1.4.0", diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 60910a40b..63f5616a9 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -3,6 +3,8 @@ import { CollectionDockingView } from "../views/collections/CollectionDockingVie import { Document } from "../../fields/Document" import { action } from "mobx"; import { DocumentView } from "../views/nodes/DocumentView"; +import { ImageField } from "../../fields/ImageField"; +import { KeyStore } from "../../fields/KeyStore"; export function setupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc: () => Document) { let onRowMove = action((e: PointerEvent): void => { @@ -105,7 +107,19 @@ export namespace DragManager { const scaleX = rect.width / w, scaleY = rect.height / h; let x = rect.left, y = rect.top; // const offsetX = e.x - rect.left, offsetY = e.y - rect.top; - let dragElement = ele.cloneNode(true) as HTMLElement; + + // bcz: PDFs don't show up if you clone them -- presumably because they contain a canvas. + // however, PDF's have a thumbnail field that contains an image of the current page. + // so we use this image instead of the cloned element if it's present. + const docView: DocumentView = dragData["documentView"]; + const doc: Document = docView ? docView.props.Document : dragData["document"]; + let thumbnail = doc.GetT(KeyStore.Thumbnail, ImageField); + let img = thumbnail ? new Image() : null; + if (thumbnail) { + img!.src = thumbnail.toString(); + } + let dragElement = img ? img : ele.cloneNode(true) as HTMLElement; + dragElement.style.opacity = "0.7"; dragElement.style.position = "absolute"; dragElement.style.bottom = ""; @@ -140,8 +154,6 @@ export namespace DragManager { y += e.movementY; if (e.shiftKey) { abortDrag(); - const docView: DocumentView = dragData["documentView"]; - const doc: Document = docView ? docView.props.Document : dragData["document"]; CollectionDockingView.Instance.StartOtherDrag(doc, { pageX: e.pageX, pageY: e.pageY, preventDefault: () => { }, button: 0 }); } dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; diff --git a/src/client/views/nodes/PDFNode.tsx b/src/client/views/nodes/PDFNode.tsx index b80283065..0390d5e0d 100644 --- a/src/client/views/nodes/PDFNode.tsx +++ b/src/client/views/nodes/PDFNode.tsx @@ -1,4 +1,4 @@ -import { action, observable } from 'mobx'; +import { action, observable, _interceptReads } from 'mobx'; import { observer } from "mobx-react"; import Measure from "react-measure"; import 'react-image-lightbox/style.css'; @@ -15,6 +15,9 @@ import { KeyStore } from '../../../fields/KeyStore'; import "./PDFNode.scss"; import { PDFField } from '../../../fields/PDFField'; import { FieldWaiting } from '../../../fields/Field'; +import { ImageField } from '../../../fields/ImageField'; +import * as htmlToImage from "html-to-image"; +import { url } from 'inspector'; /** ALSO LOOK AT: Annotation.tsx, Sticky.tsx * This method renders PDF and puts all kinds of functionalities such as annotation, highlighting, @@ -94,6 +97,7 @@ export class PDFNode extends React.Component<FieldViewProps> { if (this.perPage[this.page - 1]) { this.pageInfo = this.perPage[this.page - 1]; } + this.saveThumbnail(); } } @@ -110,6 +114,7 @@ export class PDFNode extends React.Component<FieldViewProps> { if (this.perPage[this.page - 1]) { this.pageInfo = this.perPage[this.page - 1]; } + this.saveThumbnail(); } } @@ -288,7 +293,6 @@ export class PDFNode extends React.Component<FieldViewProps> { */ @action onPointerUp = (e: React.PointerEvent) => { - if (this._highlightToolOn) { this.highlight("rgba(76, 175, 80, 0.3)"); //highlights to this default color. this._highlightToolOn = false; @@ -314,7 +318,7 @@ export class PDFNode extends React.Component<FieldViewProps> { } this._toolOn = false; } - + this._interactive = true; } /** @@ -392,8 +396,23 @@ export class PDFNode extends React.Component<FieldViewProps> { } + @observable _interactive: boolean = false; @action + saveThumbnail = () => { + setTimeout(() => { + var me = this; + htmlToImage.toPng(this._mainDiv.current!, + { width: me.props.doc.GetNumber(KeyStore.NativeWidth, 0), height: me.props.doc.GetNumber(KeyStore.NativeHeight, 0), quality: 0.5 }) + .then(function (dataUrl: string) { + me.props.doc.SetData(KeyStore.Thumbnail, new URL(dataUrl), ImageField); + }) + .catch(function (error: any) { + console.error('oops, something went wrong!', error); + }); + }, 1000); + } + @action setScaling = (r: any) => { // bcz: the nativeHeight should really be set when the document is imported. // also, the native dimensions could be different for different pages of the PDF @@ -402,8 +421,23 @@ export class PDFNode extends React.Component<FieldViewProps> { if (!this.props.doc.GetNumber(KeyStore.NativeHeight, 0)) { this.props.doc.SetNumber(KeyStore.NativeHeight, nativeWidth * r.entry.height / r.entry.width); } + if (!this.props.doc.GetT(KeyStore.Thumbnail, ImageField)) { + this.saveThumbnail(); + } } render() { + let field = this.props.doc.Get(KeyStore.Thumbnail); + if (!this._interactive && field) { + let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : + field instanceof ImageField ? field.Data.href : "http://cs.brown.edu/people/bcz/prairie.jpg"; + return ( + <div className="pdfNode-cont" ref={this._mainDiv} + onPointerDown={this.onPointerDown} + onPointerUp={this.onPointerUp} + > + <img src={path} width="100%" /> + </div>); + } const renderHeight = 2400; let xf = this.props.doc.GetNumber(KeyStore.NativeHeight, 0) / renderHeight; var pdfUrl = this.props.doc.GetT(this.props.fieldKey, PDFField); diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index a3b39735d..1327bd9f4 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -26,4 +26,5 @@ export namespace KeyStore { export const Caption = new Key("Caption"); export const ActiveFrame = new Key("ActiveFrame"); export const DocumentText = new Key("DocumentText"); + export const Thumbnail = new Key("Thumbnail"); } |