diff options
-rw-r--r-- | src/Utils.ts | 16 | ||||
-rw-r--r-- | src/client/documents/Documents.ts | 30 | ||||
-rw-r--r-- | src/client/views/PreviewCursor.tsx | 21 | ||||
-rw-r--r-- | src/client/views/collections/CollectionSubView.tsx | 59 |
4 files changed, 75 insertions, 51 deletions
diff --git a/src/Utils.ts b/src/Utils.ts index dba802f98..a01a94134 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -7,6 +7,22 @@ import { ColorState } from 'react-color'; export namespace Utils { export let DRAG_THRESHOLD = 4; + export function readUploadedFileAsText(inputFile: File) { + const temporaryFileReader = new FileReader(); + + return new Promise((resolve, reject) => { + temporaryFileReader.onerror = () => { + temporaryFileReader.abort(); + reject(new DOMException("Problem parsing input file.")); + }; + + temporaryFileReader.onload = () => { + resolve(temporaryFileReader.result); + }; + temporaryFileReader.readAsText(inputFile); + }); + } + export function GenerateGuid(): string { return v4(); } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 4c27cf47d..85da621e0 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1,5 +1,5 @@ import { runInAction } from "mobx"; -import { extname } from "path"; +import { extname, basename } from "path"; import { DateField } from "../../fields/DateField"; import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../fields/Doc"; import { HtmlField } from "../../fields/HtmlField"; @@ -48,6 +48,8 @@ import { PresElementBox } from "../views/presentationview/PresElementBox"; import { RecommendationsBox } from "../views/RecommendationsBox"; import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo"; import { DocumentType } from "./DocumentTypes"; +import { Networking } from "../Network"; +import { Upload } from "../../server/SharedMediaTypes"; const path = require('path'); export interface DocumentOptions { @@ -1104,6 +1106,32 @@ export namespace DocUtils { }); return optionsCollection; } + + export async function uploadFilesToDocs(files: File[], options: DocumentOptions) { + const generatedDocuments: Doc[] = []; + for (const { source: { name, type }, result } of await Networking.UploadFilesToServer(files)) { + if (result instanceof Error) { + alert(`Upload failed: ${result.message}`); + return []; + } + const full = { ...options, _width: 400, title: name }; + const pathname = Utils.prepend(result.accessPaths.agnostic.client); + const doc = await DocUtils.DocumentFromType(type, pathname, full); + if (!doc) { + continue; + } + const proto = Doc.GetProto(doc); + proto.text = result.rawText; + proto.fileUpload = basename(pathname).replace("upload_", "").replace(/\.[a-z0-9]*$/, ""); + if (Upload.isImageInformation(result)) { + proto["data-nativeWidth"] = (result.nativeWidth > result.nativeHeight) ? 400 * result.nativeWidth / result.nativeHeight : 400; + proto["data-nativeHeight"] = (result.nativeWidth > result.nativeHeight) ? 400 : 400 / (result.nativeWidth / result.nativeHeight); + proto.contentSize = result.contentSize; + } + generatedDocuments.push(doc); + } + return generatedDocuments; + } } Scripting.addGlobal("Docs", Docs); diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 1ab99881d..6583589f3 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -3,13 +3,18 @@ import { observer } from 'mobx-react'; import "normalize.css"; import * as React from 'react'; import "./PreviewCursor.scss"; -import { Docs } from '../documents/Documents'; +import { Docs, DocUtils } from '../documents/Documents'; import { Doc } from '../../fields/Doc'; import { Transform } from "../util/Transform"; import { DocServer } from '../DocServer'; -import { undoBatch } from '../util/UndoManager'; +import { undoBatch, UndoManager } from '../util/UndoManager'; import { NumCast } from '../../fields/Types'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; +import * as rp from 'request-promise'; +import { Utils } from '../../Utils'; +import { Networking } from '../Network'; +import { Upload } from '../../server/SharedMediaTypes'; +import { basename } from 'path'; @observer export class PreviewCursor extends React.Component<{}> { @@ -26,7 +31,7 @@ export class PreviewCursor extends React.Component<{}> { document.addEventListener("paste", this.paste); } - paste = (e: ClipboardEvent) => { + paste = async (e: ClipboardEvent) => { if (PreviewCursor.Visible && e.clipboardData) { const newPoint = PreviewCursor._getTransform().transformPoint(PreviewCursor._clickPoint[0], PreviewCursor._clickPoint[1]); runInAction(() => PreviewCursor.Visible = false); @@ -104,6 +109,16 @@ export class PreviewCursor extends React.Component<{}> { x: newPoint[0], y: newPoint[1], })))(); + } else if (e.clipboardData.items.length) { + const batch = UndoManager.StartBatch("collection view drop"); + const files: File[] = []; + for (let i = 0; i < e.clipboardData.items.length; i++) { + const file = e.clipboardData.items[i].getAsFile(); + file && files.push(file); + } + const generatedDocuments = await DocUtils.uploadFilesToDocs(files, { x: newPoint[0], y: newPoint[1] }); + generatedDocuments.forEach(PreviewCursor._addDocument); + batch.end(); } } } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 95c4898cc..ecd16d22f 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -238,21 +238,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: } return false; } - readUploadedFileAsText = (inputFile: File) => { - const temporaryFileReader = new FileReader(); - return new Promise((resolve, reject) => { - temporaryFileReader.onerror = () => { - temporaryFileReader.abort(); - reject(new DOMException("Problem parsing input file.")); - }; - - temporaryFileReader.onload = () => { - resolve(temporaryFileReader.result); - }; - temporaryFileReader.readAsText(inputFile); - }); - } @undoBatch @action protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions, completed?: () => void) { @@ -271,8 +257,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: e.stopPropagation(); e.preventDefault(); - const { addDocument } = this; - if (!addDocument) { + if (!this.addDocument) { alert("this.props.addDocument does not exist. Aborting drop operation."); return; } @@ -286,14 +271,14 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: DocServer.GetRefField(docid).then(f => { if (f instanceof Doc) { if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView - (f instanceof Doc) && addDocument(f); + (f instanceof Doc) && this.addDocument(f); } }); } else { - addDocument(Docs.Create.WebDocument(href, { ...options, title: href })); + this.addDocument(Docs.Create.WebDocument(href, { ...options, title: href })); } } else if (text) { - addDocument(Docs.Create.TextDocument(text, { ...options, _width: 100, _height: 25 })); + this.addDocument(Docs.Create.TextDocument(text, { ...options, _width: 100, _height: 25 })); } return; } @@ -313,7 +298,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: if (source.startsWith("http")) { const doc = Docs.Create.ImageDocument(source, { ...options, _width: 300 }); ImageUtils.ExtractExif(doc); - addDocument(doc); + this.addDocument(doc); } return; } else { @@ -360,7 +345,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: if (text) { if (text.includes("www.youtube.com/watch") || text.includes("www.youtube.com/embed")) { const url = text.replace("youtube.com/watch?v=", "youtube.com/embed/").split("&")[0]; - addDocument(Docs.Create.VideoDocument(url, { + this.addDocument(Docs.Create.VideoDocument(url, { ...options, title: url, _width: 400, @@ -413,10 +398,10 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: const file = item.getAsFile(); file?.type && files.push(file); - file?.type === "application/json" && this.readUploadedFileAsText(file).then(result => { + file?.type === "application/json" && Utils.readUploadedFileAsText(file).then(result => { console.log(result); const json = JSON.parse(result as string); - addDocument(Docs.Create.TreeDocument( + this.addDocument(Docs.Create.TreeDocument( json["rectangular-puzzle"].crossword.clues[0].clue.map((c: any) => { const label = Docs.Create.LabelDocument({ title: c["#text"], _width: 120, _height: 20 }); const proto = Doc.GetProto(label); @@ -428,38 +413,18 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: }); } } - for (const { source: { name, type }, result } of await Networking.UploadFilesToServer(files)) { - if (result instanceof Error) { - alert(`Upload failed: ${result.message}`); - return; - } - const full = { ...options, _width: 400, title: name }; - const pathname = Utils.prepend(result.accessPaths.agnostic.client); - const doc = await DocUtils.DocumentFromType(type, pathname, full); - if (!doc) { - continue; - } - const proto = Doc.GetProto(doc); - proto.text = result.rawText; - proto.fileUpload = basename(pathname).replace("upload_", "").replace(/\.[a-z0-9]*$/, ""); - if (Upload.isImageInformation(result)) { - proto["data-nativeWidth"] = (result.nativeWidth > result.nativeHeight) ? 400 * result.nativeWidth / result.nativeHeight : 400; - proto["data-nativeHeight"] = (result.nativeWidth > result.nativeHeight) ? 400 : 400 / (result.nativeWidth / result.nativeHeight); - proto.contentSize = result.contentSize; - } - generatedDocuments.push(doc); - } + generatedDocuments.push(...await DocUtils.uploadFilesToDocs(files, options)); if (generatedDocuments.length) { const set = generatedDocuments.length > 1 && generatedDocuments.map(d => DocUtils.iconify(d)); if (set) { - addDocument(DocUtils.pileup(generatedDocuments, options.x!, options.y!)!); + this.addDocument(DocUtils.pileup(generatedDocuments, options.x!, options.y!)!); } else { - generatedDocuments.forEach(addDocument); + generatedDocuments.forEach(this.addDocument); } completed?.(); } else { if (text && !text.includes("https://")) { - addDocument(Docs.Create.TextDocument(text, { ...options, _width: 400, _height: 315 })); + this.addDocument(Docs.Create.TextDocument(text, { ...options, _width: 400, _height: 315 })); } } batch.end(); |