From 8d774b6dd81d77294c438bb2951e04cf778dc38e Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 26 Jun 2020 00:40:49 -0400
Subject: fixed highlighting text anchors in text notes.  fixed pasting
 fragements of PDFs to create back links inside blockquotes.

---
 src/client/views/PreviewCursor.tsx | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'src/client/views/PreviewCursor.tsx')

diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index e27f6b95a..1ab99881d 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -9,6 +9,7 @@ import { Transform } from "../util/Transform";
 import { DocServer } from '../DocServer';
 import { undoBatch } from '../util/UndoManager';
 import { NumCast } from '../../fields/Types';
+import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
 
 @observer
 export class PreviewCursor extends React.Component<{}> {
@@ -81,6 +82,7 @@ export class PreviewCursor extends React.Component<{}> {
                     e.stopPropagation();
                 } else {
                     // creates text document
+                    FormattedTextBox.PasteOnLoad = e;
                     undoBatch(() => PreviewCursor._addLiveTextDoc(Docs.Create.TextDocument("", {
                         _width: 500,
                         limitHeight: 400,
-- 
cgit v1.2.3-70-g09d2


From a3ce7e180110df7e5908b93418b2dbff80aa89b5 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 1 Jul 2020 02:50:28 -0400
Subject: added pasting of snipped images (mac at least)

---
 src/Utils.ts                                       | 16 ++++++
 src/client/documents/Documents.ts                  | 30 ++++++++++-
 src/client/views/PreviewCursor.tsx                 | 21 ++++++--
 src/client/views/collections/CollectionSubView.tsx | 59 +++++-----------------
 4 files changed, 75 insertions(+), 51 deletions(-)

(limited to 'src/client/views/PreviewCursor.tsx')

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();
-- 
cgit v1.2.3-70-g09d2

