From d1c1e9f10b8523270a872c6f67df25ebb1d9aa25 Mon Sep 17 00:00:00 2001
From: kimdahey <claire_kim1@brown.edu>
Date: Mon, 27 Jan 2020 20:34:27 -0500
Subject: switching event type, some bugs :(

---
 src/client/views/nodes/DocumentView.tsx | 94 ++++++++++++++-------------------
 1 file changed, 39 insertions(+), 55 deletions(-)

(limited to 'src/client/views/nodes/DocumentView.tsx')

diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 0b6a284d6..ae2ee9e41 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -119,61 +119,45 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     private _firstY: number = 0;
 
 
-    // handle1PointerHoldStart = (e: React.TouchEvent): any => {
-    //     this.onRadialMenu(e);
-    //     const pt = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true)[0];
-    //     this._firstX = pt.pageX;
-    //     this._firstY = pt.pageY;
-    //     e.stopPropagation();
-    //     e.preventDefault();
-
-    //     document.removeEventListener("touchmove", this.onTouch);
-    //     document.removeEventListener("touchmove", this.handle1PointerHoldMove);
-    //     document.addEventListener("touchmove", this.handle1PointerHoldMove);
-    //     document.removeEventListener("touchend", this.handle1PointerHoldEnd);
-    //     document.addEventListener("touchend", this.handle1PointerHoldEnd);
-    // }
-
-    // handle1PointerHoldMove = (e: TouchEvent): void => {
-    //     const pt = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0];
-    //     if (Math.abs(pt.pageX - this._firstX) > 150 || Math.abs(pt.pageY - this._firstY) > 150) {
-    //         this.handleRelease();
-    //     }
-    //     document.removeEventListener("touchmove", this.handle1PointerHoldMove);
-    //     document.addEventListener("touchmove", this.handle1PointerHoldMove);
-    //     document.removeEventListener("touchend", this.handle1PointerHoldEnd);
-    //     document.addEventListener("touchend", this.handle1PointerHoldEnd);
-    // }
-
-    // handleRelease() {
-    //     RadialMenu.Instance.closeMenu();
-    //     document.removeEventListener("touchmove", this.handle1PointerHoldMove);
-    //     document.removeEventListener("touchend", this.handle1PointerHoldEnd);
-    // }
-
-    // handle1PointerHoldEnd = (e: TouchEvent): void => {
-    //     RadialMenu.Instance.closeMenu();
-    //     document.removeEventListener("touchmove", this.handle1PointerHoldMove);
-    //     document.removeEventListener("touchend", this.handle1PointerHoldEnd);
-    // }
-
-    // @action
-    // onRadialMenu = (e: React.TouchEvent): void => {
-    //     const pt = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0];
-
-    //     RadialMenu.Instance.openMenu();
-
-    //     RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group", selected: -1 });
-    //     RadialMenu.Instance.addItem({ description: "Delete this document", event: () => this.props.ContainingCollectionView?.removeDocument(this.props.Document), icon: "trash", selected: -1 });
-    //     RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, undefined, "onRight"), icon: "folder", selected: -1 });
-    //     RadialMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.Document), icon: "map-pin", selected: -1 });
-
-    //     RadialMenu.Instance.displayMenu(pt.pageX - 15, pt.pageY - 15);
-    //     if (!SelectionManager.IsSelected(this, true)) {
-    //         SelectionManager.SelectDoc(this, false);
-    //     }
-    //     e.stopPropagation();
-    // }
+    handle1PointerHoldStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): any => {
+        console.log("S");
+        this.onRadialMenu(e, me);
+        const pt = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0];
+        this._firstX = pt.pageX;
+        this._firstY = pt.pageY;
+
+    }
+
+    handle1PointerHoldMove = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => {
+        console.log("K");
+        const pt = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0];
+        if (Math.abs(pt.pageX - this._firstX) > 150 || Math.abs(pt.pageY - this._firstY) > 150) {
+            this.handle1PointerHoldEnd(e, me);
+        }
+    }
+
+    handle1PointerHoldEnd = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => {
+        console.log("E");
+        RadialMenu.Instance.closeMenu();
+    }
+
+    @action
+    onRadialMenu = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): void => {
+        const pt = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0];
+
+        RadialMenu.Instance.openMenu();
+
+        RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group", selected: -1 });
+        RadialMenu.Instance.addItem({ description: "Delete this document", event: () => this.props.ContainingCollectionView?.removeDocument(this.props.Document), icon: "trash", selected: -1 });
+        RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, undefined, "onRight"), icon: "folder", selected: -1 });
+        RadialMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.Document), icon: "map-pin", selected: -1 });
+
+        RadialMenu.Instance.displayMenu(pt.pageX - 15, pt.pageY - 15);
+        if (!SelectionManager.IsSelected(this, true)) {
+            SelectionManager.SelectDoc(this, false);
+        }
+        e.stopPropagation();
+    }
 
     @action
     componentDidMount() {
-- 
cgit v1.2.3-70-g09d2


From 9bf6bd83bdb136e4478c59ce69ee44fc5d0d8352 Mon Sep 17 00:00:00 2001
From: kimdahey <claire_kim1@brown.edu>
Date: Wed, 29 Jan 2020 16:56:33 -0500
Subject: fixes

---
 src/client/util/InteractionUtils.ts     | 13 ++++++++++++-
 src/client/views/GestureOverlay.tsx     | 32 ++++++++++++++++++++++++++++++++
 src/client/views/Touchable.tsx          | 24 ++++--------------------
 src/client/views/nodes/DocumentView.tsx |  8 ++++++++
 4 files changed, 56 insertions(+), 21 deletions(-)

(limited to 'src/client/views/nodes/DocumentView.tsx')

diff --git a/src/client/util/InteractionUtils.ts b/src/client/util/InteractionUtils.ts
index da42bdc93..8e1beecb7 100644
--- a/src/client/util/InteractionUtils.ts
+++ b/src/client/util/InteractionUtils.ts
@@ -23,7 +23,7 @@ export namespace InteractionUtils {
 
     export function MakeMultiTouchTarget(
         element: HTMLElement,
-        startFunc: (e: Event, me: MultiTouchEvent<React.TouchEvent>) => void,
+        startFunc: (e: Event, me: MultiTouchEvent<React.TouchEvent>) => void
     ): MultiTouchEventDisposer {
         const onMultiTouchStartHandler = (e: Event) => startFunc(e, (e as CustomEvent<MultiTouchEvent<React.TouchEvent>>).detail);
         // const onMultiTouchMoveHandler = moveFunc ? (e: Event) => moveFunc(e, (e as CustomEvent<MultiTouchEvent<TouchEvent>>).detail) : undefined;
@@ -46,6 +46,17 @@ export namespace InteractionUtils {
         };
     }
 
+    export function MakeHoldTouchTarget(
+        element: HTMLElement,
+        func: (e: Event, me: MultiTouchEvent<React.TouchEvent>) => void
+    ): MultiTouchEventDisposer {
+        const handler = (e: Event) => func(e, (e as CustomEvent<MultiTouchEvent<React.TouchEvent>>).detail);
+        element.addEventListener("dashOnTouchHoldStart", handler);
+        return () => {
+            element.removeEventListener("dashOnTouchHoldStart", handler);
+        };
+    }
+
     export function GetMyTargetTouches(mte: InteractionUtils.MultiTouchEvent<React.TouchEvent | TouchEvent>, prevPoints: Map<number, React.Touch>, ignorePen: boolean): React.Touch[] {
         const myTouches = new Array<React.Touch>();
         for (const pt of mte.touches) {
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 96c1513ff..0777bc2bc 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -32,6 +32,7 @@ export default class GestureOverlay extends Touchable {
     private _thumbX?: number;
     private _thumbY?: number;
     private thumbIdentifier?: number;
+    private _holdTimer: NodeJS.Timeout | undefined;
     private _hands: (React.Touch[])[] = [];
 
     protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
@@ -96,6 +97,7 @@ export default class GestureOverlay extends Touchable {
         ptsToDelete.forEach(pt => this.prevPoints.delete(pt));
 
         if (this.prevPoints.size && this.prevPoints.size < 5) {
+
             const nts = this.getNewTouches(te);
             const target = document.elementFromPoint(te.changedTouches.item(0).clientX, te.changedTouches.item(0).clientY);
             target?.dispatchEvent(
@@ -112,6 +114,28 @@ export default class GestureOverlay extends Touchable {
                     }
                 )
             );
+            if (this.prevPoints.size === 1 && this._holdTimer === undefined) {
+                console.log("started");
+                this._holdTimer = setTimeout(() => {
+                    console.log("hold");
+                    const target = document.elementFromPoint(te.changedTouches.item(0).clientX, te.changedTouches.item(0).clientY);
+                    target?.dispatchEvent(
+                        new CustomEvent<InteractionUtils.MultiTouchEvent<React.TouchEvent>>("dashOnTouchHoldStart",
+                            {
+                                bubbles: true,
+                                detail: {
+                                    fingers: this.prevPoints.size,
+                                    targetTouches: nts.ntt,
+                                    touches: nts.nt,
+                                    changedTouches: nts.nct,
+                                    touchEvent: te
+                                }
+                            }
+                        )
+                    );
+                    this._holdTimer = undefined;
+                }, (1000));
+            }
             document.removeEventListener("touchmove", this.onReactTouchMove);
             document.removeEventListener("touchend", this.onReactTouchEnd);
             document.addEventListener("touchmove", this.onReactTouchMove);
@@ -126,6 +150,10 @@ export default class GestureOverlay extends Touchable {
 
     onReactTouchMove = (e: TouchEvent) => {
         const nts: any = this.getNewTouches(e);
+        if (this.prevPoints.size === 1 && this._holdTimer) {
+            clearTimeout(this._holdTimer);
+            this._holdTimer = undefined;
+        }
         document.dispatchEvent(
             new CustomEvent<InteractionUtils.MultiTouchEvent<TouchEvent>>("dashOnTouchMove",
                 {
@@ -143,6 +171,10 @@ export default class GestureOverlay extends Touchable {
 
     onReactTouchEnd = (e: TouchEvent) => {
         const nts: any = this.getNewTouches(e);
+        if (this.prevPoints.size === 1 && this._holdTimer) {
+            clearTimeout(this._holdTimer);
+            this._holdTimer = undefined;
+        }
         document.dispatchEvent(
             new CustomEvent<InteractionUtils.MultiTouchEvent<TouchEvent>>("dashOnTouchEnd",
                 {
diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx
index eed72e3c5..da656dd57 100644
--- a/src/client/views/Touchable.tsx
+++ b/src/client/views/Touchable.tsx
@@ -8,7 +8,6 @@ const HOLD_DURATION = 1000;
 
 export abstract class Touchable<T = {}> extends React.Component<T> {
     //private holdTimer: NodeJS.Timeout | undefined;
-    holdTimer: NodeJS.Timeout | undefined;
     private moveDisposer?: InteractionUtils.MultiTouchEventDisposer;
     private endDisposer?: InteractionUtils.MultiTouchEventDisposer;
     private holdMoveDisposer?: InteractionUtils.MultiTouchEventDisposer;
@@ -29,6 +28,8 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
      */
     @action
     protected onTouchStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): void => {
+        console.log(e);
+        console.log(me);
         const actualPts: React.Touch[] = [];
         const te = me.touchEvent;
         // loop through all touches on screen
@@ -68,10 +69,7 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
                     //     clearTimeout(this.holdTimer)
                     //     this.holdTimer = undefined;
                     // }
-                    console.log(this.holdTimer);
-                    if (!this.holdTimer) {
-                        this.holdTimer = setTimeout(() => this.handle1PointerHoldStart(e, me), HOLD_DURATION);
-                    }
+                    // console.log(this.holdTimer);
                     // console.log(this.holdTimer);
                     break;
                 case 2:
@@ -96,11 +94,6 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
         // if we're not actually moving a lot, don't consider it as dragging yet
         if (!InteractionUtils.IsDragging(this.prevPoints, myTouches, 5) && !this._touchDrag) return;
         this._touchDrag = true;
-        if (this.holdTimer) {
-            console.log("CLEAR");
-            clearTimeout(this.holdTimer);
-            // this.holdTimer = undefined;
-        }
         // console.log(myTouches.length);
         switch (myTouches.length) {
             case 1:
@@ -123,6 +116,7 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
     @action
     protected onTouchEnd = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => {
         // console.log(InteractionUtils.GetMyTargetTouches(e, this.prevPoints).length + " up");
+        console.log("end");
         // remove all the touches associated with the event
         const te = me.touchEvent;
         for (const pt of me.changedTouches) {
@@ -132,15 +126,6 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
                 }
             }
         }
-        if (this.holdTimer) {
-            console.log(this.holdTimer);
-            clearTimeout(this.holdTimer);
-            console.log(this.holdTimer);
-
-            this.holdTimer = undefined;
-            console.log(this.holdTimer);
-            console.log("clear");
-        }
         this._touchDrag = false;
         te.stopPropagation();
 
@@ -187,7 +172,6 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
     handle1PointerHoldStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): any => {
         e.stopPropagation();
         me.touchEvent.stopPropagation();
-        this.holdTimer = undefined;
         this.removeMoveListeners();
         this.removeEndListeners();
         this.removeHoldMoveListeners();
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index ae2ee9e41..82cb36aa7 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -104,6 +104,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     private _titleRef = React.createRef<EditableView>();
 
     protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
+    private holdDisposer?: InteractionUtils.MultiTouchEventDisposer;
 
     public get displayName() { return "DocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive
     public get ContentDiv() { return this._mainCont.current; }
@@ -120,6 +121,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
 
     handle1PointerHoldStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): any => {
+        console.log(me);
         console.log("S");
         this.onRadialMenu(e, me);
         const pt = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0];
@@ -164,6 +166,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this)));
         this._mainCont.current && (this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this)));
         this._mainCont.current && (this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this)));
+        this._mainCont.current && (this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this)));
 
         !this.props.dontRegisterView && DocumentManager.Instance.DocumentViews.push(this);
     }
@@ -173,14 +176,19 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         this._dropDisposer && this._dropDisposer();
         this._gestureEventDisposer && this._gestureEventDisposer();
         this.multiTouchDisposer && this.multiTouchDisposer();
+        this.holdDisposer && this.holdDisposer();
         this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this)));
         this._mainCont.current && (this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this)));
         this._mainCont.current && (this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this)));
+        this._mainCont.current && (this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this)));
     }
 
     @action
     componentWillUnmount() {
         this._dropDisposer && this._dropDisposer();
+        this._gestureEventDisposer && this._gestureEventDisposer();
+        this.multiTouchDisposer && this.multiTouchDisposer();
+        this.holdDisposer && this.holdDisposer();
         Doc.UnBrushDoc(this.props.Document);
         !this.props.dontRegisterView && DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1);
     }
-- 
cgit v1.2.3-70-g09d2


From 962cfebaa2e15ac48aa969afc50c5913573623df Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Wed, 29 Jan 2020 17:47:34 -0500
Subject: fixed menu

---
 package-lock.json                       | 35 +++++---------
 src/client/views/GestureOverlay.tsx     | 85 ++++++++++++++++++++++++++++-----
 src/client/views/Touchable.tsx          |  4 +-
 src/client/views/nodes/DocumentView.tsx | 33 +++++++------
 4 files changed, 105 insertions(+), 52 deletions(-)

(limited to 'src/client/views/nodes/DocumentView.tsx')

diff --git a/package-lock.json b/package-lock.json
index 4a5de1c66..40272b91a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5366,8 +5366,7 @@
                 },
                 "ansi-regex": {
                     "version": "2.1.1",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 },
                 "aproba": {
                     "version": "1.2.0",
@@ -5404,8 +5403,7 @@
                 },
                 "code-point-at": {
                     "version": "1.1.0",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 },
                 "concat-map": {
                     "version": "0.0.1",
@@ -5414,8 +5412,7 @@
                 },
                 "console-control-strings": {
                     "version": "1.1.0",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 },
                 "core-util-is": {
                     "version": "1.0.2",
@@ -5518,8 +5515,7 @@
                 },
                 "inherits": {
                     "version": "2.0.3",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 },
                 "ini": {
                     "version": "1.3.5",
@@ -5529,7 +5525,6 @@
                 "is-fullwidth-code-point": {
                     "version": "1.0.0",
                     "bundled": true,
-                    "optional": true,
                     "requires": {
                         "number-is-nan": "^1.0.0"
                     }
@@ -5555,7 +5550,6 @@
                 "minipass": {
                     "version": "2.3.5",
                     "bundled": true,
-                    "optional": true,
                     "requires": {
                         "safe-buffer": "^5.1.2",
                         "yallist": "^3.0.0"
@@ -5572,7 +5566,6 @@
                 "mkdirp": {
                     "version": "0.5.1",
                     "bundled": true,
-                    "optional": true,
                     "requires": {
                         "minimist": "0.0.8"
                     }
@@ -5656,7 +5649,6 @@
                 "once": {
                     "version": "1.4.0",
                     "bundled": true,
-                    "optional": true,
                     "requires": {
                         "wrappy": "1"
                     }
@@ -5732,8 +5724,7 @@
                 },
                 "safe-buffer": {
                     "version": "5.1.2",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 },
                 "safer-buffer": {
                     "version": "2.1.2",
@@ -5763,7 +5754,6 @@
                 "string-width": {
                     "version": "1.0.2",
                     "bundled": true,
-                    "optional": true,
                     "requires": {
                         "code-point-at": "^1.0.0",
                         "is-fullwidth-code-point": "^1.0.0",
@@ -5781,7 +5771,6 @@
                 "strip-ansi": {
                     "version": "3.0.1",
                     "bundled": true,
-                    "optional": true,
                     "requires": {
                         "ansi-regex": "^2.0.0"
                     }
@@ -5820,13 +5809,11 @@
                 },
                 "wrappy": {
                     "version": "1.0.2",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 },
                 "yallist": {
                     "version": "3.0.3",
-                    "bundled": true,
-                    "optional": true
+                    "bundled": true
                 }
             }
         },
@@ -7078,7 +7065,7 @@
                 "babel-runtime": "^6.22.0",
                 "bluebird": "^3.4.7",
                 "boolify-string": "^2.0.2",
-                "emit-logger": "github:chocolateboy/emit-logger#better-emitter-name",
+                "emit-logger": "github:chocolateboy/emit-logger#b9d25a2d939e42f29c940861e9648bd0fb810070",
                 "lodash": "^4.17.4",
                 "semver": "^5.0.3",
                 "source-map-support": "^0.5.9"
@@ -14174,7 +14161,7 @@
         },
         "readable-stream": {
             "version": "2.3.6",
-            "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
             "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
             "requires": {
                 "core-util-is": "~1.0.0",
@@ -15527,7 +15514,7 @@
         },
         "string_decoder": {
             "version": "1.1.1",
-            "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
             "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
             "requires": {
                 "safe-buffer": "~5.1.0"
@@ -15557,7 +15544,7 @@
         },
         "strip-ansi": {
             "version": "3.0.1",
-            "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
             "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
             "requires": {
                 "ansi-regex": "^2.0.0"
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 0777bc2bc..029834725 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -50,21 +50,21 @@ export default class GestureOverlay extends Touchable {
         this._hands.forEach((hand) => {
             for (let i = 0; i < e.targetTouches.length; i++) {
                 const pt = e.targetTouches.item(i);
-                if (pt && hand.some((finger) => finger.screenX === pt?.screenX && finger.screenY === pt.screenY)) {
+                if (pt && hand.some((finger) => finger.screenX === pt ?.screenX && finger.screenY === pt.screenY)) {
                     ntt.splice(ntt.indexOf(pt));
                 }
             }
 
             for (let i = 0; i < e.changedTouches.length; i++) {
                 const pt = e.changedTouches.item(i);
-                if (pt && hand.some((finger) => finger.screenX === pt?.screenX && finger.screenY === pt.screenY)) {
+                if (pt && hand.some((finger) => finger.screenX === pt ?.screenX && finger.screenY === pt.screenY)) {
                     nct.splice(nct.indexOf(pt));
                 }
             }
 
             for (let i = 0; i < e.touches.length; i++) {
                 const pt = e.touches.item(i);
-                if (pt && hand.some((finger) => finger.screenX === pt?.screenX && finger.screenY === pt.screenY)) {
+                if (pt && hand.some((finger) => finger.screenX === pt ?.screenX && finger.screenY === pt.screenY)) {
                     nt.splice(ntt.indexOf(pt));
                 }
             }
@@ -100,7 +100,7 @@ export default class GestureOverlay extends Touchable {
 
             const nts = this.getNewTouches(te);
             const target = document.elementFromPoint(te.changedTouches.item(0).clientX, te.changedTouches.item(0).clientY);
-            target?.dispatchEvent(
+            target ?.dispatchEvent(
                 new CustomEvent<InteractionUtils.MultiTouchEvent<React.TouchEvent>>("dashOnTouchStart",
                     {
                         bubbles: true,
@@ -119,7 +119,7 @@ export default class GestureOverlay extends Touchable {
                 this._holdTimer = setTimeout(() => {
                     console.log("hold");
                     const target = document.elementFromPoint(te.changedTouches.item(0).clientX, te.changedTouches.item(0).clientY);
-                    target?.dispatchEvent(
+                    target ?.dispatchEvent(
                         new CustomEvent<InteractionUtils.MultiTouchEvent<React.TouchEvent>>("dashOnTouchHoldStart",
                             {
                                 bubbles: true,
@@ -134,6 +134,12 @@ export default class GestureOverlay extends Touchable {
                         )
                     );
                     this._holdTimer = undefined;
+                    document.removeEventListener("touchmove", this.onReactTouchMove);
+                    document.removeEventListener("touchend", this.onReactTouchEnd);
+                    document.removeEventListener("touchmove", this.onReactHoldTouchMove);
+                    document.removeEventListener("touchend", this.onReactHoldTouchEnd);
+                    document.addEventListener("touchmove", this.onReactHoldTouchMove);
+                    document.addEventListener("touchend", this.onReactHoldTouchEnd);
                 }, (1000));
             }
             document.removeEventListener("touchmove", this.onReactTouchMove);
@@ -148,6 +154,63 @@ export default class GestureOverlay extends Touchable {
         }
     }
 
+    onReactHoldTouchMove = (e: TouchEvent) => {
+        const nts: any = this.getNewTouches(e);
+        if (this.prevPoints.size === 1 && this._holdTimer) {
+            clearTimeout(this._holdTimer);
+            this._holdTimer = undefined;
+        }
+        document.dispatchEvent(
+            new CustomEvent<InteractionUtils.MultiTouchEvent<TouchEvent>>("dashOnTouchHoldMove",
+                {
+                    bubbles: true,
+                    detail: {
+                        fingers: this.prevPoints.size,
+                        targetTouches: nts.ntt,
+                        touches: nts.nt,
+                        changedTouches: nts.nct,
+                        touchEvent: e
+                    }
+                })
+        );
+    }
+
+    onReactHoldTouchEnd = (e: TouchEvent) => {
+        const nts: any = this.getNewTouches(e);
+        if (this.prevPoints.size === 1 && this._holdTimer) {
+            clearTimeout(this._holdTimer);
+            this._holdTimer = undefined;
+        }
+        document.dispatchEvent(
+            new CustomEvent<InteractionUtils.MultiTouchEvent<TouchEvent>>("dashOnTouchHoldEnd",
+                {
+                    bubbles: true,
+                    detail: {
+                        fingers: this.prevPoints.size,
+                        targetTouches: nts.ntt,
+                        touches: nts.nt,
+                        changedTouches: nts.nct,
+                        touchEvent: e
+                    }
+                })
+        );
+        for (let i = 0; i < e.changedTouches.length; i++) {
+            const pt = e.changedTouches.item(i);
+            if (pt) {
+                if (this.prevPoints.has(pt.identifier)) {
+                    this.prevPoints.delete(pt.identifier);
+                }
+            }
+        }
+
+        if (this.prevPoints.size === 0) {
+            document.removeEventListener("touchmove", this.onReactTouchMove);
+            document.removeEventListener("touchend", this.onReactTouchEnd);
+        }
+        e.stopPropagation();
+    }
+
+
     onReactTouchMove = (e: TouchEvent) => {
         const nts: any = this.getNewTouches(e);
         if (this.prevPoints.size === 1 && this._holdTimer) {
@@ -211,7 +274,7 @@ export default class GestureOverlay extends Touchable {
             if (pt.radiusX > 1 && pt.radiusY > 1) {
                 for (let j = 0; j < e.targetTouches.length; j++) {
                     const tPt = e.targetTouches.item(j);
-                    if (tPt?.screenX === pt?.screenX && tPt?.screenY === pt?.screenY) {
+                    if (tPt ?.screenX === pt ?.screenX && tPt ?.screenY === pt ?.screenY) {
                         if (pt && this.prevPoints.has(pt.identifier)) {
                             fingers.push(pt);
                         }
@@ -225,7 +288,7 @@ export default class GestureOverlay extends Touchable {
             this._thumbY = thumb.clientY;
             return;
         }
-        this.thumbIdentifier = thumb?.identifier;
+        this.thumbIdentifier = thumb ?.identifier;
         fingers.forEach((f) => this.prevPoints.delete(f.identifier));
         this._hands.push(fingers);
         const others = fingers.filter(f => f !== thumb);
@@ -325,8 +388,8 @@ export default class GestureOverlay extends Touchable {
                     callbackFn: callback
                 }
             });
-        target1?.dispatchEvent(ge);
-        target2?.dispatchEvent(ge);
+        target1 ?.dispatchEvent(ge);
+        target2 ?.dispatchEvent(ge);
         return actionPerformed;
     }
 
@@ -344,7 +407,7 @@ export default class GestureOverlay extends Touchable {
                 switch (result.Name) {
                     case GestureUtils.Gestures.Box:
                         const target = document.elementFromPoint(this._points[0].X, this._points[0].Y);
-                        target?.dispatchEvent(new CustomEvent<GestureUtils.GestureEvent>("dashOnGesture",
+                        target ?.dispatchEvent(new CustomEvent<GestureUtils.GestureEvent>("dashOnGesture",
                             {
                                 bubbles: true,
                                 detail: {
@@ -369,7 +432,7 @@ export default class GestureOverlay extends Touchable {
 
             if (!actionPerformed) {
                 const target = document.elementFromPoint(this._points[0].X, this._points[0].Y);
-                target?.dispatchEvent(
+                target ?.dispatchEvent(
                     new CustomEvent<GestureUtils.GestureEvent>("dashOnGesture",
                         {
                             bubbles: true,
diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx
index da656dd57..13cc38589 100644
--- a/src/client/views/Touchable.tsx
+++ b/src/client/views/Touchable.tsx
@@ -28,8 +28,7 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
      */
     @action
     protected onTouchStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): void => {
-        console.log(e);
-        console.log(me);
+
         const actualPts: React.Touch[] = [];
         const te = me.touchEvent;
         // loop through all touches on screen
@@ -116,7 +115,6 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
     @action
     protected onTouchEnd = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => {
         // console.log(InteractionUtils.GetMyTargetTouches(e, this.prevPoints).length + " up");
-        console.log("end");
         // remove all the touches associated with the event
         const te = me.touchEvent;
         for (const pt of me.changedTouches) {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 82cb36aa7..fd7aad0d9 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -116,13 +116,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     @computed get onPointerDownHandler() { return this.props.onPointerDown ? this.props.onPointerDown : this.Document.onPointerDown; }
     @computed get onPointerUpHandler() { return this.props.onPointerUp ? this.props.onPointerUp : this.Document.onPointerUp; }
 
-    private _firstX: number = 0;
-    private _firstY: number = 0;
+    private _firstX: number = -1;
+    private _firstY: number = -1;
 
 
     handle1PointerHoldStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): any => {
-        console.log(me);
-        console.log("S");
+        this.addHoldMoveListeners();
+        this.addHoldEndListeners();
         this.onRadialMenu(e, me);
         const pt = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0];
         this._firstX = pt.pageX;
@@ -131,16 +131,21 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     handle1PointerHoldMove = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => {
-        console.log("K");
         const pt = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0];
+        console.log(pt.pageX, this._firstX, pt.pageY, this._firstY);
+        if (this._firstX === -1 || this._firstY === -1) {
+            return;
+        }
         if (Math.abs(pt.pageX - this._firstX) > 150 || Math.abs(pt.pageY - this._firstY) > 150) {
+            console.log("WHY");
             this.handle1PointerHoldEnd(e, me);
         }
     }
 
     handle1PointerHoldEnd = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => {
-        console.log("E");
         RadialMenu.Instance.closeMenu();
+        this._firstX = -1;
+        this._firstY = -1;
     }
 
     @action
@@ -150,7 +155,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         RadialMenu.Instance.openMenu();
 
         RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group", selected: -1 });
-        RadialMenu.Instance.addItem({ description: "Delete this document", event: () => this.props.ContainingCollectionView?.removeDocument(this.props.Document), icon: "trash", selected: -1 });
+        RadialMenu.Instance.addItem({ description: "Delete this document", event: () => this.props.ContainingCollectionView ?.removeDocument(this.props.Document), icon: "trash", selected: -1 });
         RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, undefined, "onRight"), icon: "folder", selected: -1 });
         RadialMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.Document), icon: "map-pin", selected: -1 });
 
@@ -229,13 +234,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             e.preventDefault();
             if (e.key === "†" || e.key === "t") {
                 if (!StrCast(this.layoutDoc.showTitle)) this.layoutDoc.showTitle = "title";
-                if (!this._titleRef.current) setTimeout(() => this._titleRef.current?.setIsFocused(true), 0);
+                if (!this._titleRef.current) setTimeout(() => this._titleRef.current ?.setIsFocused(true), 0);
                 else if (!this._titleRef.current.setIsFocused(true)) { // if focus didn't change, focus on interior text...
                     {
-                        this._titleRef.current?.setIsFocused(false);
-                        const any = (this._mainCont.current?.getElementsByClassName("ProseMirror")?.[0] as any);
+                        this._titleRef.current ?.setIsFocused(false);
+                        const any = (this._mainCont.current ?.getElementsByClassName("ProseMirror") ?.[0] as any);
                         any.keeplocation = true;
-                        any?.focus();
+                        any ?.focus();
                     }
                 }
             } else if (e.key === "f") {
@@ -251,7 +256,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
             e.stopPropagation();
             let preventDefault = true;
-            if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
+            if (this._doubleTap && this.props.renderDepth && !this.onClickHandler ?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
                 const fullScreenAlias = Doc.MakeAlias(this.props.Document);
                 if (StrCast(fullScreenAlias.layoutKey) !== "layoutCustom" && fullScreenAlias.layoutCustom !== undefined) {
                     fullScreenAlias.layoutKey = "layoutCustom";
@@ -265,7 +270,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY);
             } else if (this.props.Document.isButton === "Selector") {  // this should be moved to an OnClick script
                 FormattedTextBoxComment.Hide();
-                this.Document.links?.[0] instanceof Doc && (Doc.UserDoc().SelectedDocs = new List([Doc.LinkOtherAnchor(this.Document.links[0]!, this.props.Document)]));
+                this.Document.links ?.[0] instanceof Doc && (Doc.UserDoc().SelectedDocs = new List([Doc.LinkOtherAnchor(this.Document.links[0]!, this.props.Document)]));
             } else if (this.Document.isButton) {
                 SelectionManager.SelectDoc(this, e.ctrlKey); // don't think this should happen if a button action is actually triggered.
                 this.buttonClick(e.altKey, e.ctrlKey);
@@ -638,7 +643,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     @undoBatch
     @action
     setCustomView = (custom: boolean): void => {
-        if (this.props.ContainingCollectionView?.props.DataDoc || this.props.ContainingCollectionView?.props.Document.isTemplateDoc) {
+        if (this.props.ContainingCollectionView ?.props.DataDoc || this.props.ContainingCollectionView ?.props.Document.isTemplateDoc) {
             Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.ContainingCollectionView.props.Document);
         } else {
             custom ? DocumentView.makeCustomViewClicked(this.props.Document, this.props.DataDoc) : DocumentView.makeNativeViewClicked(this.props.Document);
-- 
cgit v1.2.3-70-g09d2

