From 28efd6f2b5b79d1f25fa66e5d9f69d77a7594fee Mon Sep 17 00:00:00 2001
From: vellichora <fangrui_tong@brown.edu>
Date: Sat, 8 Feb 2020 20:48:51 -0500
Subject: refactored mobile interface so that current views are created via
 scripting

---
 src/mobile/ImageUpload.tsx | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

(limited to 'src/mobile/ImageUpload.tsx')

diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
index 0b0280519..3304e8e22 100644
--- a/src/mobile/ImageUpload.tsx
+++ b/src/mobile/ImageUpload.tsx
@@ -13,6 +13,7 @@ import { observable } from 'mobx';
 import { Utils } from '../Utils';
 import MobileInterface from './MobileInterface';
 import { CurrentUserUtils } from '../server/authentication/models/current_user_utils';
+import { Scripting } from '../client/util/Scripting';
 
 
 
@@ -27,12 +28,11 @@ const inputRef = React.createRef<HTMLInputElement>();
 
 @observer
 class Uploader extends React.Component {
-    @observable
-    error: string = "";
-    @observable
-    status: string = "";
+    @observable error: string = "";
+    @observable status: string = "";
 
     onClick = async () => {
+        console.log("uploader click");
         try {
             this.status = "initializing protos";
             await Docs.Prototypes.initialize();
@@ -105,6 +105,8 @@ class Uploader extends React.Component {
 
 }
 
+// Scripting.addGlobal(function uploadImageMobile() { return Uploader.onClick(); });
+
 
 // DocServer.init(window.location.protocol, window.location.hostname, 4321, "image upload");
 (async () => {
-- 
cgit v1.2.3-70-g09d2


From e8fcbbf57b2a2f443d9c280ce10558cf9d51c632 Mon Sep 17 00:00:00 2001
From: vellichora <fangrui_tong@brown.edu>
Date: Sun, 9 Feb 2020 17:11:24 -0500
Subject: can upload collection from mobile to desktop

---
 src/client/DocServer.ts                            |   9 +-
 src/client/util/DragManager.ts                     |   2 +-
 .../collections/CollectionMasonryViewFieldRow.tsx  |   1 +
 .../views/collections/CollectionStackingView.tsx   |   2 +
 .../CollectionStackingViewFieldColumn.tsx          |   1 +
 src/client/views/collections/CollectionSubView.tsx |   2 +-
 src/client/views/collections/CollectionView.tsx    |   2 +-
 .../views/collections/CollectionViewChromes.tsx    |   1 +
 src/mobile/ImageUpload.tsx                         |   1 +
 src/mobile/MobileInkOverlay.tsx                    |  53 +++++++-
 src/mobile/MobileInterface.scss                    |   8 ++
 src/mobile/MobileInterface.tsx                     | 150 ++++++++++++---------
 src/server/ApiManagers/UploadManager.ts            |   1 +
 src/server/Message.ts                              |   6 +
 src/server/Websocket/Websocket.ts                  |   7 +-
 .../authentication/models/current_user_utils.ts    |  21 +--
 src/server/server_Initialization.ts                |  24 ++--
 17 files changed, 195 insertions(+), 96 deletions(-)

(limited to 'src/mobile/ImageUpload.tsx')

diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index c03764471..e09251855 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -1,5 +1,5 @@
 import * as OpenSocket from 'socket.io-client';
-import { MessageStore, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent } from "./../server/Message";
+import { MessageStore, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent } from "./../server/Message";
 import { Opt, Doc } from '../new_fields/Doc';
 import { Utils, emptyFunction } from '../Utils';
 import { SerializationHelper } from './util/SerializationHelper';
@@ -81,6 +81,10 @@ export namespace DocServer {
             Utils.Emit(_socket, MessageStore.UpdateMobileInkOverlayPosition, content);
         }
 
+        export function dispatchMobileDocumentUpload(content: MobileDocumentUploadContent) {
+            Utils.Emit(_socket, MessageStore.MobileDocumentUpload, content);
+        }
+
     }
 
     export function init(protocol: string, hostname: string, port: number, identifier: string) {
@@ -116,6 +120,9 @@ export namespace DocServer {
         _socket.addEventListener("receiveUpdateOverlayPosition", (content: UpdateMobileInkOverlayPositionContent) => {
             MobileInkOverlay.Instance.updatePosition(content);
         });
+        _socket.addEventListener("receiveMobileDocumentUpload", (content: MobileDocumentUploadContent) => {
+            MobileInkOverlay.Instance.uploadDocument(content);
+        });
     }
 
     function errorFunc(): never {
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index df2f5fe3c..0bb8b531d 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -179,7 +179,7 @@ export namespace DragManager {
             );
         }
         element.dataset.canDrop = "true";
-        const handler = (e: Event) => dropFunc(e, (e as CustomEvent<DropEvent>).detail);
+        const handler = (e: Event) => { console.log("drop target reveied docs"); dropFunc(e, (e as CustomEvent<DropEvent>).detail); };
         element.addEventListener("dashOnDrop", handler);
         return () => {
             element.removeEventListener("dashOnDrop", handler);
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 80752303c..26e0cc35a 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -73,6 +73,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
 
     @undoBatch
     rowDrop = action((e: Event, de: DragManager.DropEvent) => {
+        console.log("masronry row drop");
         this._createAliasSelected = false;
         if (de.complete.docDragData) {
             (this.props.parent.Document.dropConverter instanceof ScriptField) &&
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 992820fc7..83c90810e 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -240,6 +240,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @undoBatch
     @action
     drop = (e: Event, de: DragManager.DropEvent) => {
+        console.log("DROP STACKIN G2");
         const where = [de.x, de.y];
         let targInd = -1;
         let plusOne = 0;
@@ -270,6 +271,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @undoBatch
     @action
     onDrop = async (e: React.DragEvent): Promise<void> => {
+        console.log("DROP STACKING");
         const where = [e.clientX, e.clientY];
         let targInd = -1;
         this._docXfs.map((cd, i) => {
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 39b4e4e1d..65c4b3195 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -57,6 +57,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
 
     @undoBatch
     columnDrop = action((e: Event, de: DragManager.DropEvent) => {
+        console.log("column drop stacking");
         this._createAliasSelected = false;
         if (de.complete.docDragData) {
             const key = StrCast(this.props.parent.props.Document.sectionFilter);
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index e94f24f2c..b35af2314 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -6,7 +6,7 @@ import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
 import { ScriptField } from "../../../new_fields/ScriptField";
-import { Cast } from "../../../new_fields/Types";
+import { Cast, StrCast } from "../../../new_fields/Types";
 import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
 import { Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 88023783b..1d399e26f 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -138,7 +138,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
         let index = value.reduce((p, v, i) => (v instanceof Doc && v === doc) ? i : p, -1);
         index = index !== -1 ? index : value.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, doc)) ? i : p, -1);
 
-        ContextMenu.Instance.clearItems();
+        ContextMenu.Instance && ContextMenu.Instance.clearItems();
         if (index !== -1) {
             value.splice(index, 1);
             return true;
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index a870b6043..01dc21f95 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -231,6 +231,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
 
     @action
     toggleCollapse = () => {
+        console.log("toggle collapse");
         this.props.CollectionView.props.Document.chromeStatus = this.props.CollectionView.props.Document.chromeStatus === "enabled" ? "collapsed" : "enabled";
         if (this.props.collapse) {
             this.props.collapse(this.props.CollectionView.props.Document.chromeStatus !== "enabled");
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
index 3304e8e22..10bd78075 100644
--- a/src/mobile/ImageUpload.tsx
+++ b/src/mobile/ImageUpload.tsx
@@ -47,6 +47,7 @@ class Uploader extends React.Component {
 
                     const upload = window.location.origin + "/upload";
                     this.status = "uploading image";
+                    console.log("uploading image", formData);
                     const res = await fetch(upload, {
                         method: 'POST',
                         body: formData
diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx
index 6b65aa436..ed4cca5b9 100644
--- a/src/mobile/MobileInkOverlay.tsx
+++ b/src/mobile/MobileInkOverlay.tsx
@@ -1,9 +1,13 @@
 import React = require('react');
 import { observer } from "mobx-react";
-import { MobileInkOverlayContent, GestureContent, UpdateMobileInkOverlayPositionContent } from "../server/Message";
+import { MobileInkOverlayContent, GestureContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent } from "../server/Message";
 import { observable, action } from "mobx";
 import { GestureUtils } from "../pen-gestures/GestureUtils";
 import "./MobileInkOverlay.scss";
+import { StrCast } from '../new_fields/Types';
+import { DragManager } from "../client/util/DragManager";
+import { DocServer } from '../client/DocServer';
+import { Doc } from '../new_fields/Doc';
 
 
 @observer
@@ -67,7 +71,7 @@ export default class MobileInkOverlay extends React.Component {
             height: bounds.height * this._scale,
         };
 
-        const target = document.elementFromPoint(points[0].X, points[0].Y);
+        const target = document.elementFromPoint(this._x + 10, this._y + 10);
         target?.dispatchEvent(
             new CustomEvent<GestureUtils.GestureEvent>("dashOnGesture",
                 {
@@ -82,6 +86,43 @@ export default class MobileInkOverlay extends React.Component {
         );
     }
 
+    uploadDocument = async (content: MobileDocumentUploadContent) => {
+        const { docId } = content;
+        console.log("receive upload document id", docId);
+        const doc = await DocServer.GetRefField(docId);
+
+        if (doc && doc instanceof Doc) {
+            console.log("parsed upload document into doc", StrCast(doc.proto!.title));
+
+            const target = document.elementFromPoint(this._x + 10, this._y + 10);
+            console.log("the target is", target);
+
+            const dragData = new DragManager.DocumentDragData([doc]);
+            const complete = new DragManager.DragCompleteEvent(false, dragData);
+            console.log("the drag data is", dragData);
+
+            if (target) {
+                target.dispatchEvent(
+                    new CustomEvent<DragManager.DropEvent>("dashOnDrop",
+                        {
+                            bubbles: true,
+                            detail: {
+                                x: this._x,
+                                y: this._y,
+                                complete: complete,
+                                altKey: false,
+                                metaKey: false,
+                                ctrlKey: false
+                            }
+                        }
+                    )
+                );
+            } else {
+                alert("TARGET IS UNDEFINED");
+            }
+        }
+    }
+
     @action
     dragStart = (e: React.PointerEvent) => {
         document.removeEventListener("pointermove", this.dragging);
@@ -132,15 +173,17 @@ export default class MobileInkOverlay extends React.Component {
                     transform: `translate(${this._x}px, ${this._y}px)`,
                     zIndex: 30000,
                     pointerEvents: "none",
-                    borderStyle: this._isDragging ? "solid" : "dashed"
-                }}
+                    borderStyle: this._isDragging ? "solid" : "dashed",
+                    backgroundColor: "rgba(255, 0, 0, 0.3)"
+                }
+                }
                 ref={this._mainCont}
             >
                 <div className="mobileInkOverlay-border top" onPointerDown={this.dragStart}></div>
                 <div className="mobileInkOverlay-border bottom" onPointerDown={this.dragStart}></div>
                 <div className="mobileInkOverlay-border left" onPointerDown={this.dragStart}></div>
                 <div className="mobileInkOverlay-border right" onPointerDown={this.dragStart}></div>
-            </div>
+            </div >
         );
     }
 }
\ No newline at end of file
diff --git a/src/mobile/MobileInterface.scss b/src/mobile/MobileInterface.scss
index 8abe5a40d..8b0ebcd53 100644
--- a/src/mobile/MobileInterface.scss
+++ b/src/mobile/MobileInterface.scss
@@ -1,7 +1,15 @@
 .mobileInterface-inkInterfaceButtons {
     position: absolute;
+    top: -50px;
     display: flex;
     justify-content: space-between;
     width: 100%;
     z-index: 9999;
+    height: 50px;
+}
+
+.mobileInterface-container {
+    height: calc(100% - 50px);
+    margin-top: 50px;
+    position: relative;
 }
\ No newline at end of file
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 665d9a168..a1ef0a5d1 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -22,6 +22,18 @@ import { SelectionManager } from '../client/util/SelectionManager';
 import { DateField } from '../new_fields/DateField';
 import { GestureUtils } from '../pen-gestures/GestureUtils';
 import { DocServer } from '../client/DocServer';
+import { DocumentDecorations } from '../client/views/DocumentDecorations';
+import { OverlayView } from '../client/views/OverlayView';
+import { DictationOverlay } from '../client/views/DictationOverlay';
+import SharingManager from '../client/util/SharingManager';
+import { PreviewCursor } from '../client/views/PreviewCursor';
+import { ContextMenu } from '../client/views/ContextMenu';
+import { RadialMenu } from '../client/views/nodes/RadialMenu';
+import PDFMenu from '../client/views/pdf/PDFMenu';
+import MarqueeOptionsMenu from '../client/views/collections/collectionFreeForm/MarqueeOptionsMenu';
+import GoogleAuthenticationManager from '../client/apis/GoogleAuthenticationManager';
+import { listSpec } from '../new_fields/Schema';
+import { Id } from '../new_fields/FieldSymbols';
 
 library.add(faLongArrowAltLeft);
 
@@ -31,7 +43,7 @@ export default class MobileInterface extends React.Component {
     @computed private get userDoc() { return CurrentUserUtils.UserDocument; }
     @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeMobile, Doc)) : CurrentUserUtils.GuestMobile; }
     // @observable private currentView: "main" | "ink" | "upload" = "main";
-    private mainDoc: Doc = CurrentUserUtils.setupMobileDoc(this.userDoc);
+    private mainDoc: any = CurrentUserUtils.setupMobileDoc(this.userDoc);
     @observable private renderView?: () => JSX.Element;
 
     // private inkDoc?: Doc;
@@ -49,7 +61,6 @@ export default class MobileInterface extends React.Component {
         library.add(...[faPenNib, faHighlighter, faEraser, faMousePointer]);
 
         if (this.userDoc && !this.mainContainer) {
-            // const doc = CurrentUserUtils.setupMobileDoc(this.userDoc);
             this.userDoc.activeMobile = this.mainDoc;
         }
     }
@@ -76,48 +87,22 @@ export default class MobileInterface extends React.Component {
         });
     }
 
-    // @action
-    // switchCurrentView = (view: "main" | "ink" | "upload") => {
-    //     this.currentView = view;
-
-    //     if (this.userDoc) {
-    //         switch (view) {
-    //             case "main": {
-    //                 // const doc = CurrentUserUtils.setupMobileDoc(this.userDoc);
-    //                 this.userDoc.activeMobile = this.mainDoc;
-    //                 break;
-    //             }
-    //             case "ink": {
-    //                 this.inkDoc = CurrentUserUtils.setupMobileInkingDoc(this.userDoc);
-    //                 this.userDoc.activeMobile = this.inkDoc;
-    //                 InkingControl.Instance.switchTool(InkTool.Pen);
-    //                 this.drawingInk = true;
-
-    //                 DocServer.Mobile.dispatchOverlayTrigger({
-    //                     enableOverlay: true,
-    //                     width: window.innerWidth,
-    //                     height: window.innerHeight
-    //                 });
-
-    //                 break;
-    //             }
-    //             case "upload": {
-    //                 this.uploadDoc = CurrentUserUtils.setupMobileUploadDoc(this.userDoc);
-    //                 this.userDoc.activeMobile = this.uploadDoc;
-
-    //             }
-    //         }
-    //     }
-    // }
+    onSwitchUpload = () => {
+        DocServer.Mobile.dispatchOverlayTrigger({
+            enableOverlay: true,
+            width: 100,
+            height: 100
+        });
+    }
 
     renderDefaultContent = () => {
-        console.log("rendering default content");
+        console.log("rendering default content", this.mainContainer);
         if (this.mainContainer) {
             return <DocumentView
                 Document={this.mainContainer}
                 DataDoc={undefined}
                 LibraryPath={emptyPath}
-                addDocument={returnFalse}
+                addDocument={(doc: Doc) => { console.log("want to add doc to default content", StrCast(doc.title)); return false; }}
                 addDocTab={returnFalse}
                 pinToPres={emptyFunction}
                 removeDocument={undefined}
@@ -192,42 +177,54 @@ export default class MobileInterface extends React.Component {
                             <button className="mobileInterface-button" onClick={this.shiftRight} title="Shift right">right</button>
                         </div>
                     </div>
-                    <GestureOverlay>
-                        <CollectionView
-                            Document={this.mainContainer}
-                            DataDoc={undefined}
-                            LibraryPath={emptyPath}
-                            fieldKey={""}
-                            addDocTab={returnFalse}
-                            pinToPres={emptyFunction}
-                            PanelHeight={() => window.innerHeight}
-                            PanelWidth={() => window.innerWidth}
-                            focus={emptyFunction}
-                            isSelected={returnFalse}
-                            select={emptyFunction}
-                            active={returnFalse}
-                            ContentScaling={returnOne}
-                            whenActiveChanged={returnFalse}
-                            ScreenToLocalTransform={Transform.Identity}
-                            ruleProvider={undefined}
-                            renderDepth={0}
-                            ContainingCollectionView={undefined}
-                            ContainingCollectionDoc={undefined}>
-                        </CollectionView>
-                    </GestureOverlay>
+                    <CollectionView
+                        Document={this.mainContainer}
+                        DataDoc={undefined}
+                        LibraryPath={emptyPath}
+                        fieldKey={""}
+                        addDocTab={returnFalse}
+                        pinToPres={emptyFunction}
+                        PanelHeight={() => window.innerHeight}
+                        PanelWidth={() => window.innerWidth}
+                        focus={emptyFunction}
+                        isSelected={returnFalse}
+                        select={emptyFunction}
+                        active={returnFalse}
+                        ContentScaling={returnOne}
+                        whenActiveChanged={returnFalse}
+                        ScreenToLocalTransform={Transform.Identity}
+                        ruleProvider={undefined}
+                        renderDepth={0}
+                        ContainingCollectionView={undefined}
+                        ContainingCollectionDoc={undefined}>
+                    </CollectionView>
                 </div>
             );
         }
     }
 
-    upload = () => {
+    upload = async (e: React.MouseEvent) => {
+        if (this.mainContainer) {
+            const data = Cast(this.mainContainer.data, listSpec(Doc));
+            if (data) {
+                const uploadDoc = await data[1]; // TODO: ensure this is the collection to upload
 
+                console.log("UPLOADING DOCUMENT FROM MOBILE", uploadDoc[Id], StrCast(uploadDoc.proto!.title));
+                if (uploadDoc) {
+                    DocServer.Mobile.dispatchMobileDocumentUpload({
+                        docId: uploadDoc[Id]
+                    });
+                }
+            }
+        }
+        e.stopPropagation();
+        e.preventDefault();
     }
 
     renderUploadContent() {
         if (this.mainContainer) {
             return (
-                <div className="mobileInterface">
+                <div className="mobileInterface" onDragOver={this.onDragOver}>
                     <div className="mobileInterface-inkInterfaceButtons">
                         <div className="navButtons">
                             <button className="mobileInterface-button cancel" onClick={this.onBack} title="Back">BACK</button>
@@ -240,7 +237,7 @@ export default class MobileInterface extends React.Component {
                         Document={this.mainContainer}
                         DataDoc={undefined}
                         LibraryPath={emptyPath}
-                        addDocument={returnFalse}
+                        addDocument={(doc: Doc) => { console.log("want to add doc", StrCast(doc.title)); return false; }}
                         addDocTab={returnFalse}
                         pinToPres={emptyFunction}
                         removeDocument={undefined}
@@ -266,13 +263,35 @@ export default class MobileInterface extends React.Component {
         }
     }
 
+    onDragOver = (e: React.DragEvent) => {
+        e.preventDefault();
+        e.stopPropagation();
+    }
+
     render() {
         // const content = this.currentView === "main" ? this.mainContent :
         //     this.currentView === "ink" ? this.inkContent :
         //         this.currentView === "upload" ? this.uploadContent : <></>;
         return (
-            <div className="mobile-container">
-                {this.renderView ? this.renderView() : this.renderDefaultContent()}
+            <div className="mobileInterface-container" onDragOver={this.onDragOver}>
+                {/* <DocumentDecorations />
+                <GestureOverlay>
+                    {this.renderView ? this.renderView() : this.renderDefaultContent()}
+                </GestureOverlay> */}
+
+                {/* <DictationOverlay />
+                <SharingManager />
+                <GoogleAuthenticationManager /> */}
+                <DocumentDecorations />
+                <GestureOverlay>
+                    {this.renderView ? this.renderView() : this.renderDefaultContent()}
+                </GestureOverlay>
+                <PreviewCursor />
+                {/* <ContextMenu /> */}
+                <RadialMenu />
+                {/* <PDFMenu />
+                <MarqueeOptionsMenu />
+                <OverlayView /> */}
             </div>
         );
     }
@@ -281,5 +300,6 @@ export default class MobileInterface extends React.Component {
 Scripting.addGlobal(function switchMobileView(doc: (userDoc: Doc) => Doc, renderView?: () => JSX.Element, onSwitch?: () => void) { return MobileInterface.Instance.switchCurrentView(doc, renderView, onSwitch); });
 Scripting.addGlobal(function onSwitchMobileInking() { return MobileInterface.Instance.onSwitchInking(); });
 Scripting.addGlobal(function renderMobileInking() { return MobileInterface.Instance.renderInkingContent(); });
+Scripting.addGlobal(function onSwitchMobileUpload() { return MobileInterface.Instance.onSwitchUpload(); });
 Scripting.addGlobal(function renderMobileUpload() { return MobileInterface.Instance.renderUploadContent(); });
 
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index 74f45ae62..e76d9b7a2 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -42,6 +42,7 @@ export default class UploadManager extends ApiManager {
             method: Method.POST,
             subscription: "/upload",
             secureHandler: async ({ req, res }) => {
+                console.log("/upload register");
                 const form = new formidable.IncomingForm();
                 form.uploadDir = pathToDirectory(Directory.parsed_files);
                 form.keepExtensions = true;
diff --git a/src/server/Message.ts b/src/server/Message.ts
index 236df3f3c..c23a2f0a8 100644
--- a/src/server/Message.ts
+++ b/src/server/Message.ts
@@ -1,5 +1,6 @@
 import { Utils } from "../Utils";
 import { Point } from "../pen-gestures/ndollar";
+import { Doc } from "../new_fields/Doc";
 
 export class Message<T> {
     private _name: string;
@@ -62,6 +63,10 @@ export interface UpdateMobileInkOverlayPositionContent {
     readonly dsize?: number;
 }
 
+export interface MobileDocumentUploadContent {
+    readonly docId: string;
+}
+
 export namespace MessageStore {
     export const Foo = new Message<string>("Foo");
     export const Bar = new Message<string>("Bar");
@@ -75,6 +80,7 @@ export namespace MessageStore {
     export const GesturePoints = new Message<GestureContent>("Gesture Points");
     export const MobileInkOverlayTrigger = new Message<MobileInkOverlayContent>("Trigger Mobile Ink Overlay");
     export const UpdateMobileInkOverlayPosition = new Message<UpdateMobileInkOverlayPositionContent>("Update Mobile Ink Overlay Position");
+    export const MobileDocumentUpload = new Message<MobileDocumentUploadContent>("Upload Document From Mobile");
 
     export const GetRefField = new Message<string>("Get Ref Field");
     export const GetRefFields = new Message<string[]>("Get Ref Fields");
diff --git a/src/server/Websocket/Websocket.ts b/src/server/Websocket/Websocket.ts
index 77816c897..798bdae67 100644
--- a/src/server/Websocket/Websocket.ts
+++ b/src/server/Websocket/Websocket.ts
@@ -1,5 +1,5 @@
 import { Utils } from "../../Utils";
-import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent } from "../Message";
+import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent } from "../Message";
 import { Client } from "../Client";
 import { Socket } from "socket.io";
 import { Database } from "../database";
@@ -57,6 +57,7 @@ export namespace WebSocket {
             Utils.AddServerHandler(socket, MessageStore.GesturePoints, content => processGesturePoints(socket, content));
             Utils.AddServerHandler(socket, MessageStore.MobileInkOverlayTrigger, content => processOverlayTrigger(socket, content));
             Utils.AddServerHandler(socket, MessageStore.UpdateMobileInkOverlayPosition, content => processUpdateOverlayPosition(socket, content));
+            Utils.AddServerHandler(socket, MessageStore.MobileDocumentUpload, content => processMobileDocumentUpload(socket, content));
             Utils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField);
             Utils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields);
 
@@ -83,6 +84,10 @@ export namespace WebSocket {
         socket.broadcast.emit("receiveUpdateOverlayPosition", content);
     }
 
+    function processMobileDocumentUpload(socket: Socket, content: MobileDocumentUploadContent) {
+        socket.broadcast.emit("receiveMobileDocumentUpload", content);
+    }
+
     function HandleYoutubeQuery([query, callback]: [YoutubeQueryInput, (result?: any[]) => void]) {
         const { ProjectCredentials } = GoogleCredentialsLoader;
         switch (query.type) {
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 817cf40b1..3e5953ac1 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -103,7 +103,7 @@ export class CurrentUserUtils {
             { title: "use scrubber", icon: "eraser", click: 'activateScrubber(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "green", activePen: doc },
             { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc },
             { title: "draw", icon: "pen-nib", click: 'switchMobileView(setupMobileInkingDoc, renderMobileInking, onSwitchMobileInking);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "red", activePen: doc },
-            { title: "upload", icon: "upload", click: 'switchMobileView(setupMobileUploadDoc, renderMobileUpload);', backgroundColor: "orange" },
+            { title: "upload", icon: "upload", click: 'switchMobileView(setupMobileUploadDoc, renderMobileUpload, onSwitchMobileUpload);', backgroundColor: "orange" },
             { title: "upload", icon: "upload", click: 'uploadImageMobile();', backgroundColor: "cyan" },
         ];
         return docProtoData.filter(d => !buttons || !buttons.includes(d.title)).map(data => Docs.Create.FontIconDocument({
@@ -138,7 +138,9 @@ export class CurrentUserUtils {
     }
 
     static setupMobileDoc(userDoc: Doc) {
-        return userDoc.activeMoble ?? Docs.Create.MasonryDocument(CurrentUserUtils.setupMobileButtons(userDoc), {
+        const webDoc = Docs.Create.WebDocument("https://wikipedia.com", { title: "Mobile Upload Web", chromeStatus: "enabled" });
+
+        return userDoc.activeMoble ?? Docs.Create.MasonryDocument([webDoc, ...CurrentUserUtils.setupMobileButtons(userDoc)], {
             columnWidth: 100, ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", title: "buttons", autoHeight: true, yMargin: 5
         });
     }
@@ -148,13 +150,14 @@ export class CurrentUserUtils {
     }
 
     static setupMobileUploadDoc(userDoc: Doc) {
-        console.log("setup mobile upload", window.innerWidth, window.innerHeight);
-        const webDoc = Docs.Create.WebDocument("https://wikipedia.com", { title: "Mobile Upload Web", chromeStatus: "enabled" });
-        const uploadDoc = Docs.Create.StackingDocument([], { title: "Mobile Upload", backgroundColor: "pink" });
-        return Docs.Create.StackingDocument([webDoc, uploadDoc], {
-            title: "Mobile Upload", backgroundColor: "white",
-            columnWidth: window.innerWidth, ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", autoHeight: true, yMargin: 5,
-            width: window.innerWidth, height: window.innerHeight
+        const webDoc = Docs.Create.WebDocument("https://yahoo.com", { title: "Upload Images From the Web", chromeStatus: "enabled" });
+        const uploadDoc = Docs.Create.StackingDocument([], { title: "Mobile Upload Collection", backgroundColor: "pink" });
+        console.log("window size", window.innerWidth, window.innerHeight);
+        // return Docs.Create.StackingDocument([webDoc, uploadDoc], {
+        //     columnWidth: window.innerWidth, //ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", title: "Mobile Upload", autoHeight: true, yMargin: 5
+        // });
+        return Docs.Create.StackingDocument([webDoc, uploadDoc], {//...CurrentUserUtils.setupMobileButtons(userDoc)], {
+            columnWidth: 100, lockedPosition: true, chromeStatus: "disabled", title: "Upload", autoHeight: true, yMargin: 30
         });
     }
 
diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts
index cbe070293..5f1ecc733 100644
--- a/src/server/server_Initialization.ts
+++ b/src/server/server_Initialization.ts
@@ -42,18 +42,18 @@ export default async function InitializeServer(routeSetter: RouteSetter) {
         }
     };
     app.use(cors(corsOptions));
-    app.use("*", ({ user, originalUrl }, res, next) => {
-        if (user && !originalUrl.includes("Heartbeat")) {
-            const userEmail = (user as any).email;
-            if (userEmail) {
-                timeMap[userEmail] = Date.now();
-            }
-        }
-        if (!user && originalUrl === "/") {
-            return res.redirect("/login");
-        }
-        next();
-    });
+    // app.use("*", ({ user, originalUrl }, res, next) => {
+    //     if (user && !originalUrl.includes("Heartbeat")) {
+    //         const userEmail = (user as any).email;
+    //         if (userEmail) {
+    //             timeMap[userEmail] = Date.now();
+    //         }
+    //     }
+    //     if (!user && originalUrl === "/") {
+    //         return res.redirect("/login");
+    //     }
+    //     next();
+    // });
 
     app.use(wdm(compiler, { publicPath: config.output.publicPath }));
     app.use(whm(compiler));
-- 
cgit v1.2.3-70-g09d2


From 74ca8ac01e32faa8adab54ddfd806fe46cda03ec Mon Sep 17 00:00:00 2001
From: Hannah <hannah_chow@brown.edu>
Date: Tue, 11 Feb 2020 06:22:04 -0500
Subject: refined upload interaction

---
 src/client/util/DragManager.ts                     |  21 ++--
 src/client/views/nodes/WebBox.scss                 |  15 +++
 src/client/views/nodes/WebBox.tsx                  | 130 ++++++++++-----------
 src/mobile/ImageUpload.tsx                         |   2 -
 src/mobile/MobileInkOverlay.scss                   |   4 +-
 src/mobile/MobileInkOverlay.tsx                    |  35 +++---
 src/mobile/MobileInterface.scss                    |   7 +-
 src/mobile/MobileInterface.tsx                     |  42 ++++---
 src/server/Message.ts                              |   2 +-
 .../authentication/models/current_user_utils.ts    |  25 ++--
 10 files changed, 146 insertions(+), 137 deletions(-)

(limited to 'src/mobile/ImageUpload.tsx')

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 745540ff9..702c10910 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -195,7 +195,7 @@ export namespace DragManager {
                     dragData.userDropAction === "alias" || (!dragData.userDropAction && dragData.dropAction === "alias") ? Doc.MakeAlias(d) :
                         dragData.userDropAction === "copy" || (!dragData.userDropAction && dragData.dropAction === "copy") ? Doc.MakeCopy(d, true) : d)
             );
-            e.docDragData?.droppedDocuments.forEach((drop: Doc, i: number) =>
+            e.docDragData ?.droppedDocuments.forEach((drop: Doc, i: number) =>
                 Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec("string"), []).map(prop => drop[prop] = undefined));
         };
         dragData.draggedDocuments.map(d => d.dragFactory); // does this help?  trying to make sure the dragFactory Doc is loaded
@@ -288,6 +288,7 @@ export namespace DragManager {
             if (!ele.parentNode) dragDiv.appendChild(ele);
             const dragElement = ele.parentNode === dragDiv ? ele : ele.cloneNode(true) as HTMLElement;
             const rect = ele.getBoundingClientRect();
+            console.log("boudning", rect);
             const scaleX = rect.width / ele.offsetWidth,
                 scaleY = rect.height / ele.offsetHeight;
             xs.push(rect.left);
@@ -305,7 +306,7 @@ export namespace DragManager {
             dragElement.style.transformOrigin = "0 0";
             dragElement.style.borderRadius = getComputedStyle(ele).borderRadius;
             dragElement.style.zIndex = globalCssVariables.contextMenuZindex;// "1000";
-            dragElement.style.transform = `translate(${rect.left + (options?.offsetX || 0)}px, ${rect.top + (options?.offsetY || 0)}px) scale(${scaleX}, ${scaleY})`;
+            dragElement.style.transform = `translate(${rect.left + (options ?.offsetX || 0)}px, ${rect.top + (options ?.offsetY || 0)}px) scale(${scaleX}, ${scaleY})`;
             dragElement.style.width = `${rect.width / scaleX}px`;
             dragElement.style.height = `${rect.height / scaleY}px`;
 
@@ -334,8 +335,8 @@ export namespace DragManager {
             return dragElement;
         });
 
-        const hideSource = options?.hideSource ? true : false;
-        eles.map(ele => ele.parentElement && ele.parentElement?.className === dragData.dragDivName ? (ele.parentElement.hidden = hideSource) : (ele.hidden = hideSource));
+        const hideSource = options ?.hideSource ? true : false;
+        eles.map(ele => ele.parentElement && ele.parentElement ?.className === dragData.dragDivName ? (ele.parentElement.hidden = hideSource) : (ele.hidden = hideSource));
 
         let lastX = downX;
         let lastY = downY;
@@ -346,7 +347,7 @@ export namespace DragManager {
             }
             if (e.shiftKey && CollectionDockingView.Instance) {
                 AbortDrag();
-                finishDrag?.(new DragCompleteEvent(true, dragData));
+                finishDrag ?.(new DragCompleteEvent(true, dragData));
                 CollectionDockingView.Instance.StartOtherDrag({
                     pageX: e.pageX,
                     pageY: e.pageY,
@@ -360,13 +361,13 @@ export namespace DragManager {
             lastX = e.pageX;
             lastY = e.pageY;
             dragElements.map((dragElement, i) => (dragElement.style.transform =
-                `translate(${(xs[i] += moveX) + (options?.offsetX || 0)}px, ${(ys[i] += moveY) + (options?.offsetY || 0)}px)  scale(${scaleXs[i]}, ${scaleYs[i]})`)
+                `translate(${(xs[i] += moveX) + (options ?.offsetX || 0)}px, ${(ys[i] += moveY) + (options ?.offsetY || 0)}px)  scale(${scaleXs[i]}, ${scaleYs[i]})`)
             );
         };
 
         const hideDragShowOriginalElements = () => {
             dragElements.map(dragElement => dragElement.parentNode === dragDiv && dragDiv.removeChild(dragElement));
-            eles.map(ele => ele.parentElement && ele.parentElement?.className === dragData.dragDivName ? (ele.parentElement.hidden = false) : (ele.hidden = false));
+            eles.map(ele => ele.parentElement && ele.parentElement ?.className === dragData.dragDivName ? (ele.parentElement.hidden = false) : (ele.hidden = false));
         };
         const endDrag = () => {
             document.removeEventListener("pointermove", moveHandler, true);
@@ -376,14 +377,14 @@ export namespace DragManager {
         AbortDrag = () => {
             hideDragShowOriginalElements();
             SelectionManager.SetIsDragging(false);
-            options?.dragComplete?.(new DragCompleteEvent(true, dragData));
+            options ?.dragComplete ?.(new DragCompleteEvent(true, dragData));
             endDrag();
         };
         const upHandler = (e: PointerEvent) => {
             hideDragShowOriginalElements();
             dispatchDrag(eles, e, dragData, options, finishDrag);
             SelectionManager.SetIsDragging(false);
-            options?.dragComplete?.(new DragCompleteEvent(false, dragData));
+            options ?.dragComplete ?.(new DragCompleteEvent(false, dragData));
             endDrag();
         };
         document.addEventListener("pointermove", moveHandler, true);
@@ -404,7 +405,7 @@ export namespace DragManager {
         });
         if (target) {
             const complete = new DragCompleteEvent(false, dragData);
-            finishDrag?.(complete);
+            finishDrag ?.(complete);
 
             target.dispatchEvent(
                 new CustomEvent<DropEvent>("dashOnDrop", {
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index fbe9bf063..226103a53 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -90,4 +90,19 @@
     width: 100%;
     margin-right: 10px;
     height: 100%;
+}
+
+.touch-iframe-overlay {
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    pointer-events: all;
+
+    .indicator {
+        position: absolute;
+
+        &.active {
+            background-color: rgba(0, 0, 0, 0.1);
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index c405dd9d4..ee5bf6f2f 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -39,6 +39,7 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
 
     private _longPressSecondsHack?: NodeJS.Timeout;
     private _iframeRef = React.createRef<HTMLIFrameElement>();
+    private _iframeIndicatorRef = React.createRef<HTMLDivElement>();
     private _iframeDragRef = React.createRef<HTMLDivElement>();
     @observable private _pressX: number = 0;
     @observable private _pressY: number = 0;
@@ -63,39 +64,6 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
     componentDidMount() {
         document.addEventListener("pointerup", this.onLongPressUp);
         document.addEventListener("pointermove", this.onLongPressMove);
-        // this._iframeRef.current?.contentWindow?.document.addEventListener("mousedown", (event: MouseEvent) => {
-        //     console.log("clicked inside the iframe?");
-        // });
-        // const iframe = document.getElementById(this.props.Document.proto![Id]);
-        // if (iframe) {
-        //     iframe.addEventListener('pointerdown', function (event) {
-        //         const B = iframe.getBoundingClientRect();
-        //         const e = new CustomEvent('pointerdown', { bubbles: true, cancelable: false });
-        //         // e.clientX = e.clientX + B?.left;
-        //         // e.clientY = e.clientY + B?.top;
-        //         console.log("custom event pointer down");
-        //         iframe.dispatchEvent(e);
-        //     })
-        // }
-        // if (this._iframeRef.current) {
-        //     console.log("resetting iframes events");
-        //     const self = this;
-        //     this._iframeRef.current.addEventListener('pointermove', function (event) {
-        //         const B = self._iframeRef.current?.getBoundingClientRect();
-        //         const e = new CustomEvent('pointermove', { bubbles: true, cancelable: false });
-        //         // e.clientX = e.clientX + B?.left;
-        //         // e.clientY = e.clientY + B?.top;
-        //         self._iframeRef.current?.dispatchEvent(e);
-        //     });
-        //     this._iframeRef.current.addEventListener('pointerdown', function (event) {
-        //         const B = self._iframeRef.current?.getBoundingClientRect();
-        //         const e = new CustomEvent('pointerdown', { bubbles: true, cancelable: false });
-        //         // e.clientX = e.clientX + B?.left;
-        //         // e.clientY = e.clientY + B?.top;
-        //         console.log("custom event pointer down");
-        //         self._iframeRef.current?.dispatchEvent(e);
-        //     })
-        // }
     }
 
     componentWillUnmount() {
@@ -217,59 +185,75 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
         }
     }
 
-    // TODO: make this actually a long press
     onLongPressDown = (e: React.PointerEvent) => {
-
-        console.log("press down", e.clientX, e.clientX);
         this._pressX = e.clientX;
         this._pressY = e.clientY;
-        this._longPressSecondsHack = setTimeout(() => {
-            console.log("start the drag!!");
-            const B = this._iframeRef.current?.getBoundingClientRect();
-            const iframeDoc = this._iframeRef.current?.contentDocument;
+
+        // find the pressed element in the iframe (currently only works if its an img)
+        let pressedElement: HTMLElement | undefined;
+        let pressedBound: ClientRect | undefined;
+        if (this._iframeRef.current) {
+            const B = this._iframeRef.current.getBoundingClientRect();
+            const iframeDoc = this._iframeRef.current.contentDocument;
             if (B && iframeDoc) {
-                console.log("frame doc", iframeDoc);
-                console.log("get point", this._pressX, B.left, this._pressY, B.top);
+                // TODO: this only works when scale = 1
                 const element = iframeDoc.elementFromPoint(this._pressX - B.left, this._pressY - B.top);
-                console.log("found element", element);
-                if (element) {
-                    e.stopPropagation();
-                    e.preventDefault();
-                    const clone = element.cloneNode(true) as HTMLElement;
-
-                    if (clone.nodeName === "IMG") {
-                        const src = clone.getAttribute("src"); // TODO: may not always work
-
-                        if (src) {
-                            const doc = Docs.Create.ImageDocument(src, { width: 300 });
-                            ImageUtils.ExtractExif(doc);
-
-                            console.log("start image drag", this._pressX, this._pressY, doc);
-                            // document.dispatchEvent()
-                            const dragData = new DragManager.DocumentDragData([doc]);
-                            DragManager.StartDocumentDrag([clone], dragData, this._pressX, this._pressY);
-                        }
+                if (element && element.nodeName === "IMG") {
+                    pressedBound = element.getBoundingClientRect();
+                    pressedElement = element.cloneNode(true) as HTMLElement;
+                }
+            }
+        }
+
+        // mark the pressed element
+        if (pressedElement && pressedBound) {
+            console.log("clones b", pressedElement.getBoundingClientRect(), pressedBound);
+            if (this._iframeIndicatorRef.current) {
+                this._iframeIndicatorRef.current.style.top = pressedBound.top + "px";
+                this._iframeIndicatorRef.current.style.left = pressedBound.left + "px";
+                this._iframeIndicatorRef.current.style.width = pressedBound.width + "px";
+                this._iframeIndicatorRef.current.style.height = pressedBound.height + "px";
+                this._iframeIndicatorRef.current.classList.add("active");
+            }
+        }
+
+        // start dragging the pressed element if long pressed
+        this._longPressSecondsHack = setTimeout(() => {
+            if (pressedElement && pressedBound) {
+                e.stopPropagation();
+                e.preventDefault();
+                if (pressedElement.nodeName === "IMG") {
+                    const src = pressedElement.getAttribute("src"); // TODO: may not always work
+                    if (src) {
+                        const doc = Docs.Create.ImageDocument(src, { width: 300 });
+                        ImageUtils.ExtractExif(doc);
+
+                        // add clone to div so that dragging ghost is placed properly
+                        if (this._iframeDragRef.current) this._iframeDragRef.current.appendChild(pressedElement);
+
+                        const dragData = new DragManager.DocumentDragData([doc]);
+                        DragManager.StartDocumentDrag([pressedElement], dragData, this._pressX, this._pressY, { hideSource: true });
                     }
                 }
             }
         }, 1500);
-        // e.stopPropagation();
-        // e.preventDefault();
     }
 
     onLongPressMove = (e: PointerEvent) => {
-        this._pressX = e.clientX;
-        this._pressY = e.clientY;
+        // this._pressX = e.clientX;
+        // this._pressY = e.clientY;
     }
 
     onLongPressUp = (e: PointerEvent) => {
-        console.log("press up");
         if (this._longPressSecondsHack) {
             clearTimeout(this._longPressSecondsHack);
-            console.log("long press cancelled");
         }
-        // e.stopPropagation();
-        // e.preventDefault();
+        if (this._iframeIndicatorRef.current) {
+            this._iframeIndicatorRef.current.classList.remove("active");
+        }
+        if (this._iframeDragRef.current) {
+            while (this._iframeDragRef.current.firstChild) this._iframeDragRef.current.removeChild(this._iframeDragRef.current.firstChild);
+        }
     }
 
 
@@ -300,9 +284,13 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
                 <div className={classname}  >
                     {content}
                 </div>
-                <div className="mobileIframeDragger" ref={this._iframeDragRef} draggable></div>
-                {!frozen ? (null) : <div className="webBox-overlay" onWheel={this.onPreWheel} onPointerDown={this.onPrePointer} onPointerMove={this.onPrePointer} onPointerUp={this.onPrePointer} />}
-                {/* onPointerDown={(e) => { this.onPrePointer(e); this.onLongPressDown(e) }} onPointerMove={this.onPrePointer} onPointerUp={(e) => { this.onPrePointer(e); }} />} */}
+                {!frozen ? (null) :
+                    <div className="webBox-overlay" onWheel={this.onPreWheel} onPointerDown={this.onPrePointer} onPointerMove={this.onPrePointer} onPointerUp={this.onPrePointer}>
+                        <div className="touch-iframe-overlay" onPointerDown={this.onLongPressDown} >
+                            <div className="indicator" ref={this._iframeIndicatorRef}></div>
+                            <div className="dragger" ref={this._iframeDragRef}></div>
+                        </div>
+                    </div>}
             </>);
     }
     render() {
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
index 10bd78075..42dfd4e51 100644
--- a/src/mobile/ImageUpload.tsx
+++ b/src/mobile/ImageUpload.tsx
@@ -106,8 +106,6 @@ class Uploader extends React.Component {
 
 }
 
-// Scripting.addGlobal(function uploadImageMobile() { return Uploader.onClick(); });
-
 
 // DocServer.init(window.location.protocol, window.location.hostname, 4321, "image upload");
 (async () => {
diff --git a/src/mobile/MobileInkOverlay.scss b/src/mobile/MobileInkOverlay.scss
index 2e45d0441..0b4484519 100644
--- a/src/mobile/MobileInkOverlay.scss
+++ b/src/mobile/MobileInkOverlay.scss
@@ -1,10 +1,10 @@
 .mobileInkOverlay {
     border: 5px dashed red;
+    background-color: rgba(0, 0, 0, .05);
 }
 
 .mobileInkOverlay-border {
-    background-color: rgba(0, 255, 0, .4);
-    position: absolute;
+    // background-color: rgba(0, 255, 0, .4);    position: absolute;
     pointer-events: auto;
     cursor: pointer;
 
diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx
index 9f810424a..db6cf21b4 100644
--- a/src/mobile/MobileInkOverlay.tsx
+++ b/src/mobile/MobileInkOverlay.tsx
@@ -20,6 +20,7 @@ export default class MobileInkOverlay extends React.Component {
     @observable private _height: number = 0;
     @observable private _x: number = -300;
     @observable private _y: number = -300;
+    @observable private _text: string = "";
 
     @observable private _offsetX: number = 0;
     @observable private _offsetY: number = 0;
@@ -32,21 +33,25 @@ export default class MobileInkOverlay extends React.Component {
     }
 
     initialSize(mobileWidth: number, mobileHeight: number) {
-        const maxWidth = window.innerWidth - 30; // TODO: may not be window ?? figure out how to not include library ????
+        const maxWidth = window.innerWidth - 30;
         const maxHeight = window.innerHeight - 30; // -30 for padding
-        const scale = Math.min(maxWidth / mobileWidth, maxHeight / mobileHeight);
-        return { width: mobileWidth * scale, height: mobileHeight * scale, scale: scale };
+        if (mobileWidth > maxWidth || mobileHeight > maxHeight) {
+            const scale = Math.min(maxWidth / mobileWidth, maxHeight / mobileHeight);
+            return { width: mobileWidth * scale, height: mobileHeight * scale, scale: scale };
+        }
+        return { width: mobileWidth, height: mobileHeight, scale: 1 };
     }
 
     @action
     initMobileInkOverlay(content: MobileInkOverlayContent) {
-        const { width, height } = content;
+        const { width, height, text } = content;
         const scaledSize = this.initialSize(width ? width : 0, height ? height : 0);
         this._width = scaledSize.width;
         this._height = scaledSize.height;
-        this._scale = scaledSize.scale; //scaledSize.scale;
+        this._scale = scaledSize.scale;
         this._x = 300; // TODO: center on screen
         this._y = 25; // TODO: center on screen
+        this._text = text ? text : "";
     }
 
     @action
@@ -73,7 +78,7 @@ export default class MobileInkOverlay extends React.Component {
         };
 
         const target = document.elementFromPoint(this._x + 10, this._y + 10);
-        target?.dispatchEvent(
+        target ?.dispatchEvent(
             new CustomEvent<GestureUtils.GestureEvent>("dashOnGesture",
                 {
                     bubbles: true,
@@ -88,25 +93,13 @@ export default class MobileInkOverlay extends React.Component {
     }
 
     uploadDocument = async (content: MobileDocumentUploadContent) => {
-        const { docId, asCollection } = content;
-        console.log("receive upload document id", docId);
+        const { docId } = content;
         const doc = await DocServer.GetRefField(docId);
 
         if (doc && doc instanceof Doc) {
-            console.log("parsed upload document into doc", StrCast(doc.proto!.title));
-
             const target = document.elementFromPoint(this._x + 10, this._y + 10);
-            console.log("the target is", target);
-
-            let uploadDocs = [doc];
-            if (!asCollection) {
-                const children = await DocListCastAsync(doc.data);
-                console.log("uploading children", children);
-                uploadDocs = children ? children : [];
-            }
-            const dragData = new DragManager.DocumentDragData(uploadDocs);
+            const dragData = new DragManager.DocumentDragData([doc]);
             const complete = new DragManager.DragCompleteEvent(false, dragData);
-            console.log("the drag data is", dragData);
 
             if (target) {
                 target.dispatchEvent(
@@ -181,11 +174,11 @@ export default class MobileInkOverlay extends React.Component {
                     zIndex: 30000,
                     pointerEvents: "none",
                     borderStyle: this._isDragging ? "solid" : "dashed",
-                    backgroundColor: "rgba(255, 0, 0, 0.3)"
                 }
                 }
                 ref={this._mainCont}
             >
+                <p>{this._text}</p>
                 <div className="mobileInkOverlay-border top" onPointerDown={this.dragStart}></div>
                 <div className="mobileInkOverlay-border bottom" onPointerDown={this.dragStart}></div>
                 <div className="mobileInkOverlay-border left" onPointerDown={this.dragStart}></div>
diff --git a/src/mobile/MobileInterface.scss b/src/mobile/MobileInterface.scss
index 8b0ebcd53..8083e5760 100644
--- a/src/mobile/MobileInterface.scss
+++ b/src/mobile/MobileInterface.scss
@@ -1,15 +1,18 @@
 .mobileInterface-inkInterfaceButtons {
     position: absolute;
-    top: -50px;
+    top: 0px;
     display: flex;
     justify-content: space-between;
     width: 100%;
     z-index: 9999;
     height: 50px;
+
+    .mobileInterface-button {
+        height: 100%;
+    }
 }
 
 .mobileInterface-container {
     height: calc(100% - 50px);
-    margin-top: 50px;
     position: relative;
 }
\ No newline at end of file
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index e21258c62..a3b956a15 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -34,6 +34,7 @@ import MarqueeOptionsMenu from '../client/views/collections/collectionFreeForm/M
 import GoogleAuthenticationManager from '../client/apis/GoogleAuthenticationManager';
 import { listSpec } from '../new_fields/Schema';
 import { Id } from '../new_fields/FieldSymbols';
+import { DocumentManager } from '../client/util/DocumentManager';
 
 library.add(faLongArrowAltLeft);
 
@@ -73,7 +74,6 @@ export default class MobileInterface extends React.Component {
         onSwitch && onSwitch();
 
         this.renderView = renderView;
-        console.log("switching current view", renderView);
     }
 
     onSwitchInking = () => {
@@ -87,22 +87,37 @@ export default class MobileInterface extends React.Component {
         });
     }
 
-    onSwitchUpload = () => {
+    onSwitchUpload = async () => {
+        let width = 300;
+        let height = 300;
+
+        // get width and height of the collection doc
+        if (this.mainContainer) {
+            const data = Cast(this.mainContainer.data, listSpec(Doc));
+            if (data) {
+                const collectionDoc = await data[1]; // this should be the collection doc since the positions should be locked
+                const docView = DocumentManager.Instance.getDocumentView(collectionDoc);
+                if (docView) {
+                    width = docView.nativeWidth ? docView.nativeWidth : 300;
+                    height = docView.nativeHeight ? docView.nativeHeight : 300;
+                }
+            }
+        }
         DocServer.Mobile.dispatchOverlayTrigger({
             enableOverlay: true,
-            width: 100,
-            height: 100
+            width: width,
+            height: height,
+            text: "Documents uploaded from mobile will show here",
         });
     }
 
     renderDefaultContent = () => {
-        console.log("rendering default content", this.mainContainer);
         if (this.mainContainer) {
             return <DocumentView
                 Document={this.mainContainer}
                 DataDoc={undefined}
                 LibraryPath={emptyPath}
-                addDocument={(doc: Doc) => { console.log("want to add doc to default content", StrCast(doc.title)); return false; }}
+                addDocument={returnFalse}
                 addDocTab={returnFalse}
                 pinToPres={emptyFunction}
                 removeDocument={undefined}
@@ -142,7 +157,6 @@ export default class MobileInterface extends React.Component {
     }
 
     shiftLeft = (e: React.MouseEvent) => {
-        console.log("shift left!");
         DocServer.Mobile.dispatchOverlayPositionUpdate({
             dx: -10
         });
@@ -203,17 +217,16 @@ export default class MobileInterface extends React.Component {
         }
     }
 
-    upload = async (e: React.MouseEvent, asCollection: boolean) => {
+    upload = async (e: React.MouseEvent) => {
         if (this.mainContainer) {
             const data = Cast(this.mainContainer.data, listSpec(Doc));
             if (data) {
-                const uploadDoc = await data[1]; // TODO: ensure this is the collection to upload
-
-                console.log("UPLOADING DOCUMENT FROM MOBILE", uploadDoc[Id], StrCast(uploadDoc.proto!.title));
+                const collectionDoc = await data[1]; // this should be the collection doc since the positions should be locked
+                const children = Cast(collectionDoc.data, listSpec(Doc), []);
+                const uploadDoc = children.length === 1 ? await children[0] : collectionDoc;
                 if (uploadDoc) {
                     DocServer.Mobile.dispatchMobileDocumentUpload({
                         docId: uploadDoc[Id],
-                        asCollection: asCollection
                     });
                 }
             }
@@ -231,15 +244,14 @@ export default class MobileInterface extends React.Component {
                             <button className="mobileInterface-button cancel" onClick={this.onBack} title="Back">BACK</button>
                         </div>
                         <div className="uploadSettings">
-                            <button className="mobileInterface-button" onClick={e => this.upload(e, false)} title="Upload">UPLOAD</button>
-                            <button className="mobileInterface-button" onClick={e => this.upload(e, true)} title="Upload">UPLOAD AS COLLECTION</button>
+                            <button className="mobileInterface-button" onClick={this.upload} title="Upload">UPLOAD</button>
                         </div>
                     </div>
                     <DocumentView
                         Document={this.mainContainer}
                         DataDoc={undefined}
                         LibraryPath={emptyPath}
-                        addDocument={(doc: Doc) => { console.log("want to add doc", StrCast(doc.title)); return false; }}
+                        addDocument={returnFalse}
                         addDocTab={returnFalse}
                         pinToPres={emptyFunction}
                         removeDocument={undefined}
diff --git a/src/server/Message.ts b/src/server/Message.ts
index 6dac37a46..b7bf2e81e 100644
--- a/src/server/Message.ts
+++ b/src/server/Message.ts
@@ -55,6 +55,7 @@ export interface MobileInkOverlayContent {
     readonly enableOverlay: boolean;
     readonly width?: number;
     readonly height?: number;
+    readonly text?: string;
 }
 
 export interface UpdateMobileInkOverlayPositionContent {
@@ -65,7 +66,6 @@ export interface UpdateMobileInkOverlayPositionContent {
 
 export interface MobileDocumentUploadContent {
     readonly docId: string;
-    readonly asCollection: boolean;
 }
 
 export namespace MessageStore {
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 3e5953ac1..491685e18 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -102,9 +102,9 @@ export class CurrentUserUtils {
             { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc },
             { title: "use scrubber", icon: "eraser", click: 'activateScrubber(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "green", activePen: doc },
             { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc },
-            { title: "draw", icon: "pen-nib", click: 'switchMobileView(setupMobileInkingDoc, renderMobileInking, onSwitchMobileInking);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "red", activePen: doc },
+            // { title: "draw", icon: "pen-nib", click: 'switchMobileView(setupMobileInkingDoc, renderMobileInking, onSwitchMobileInking);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "red", activePen: doc },
             { title: "upload", icon: "upload", click: 'switchMobileView(setupMobileUploadDoc, renderMobileUpload, onSwitchMobileUpload);', backgroundColor: "orange" },
-            { title: "upload", icon: "upload", click: 'uploadImageMobile();', backgroundColor: "cyan" },
+            // { title: "upload", icon: "upload", click: 'uploadImageMobile();', backgroundColor: "cyan" },
         ];
         return docProtoData.filter(d => !buttons || !buttons.includes(d.title)).map(data => Docs.Create.FontIconDocument({
             nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, dropAction: data.click ? "copy" : undefined, title: data.title, icon: data.icon, ignoreClick: data.ignoreClick,
@@ -138,9 +138,7 @@ export class CurrentUserUtils {
     }
 
     static setupMobileDoc(userDoc: Doc) {
-        const webDoc = Docs.Create.WebDocument("https://wikipedia.com", { title: "Mobile Upload Web", chromeStatus: "enabled" });
-
-        return userDoc.activeMoble ?? Docs.Create.MasonryDocument([webDoc, ...CurrentUserUtils.setupMobileButtons(userDoc)], {
+        return userDoc.activeMoble ?? Docs.Create.MasonryDocument(CurrentUserUtils.setupMobileButtons(userDoc), {
             columnWidth: 100, ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", title: "buttons", autoHeight: true, yMargin: 5
         });
     }
@@ -150,14 +148,15 @@ export class CurrentUserUtils {
     }
 
     static setupMobileUploadDoc(userDoc: Doc) {
-        const webDoc = Docs.Create.WebDocument("https://yahoo.com", { title: "Upload Images From the Web", chromeStatus: "enabled" });
-        const uploadDoc = Docs.Create.StackingDocument([], { title: "Mobile Upload Collection", backgroundColor: "pink" });
-        console.log("window size", window.innerWidth, window.innerHeight);
-        // return Docs.Create.StackingDocument([webDoc, uploadDoc], {
-        //     columnWidth: window.innerWidth, //ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", title: "Mobile Upload", autoHeight: true, yMargin: 5
-        // });
-        return Docs.Create.StackingDocument([webDoc, uploadDoc], {//...CurrentUserUtils.setupMobileButtons(userDoc)], {
-            columnWidth: 100, lockedPosition: true, chromeStatus: "disabled", title: "Upload", autoHeight: true, yMargin: 30
+        const webDoc = Docs.Create.WebDocument("https://www.britannica.com/animal/cat", {
+            title: "Upload Images From the Web", chromeStatus: "enabled", lockedPosition: true
+        });
+        const uploadDoc = Docs.Create.StackingDocument([], {
+            title: "Mobile Upload Collection", backgroundColor: "white", lockedPosition: true
+        });
+        console.log(window.innerWidth, screen.width, window.devicePixelRatio);
+        return Docs.Create.StackingDocument([webDoc, uploadDoc], {
+            columnWidth: screen.width - 10, lockedPosition: true, chromeStatus: "disabled", title: "Upload", autoHeight: true, yMargin: 80, backgroundColor: "lightgray"
         });
     }
 
-- 
cgit v1.2.3-70-g09d2

