diff options
author | andrewdkim <adkim414@gmail.com> | 2020-02-12 20:28:44 -0500 |
---|---|---|
committer | andrewdkim <adkim414@gmail.com> | 2020-02-12 20:28:44 -0500 |
commit | e100f189047ee05aad0864064e4764da073cfc19 (patch) | |
tree | 0c3d05649c8b6329ffd3862bce30e77e86d61006 /src | |
parent | d1b9049fe50e401ac1a33177babd0cfa4b32f6a0 (diff) | |
parent | 33d5a12af14e1ed50e5c3164b363fbbc253506a0 (diff) |
merge
Diffstat (limited to 'src')
-rw-r--r-- | src/client/util/InteractionUtils.tsx | 1 | ||||
-rw-r--r-- | src/client/util/SelectionManager.ts | 1 | ||||
-rw-r--r-- | src/client/views/GestureOverlay.tsx | 112 | ||||
-rw-r--r-- | src/client/views/MainView.tsx | 2 | ||||
-rw-r--r-- | src/client/views/Touchable.tsx | 4 | ||||
-rw-r--r-- | src/client/views/collections/CollectionDockingView.tsx | 69 | ||||
-rw-r--r-- | src/client/views/collections/CollectionSubView.tsx | 2 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss | 7 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 97 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 32 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 73 | ||||
-rw-r--r-- | src/client/views/nodes/RadialMenu.tsx | 75 | ||||
-rw-r--r-- | src/mobile/MobileInkOverlay.tsx | 3 | ||||
-rw-r--r-- | src/pen-gestures/ndollar.ts | 2 | ||||
-rw-r--r-- | src/server/authentication/models/current_user_utils.ts | 2 |
15 files changed, 366 insertions, 116 deletions
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index 2eec02a42..cf51b8e89 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -108,6 +108,7 @@ export namespace InteractionUtils { } export function IsType(e: PointerEvent | React.PointerEvent, type: string): boolean { + console.log(e.button); switch (type) { // pen and eraser are both pointer type 'pen', but pen is button 0 and eraser is button 5. -syip2 case PENTYPE: diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 86a7a620e..4fd8abb12 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -56,6 +56,7 @@ export namespace SelectionManager { export function SelectDoc(docView: DocumentView, ctrlPressed: boolean): void { manager.SelectDoc(docView, ctrlPressed); } + export function IsSelected(doc: DocumentView, outsideReaction?: boolean): boolean { return outsideReaction ? diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 52fa6dc22..78a5389d2 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -30,6 +30,9 @@ import TouchScrollableMenu, { TouchScrollableMenuItem } from "./TouchScrollableM import MobileInterface from "../../mobile/MobileInterface"; import { MobileInkOverlayContent } from "../../server/Message"; import MobileInkOverlay from "../../mobile/MobileInkOverlay"; +import { RadialMenu } from "./nodes/RadialMenu"; +import { SelectionManager } from "../util/SelectionManager"; + @observer export default class GestureOverlay extends Touchable { @@ -109,6 +112,15 @@ export default class GestureOverlay extends Touchable { } onReactTouchStart = (te: React.TouchEvent) => { + document.removeEventListener("touchmove", this.onReactHoldTouchMove); + document.removeEventListener("touchend", this.onReactHoldTouchEnd); + if (RadialMenu.Instance._display === true) { + te.preventDefault(); + te.stopPropagation(); + RadialMenu.Instance.closeMenu(); + return; + } + const actualPts: React.Touch[] = []; for (let i = 0; i < te.touches.length; i++) { const pt: any = te.touches.item(i); @@ -132,10 +144,15 @@ export default class GestureOverlay extends Touchable { ptsToDelete.forEach(pt => this.prevPoints.delete(pt)); const nts = this.getNewTouches(te); - if (nts.nt.length < 5) { const target = document.elementFromPoint(te.changedTouches.item(0).clientX, te.changedTouches.item(0).clientY); +<<<<<<< HEAD target ?.dispatchEvent( +======= + te.changedTouches.item(0).identifier; + console.log(te.touches); + target?.dispatchEvent( +>>>>>>> 33d5a12af14e1ed50e5c3164b363fbbc253506a0 new CustomEvent<InteractionUtils.MultiTouchEvent<React.TouchEvent>>("dashOnTouchStart", { bubbles: true, @@ -149,34 +166,41 @@ 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; - // 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)); - // } + if (nts.nt.length === 1) { + console.log("started"); + this._holdTimer = setTimeout(() => { + console.log("hold"); + const target = document.elementFromPoint(te.changedTouches.item(0).clientX, te.changedTouches.item(0).clientY); + let pt: any = te.touches[te.touches.length - 1]; + if (nts.nt.length === 1 && pt.radiusX > 1 && pt.radiusY > 1) { + 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; + 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); + } + + }, (500)); + } + else { + clearTimeout(this._holdTimer); + } document.removeEventListener("touchmove", this.onReactTouchMove); document.removeEventListener("touchend", this.onReactTouchEnd); document.addEventListener("touchmove", this.onReactTouchMove); @@ -190,10 +214,15 @@ export default class GestureOverlay extends Touchable { } onReactHoldTouchMove = (e: TouchEvent) => { + 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); 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", @@ -238,20 +267,18 @@ export default class GestureOverlay extends Touchable { } } - if (this.prevPoints.size === 0) { - document.removeEventListener("touchmove", this.onReactTouchMove); - document.removeEventListener("touchend", this.onReactTouchEnd); - } + document.removeEventListener("touchmove", this.onReactHoldTouchMove); + document.removeEventListener("touchend", this.onReactHoldTouchEnd); + e.stopPropagation(); } onReactTouchMove = (e: TouchEvent) => { const nts: any = this.getNewTouches(e); - if (this.prevPoints.size === 1 && this._holdTimer) { - clearTimeout(this._holdTimer); - this._holdTimer = undefined; - } + clearTimeout(this._holdTimer); + this._holdTimer = undefined; + document.dispatchEvent( new CustomEvent<InteractionUtils.MultiTouchEvent<TouchEvent>>("dashOnTouchMove", { @@ -269,10 +296,9 @@ 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; - } + clearTimeout(this._holdTimer); + this._holdTimer = undefined; + document.dispatchEvent( new CustomEvent<InteractionUtils.MultiTouchEvent<TouchEvent>>("dashOnTouchEnd", { @@ -303,6 +329,7 @@ export default class GestureOverlay extends Touchable { } handleHandDown = async (e: React.TouchEvent) => { + clearTimeout(this._holdTimer!); const fingers = new Array<React.Touch>(); for (let i = 0; i < e.touches.length; i++) { const pt: any = e.touches.item(i); @@ -352,6 +379,7 @@ export default class GestureOverlay extends Touchable { const thumbDoc = await Cast(CurrentUserUtils.setupThumbDoc(CurrentUserUtils.UserDocument), Doc); if (thumbDoc) { runInAction(() => { + RadialMenu.Instance._display = false; this._inkToTextDoc = FieldValue(Cast(thumbDoc.inkToTextDoc, Doc)); this._thumbDoc = thumbDoc; this._thumbX = thumb.clientX; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 1b886da2e..ff6e79836 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -540,7 +540,7 @@ export class MainView extends React.Component { </GestureOverlay> <PreviewCursor /> <ContextMenu /> - {/* <RadialMenu /> */} + <RadialMenu /> <PDFMenu /> <MarqueeOptionsMenu /> <RichTextMenu /> diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx index 13cc38589..bc3d07130 100644 --- a/src/client/views/Touchable.tsx +++ b/src/client/views/Touchable.tsx @@ -221,8 +221,8 @@ export abstract class Touchable<T = {}> extends React.Component<T> { handle1PointerHoldMove = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => { - e.stopPropagation(); - me.touchEvent.stopPropagation(); + // e.stopPropagation(); + // me.touchEvent.stopPropagation(); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 82cb3bc88..7a6d54ac2 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -249,6 +249,75 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp return true; } + + // + // Creates a split on the any side of the docking view, based on the passed input pullSide and then adds the Document to the requested side + // + @undoBatch + @action + public static AddSplit(document: Doc, pullSide: string, dataDoc: Doc | undefined, libraryPath?: Doc[]) { + if (!CollectionDockingView.Instance) return false; + const instance = CollectionDockingView.Instance; + const newItemStackConfig = { + type: 'stack', + content: [CollectionDockingView.makeDocumentConfig(document, dataDoc, undefined, libraryPath)] + }; + + const newContentItem = instance._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout); + + if (instance._goldenLayout.root.contentItems.length === 0) { // if no rows / columns + instance._goldenLayout.root.addChild(newContentItem); + } else if (instance._goldenLayout.root.contentItems[0].isRow) { // if row + if (pullSide === "left") { + instance._goldenLayout.root.contentItems[0].addChild(newContentItem, 0); + } else if (pullSide === "right") { + instance._goldenLayout.root.contentItems[0].addChild(newContentItem); + } else if (pullSide === "top" || pullSide === "bottom") { + // if not going in a row layout, must add already existing content into column + const rowlayout = instance._goldenLayout.root.contentItems[0]; + const newColumn = rowlayout.layoutManager.createContentItem({ type: "column" }, instance._goldenLayout); + rowlayout.parent.replaceChild(rowlayout, newColumn); + if (pullSide === "top") { + newColumn.addChild(rowlayout, undefined, true); + newColumn.addChild(newContentItem, 0, true); + } else if (pullSide === "bottom") { + newColumn.addChild(newContentItem, undefined, true); + newColumn.addChild(rowlayout, 0, true); + } + + rowlayout.config.height = 50; + newContentItem.config.height = 50; + } + } else if (instance._goldenLayout.root.contentItems[0].isColumn) { // if column + if (pullSide === "top") { + instance._goldenLayout.root.contentItems[0].addChild(newContentItem, 0); + } else if (pullSide === "bottom") { + instance._goldenLayout.root.contentItems[0].addChild(newContentItem); + } else if (pullSide === "left" || pullSide === "right") { + // if not going in a row layout, must add already existing content into column + const collayout = instance._goldenLayout.root.contentItems[0]; + const newRow = collayout.layoutManager.createContentItem({ type: "row" }, instance._goldenLayout); + collayout.parent.replaceChild(collayout, newRow); + + if (pullSide === "left") { + newRow.addChild(collayout, undefined, true); + newRow.addChild(newContentItem, 0, true); + } else if (pullSide === "right") { + newRow.addChild(newContentItem, undefined, true); + newRow.addChild(collayout, 0, true); + } + + collayout.config.width = 50; + newContentItem.config.width = 50; + } + } + + newContentItem.callDownwards('_$init'); + instance.layoutChanged(); + return true; + } + + // // Creates a vertical split on the right side of the docking view, and then adds the Document to that split // diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index f125403f9..c5028d16e 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -51,11 +51,13 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) { private gestureDisposer?: GestureUtils.GestureEventDisposer; protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; private _childLayoutDisposer?: IReactionDisposer; + protected _mainCont?: HTMLDivElement; protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view this.dropDisposer ?.(); this.gestureDisposer ?.(); this.multiTouchDisposer ?.(); if (ele) { + this._mainCont = ele; this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)); this.gestureDisposer = GestureUtils.MakeGestureTarget(ele, this.onGesture.bind(this)); this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(ele, this.onTouchStart.bind(this)); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index 58fb81453..2213b7882 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -34,6 +34,7 @@ height: 100%; display: flex; align-items: center; + .collectionfreeformview-placeholderSpan { font-size: 32; display: flex; @@ -97,4 +98,10 @@ #prevCursor { animation: blink 1s infinite; +} + +.pullpane-indicator { + z-index: 99999; + background-color: rgba($color: #000000, $alpha: .4); + position: absolute; }
\ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d988ff241..2f50fd710 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,6 +1,6 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faEye } from "@fortawesome/free-regular-svg-icons"; -import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons"; +import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload, faTextHeight } from "@fortawesome/free-solid-svg-icons"; import { action, computed, observable, ObservableMap, reaction, runInAction, IReactionDisposer } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocListCastAsync, Field } from "../../../../new_fields/Doc"; @@ -45,6 +45,9 @@ import { CognitiveServices } from "../../../cognitive_services/CognitiveServices import { RichTextField } from "../../../../new_fields/RichTextField"; import { List } from "../../../../new_fields/List"; import { DocumentViewProps } from "../../nodes/DocumentView"; +import { CollectionDockingView } from "../CollectionDockingView"; +import { MainView } from "../../MainView"; +import { TouchScrollableMenuItem } from "../../TouchScrollableMenu"; library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload); @@ -80,6 +83,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private _hitCluster = false; private _layoutComputeReaction: IReactionDisposer | undefined; private _layoutPoolData = new ObservableMap<string, any>(); + @observable private _pullCoords: number[] = [0, 0]; + @observable private _pullDirection: string = ""; public get displayName() { return "CollectionFreeFormView(" + this.props.Document.title ?.toString() + ")"; } // this makes mobx trace() statements more descriptive @observable.shallow _layoutElements: ViewDefResult[] = []; // shallow because some layout items (eg pivot labels) are just generated 'divs' and can't be frozen as observables @@ -454,8 +459,21 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } return false; }); - const inkFields = inks.map(i => Cast(i.data, InkField)); - CognitiveServices.Inking.Appliers.InterpretStrokes(inkFields.filter(i => i instanceof InkField).map(i => i!.inkData)).then((results) => { + // const inkFields = inks.map(i => Cast(i.data, InkField)); + const strokes: InkData[] = []; + inks.forEach(i => { + const d = Cast(i.data, InkField); + const x = NumCast(i.x); + const y = NumCast(i.y); + const left = Math.min(...d?.inkData.map(pd => pd.X) ?? [0]); + const top = Math.min(...d?.inkData.map(pd => pd.Y) ?? [0]); + if (d) { + strokes.push(d.inkData.map(pd => ({ X: pd.X + x - left, Y: pd.Y + y - top }))); + } + }); + + CognitiveServices.Inking.Appliers.InterpretStrokes(strokes).then((results) => { + console.log(results); const wordResults = results.filter((r: any) => r.category === "inkWord"); for (const word of wordResults) { const indices: number[] = word.strokeIds; @@ -469,7 +487,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (this._wordPalette.has(word.recognizedText.toLowerCase())) { inks[i].color = this._wordPalette.get(word.recognizedText.toLowerCase()); } - else { + else if (word.alternates) { for (const alt of word.alternates) { if (this._wordPalette.has(alt.recognizedString.toLowerCase())) { inks[i].color = this._wordPalette.get(alt.recognizedString.toLowerCase()); @@ -595,7 +613,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { const myTouches = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true); const pt1 = myTouches[0]; const pt2 = myTouches[1]; - console.log(myTouches); if (this.prevPoints.size === 2) { const oldPoint1 = this.prevPoints.get(pt1.identifier); @@ -624,7 +641,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { // use the centerx and centery as the "new mouse position" const centerX = Math.min(pt1.clientX, pt2.clientX) + Math.abs(pt2.clientX - pt1.clientX) / 2; const centerY = Math.min(pt1.clientY, pt2.clientY) + Math.abs(pt2.clientY - pt1.clientY) / 2; - this.pan({ clientX: centerX, clientY: centerY }); + // const transformed = this.getTransform().inverse().transformPoint(centerX, centerY); + + if (!this._pullDirection) { // if we are not bezel movement + this.pan({ clientX: centerX, clientY: centerY }); + } else { + this._pullCoords = [centerX, centerY]; + } + this._lastX = centerX; this._lastY = centerY; } @@ -649,6 +673,27 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { const centerY = Math.min(pt1.clientY, pt2.clientY) + Math.abs(pt2.clientY - pt1.clientY) / 2; this._lastX = centerX; this._lastY = centerY; + const screenBox = this._mainCont?.getBoundingClientRect(); + + + // determine if we are using a bezel movement + if (screenBox) { + if ((screenBox.right - centerX) < 100) { + this._pullCoords = [centerX, centerY]; + this._pullDirection = "right"; + } else if (centerX - screenBox.left < 100) { + this._pullCoords = [centerX, centerY]; + this._pullDirection = "left"; + } else if (screenBox.bottom - centerY < 100) { + this._pullCoords = [centerX, centerY]; + this._pullDirection = "bottom"; + } else if (centerY - screenBox.top < 100) { + this._pullCoords = [centerX, centerY]; + this._pullDirection = "top"; + } + } + + this.removeMoveListeners(); this.addMoveListeners(); this.removeEndListeners(); @@ -659,12 +704,36 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } cleanUpInteractions = () => { + + switch (this._pullDirection) { + + case "left": + CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], { title: "New Collection" }), "left", undefined); + break; + case "right": + CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], { title: "New Collection" }), "right", undefined); + break; + case "top": + CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], { title: "New Collection" }), "top", undefined); + break; + case "bottom": + CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], { title: "New Collection" }), "bottom", undefined); + break; + default: + break; + } + console.log(""); + + this._pullDirection = ""; + this._pullCoords = [0, 0]; + document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); this.removeMoveListeners(); this.removeEndListeners(); } + @action zoom = (pointX: number, pointY: number, deltaY: number): void => { let deltaScale = deltaY > 0 ? (1 / 1.1) : 1.1; @@ -1066,6 +1135,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } render() { TraceMobx(); + const clientRect = this._mainCont?.getBoundingClientRect(); // update the actual dimensions of the collection so that they can inquired (e.g., by a minimap) // this.Document.fitX = this.contentBounds && this.contentBounds.x; // this.Document.fitY = this.contentBounds && this.contentBounds.y; @@ -1088,7 +1158,20 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { {!this.Document._LODdisable && !this.props.active() && !this.props.isAnnotationOverlay && !this.props.annotationsKey && this.props.renderDepth > 0 ? // && this.props.CollectionView && lodarea < NumCast(this.Document.LODarea, 100000) ? this.placeholder : this.marqueeView} <CollectionFreeFormOverlayView elements={this.elementFunc} /> - </div>; + + <div className={"pullpane-indicator"} + style={{ + display: this._pullDirection ? "block" : "none", + top: clientRect ? this._pullDirection === "bottom" ? this._pullCoords[1] - clientRect.y : 0 : "auto", + // left: clientRect ? this._pullDirection === "right" ? this._pullCoords[0] - clientRect.x - MainView.Instance.flyoutWidth : 0 : "auto", + left: clientRect ? this._pullDirection === "right" ? this._pullCoords[0] - clientRect.x : 0 : "auto", + width: clientRect ? this._pullDirection === "left" ? this._pullCoords[0] - clientRect.left : this._pullDirection === "right" ? clientRect.right - this._pullCoords[0] : clientRect.width : 0, + height: clientRect ? this._pullDirection === "top" ? this._pullCoords[1] - clientRect.top : this._pullDirection === "bottom" ? clientRect.bottom - this._pullCoords[1] : clientRect.height : 0, + + }}> + </div> + + </div >; } } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 8591144c0..d4faa4dc1 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -21,6 +21,7 @@ import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import { SubCollectionViewProps } from "../CollectionSubView"; import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { RichTextField } from "../../../../new_fields/RichTextField"; +import { InteractionUtils } from "../../../util/InteractionUtils"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -383,16 +384,39 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque }); const inkFields = inks.map(i => Cast(i.data, InkField)); CognitiveServices.Inking.Appliers.InterpretStrokes(inkFields.filter(i => i instanceof InkField).map(i => i!.inkData)).then((results) => { + // const wordResults = results.filter((r: any) => r.category === "inkWord"); + // console.log(wordResults); + // console.log(results); + // for (const word of wordResults) { + // const indices: number[] = word.strokeIds; + // indices.forEach(i => { + // if (wordToColor.has(word.recognizedText.toLowerCase())) { + // inks[i].color = wordToColor.get(word.recognizedText.toLowerCase()); + // } + // else { + // for (const alt of word.alternates) { + // if (wordToColor.has(alt.recognizedString.toLowerCase())) { + // inks[i].color = wordToColor.get(alt.recognizedString.toLowerCase()); + // break; + // } + // } + // } + // }) + // } const wordResults = results.filter((r: any) => r.category === "inkWord"); - console.log(wordResults); - console.log(results); for (const word of wordResults) { const indices: number[] = word.strokeIds; indices.forEach(i => { + const otherInks: Doc[] = []; + indices.forEach(i2 => i2 !== i && otherInks.push(inks[i2])); + inks[i].relatedInks = new List<Doc>(otherInks); + const uniqueColors: string[] = []; + Array.from(wordToColor.values()).forEach(c => uniqueColors.indexOf(c) === -1 && uniqueColors.push(c)); + inks[i].alternativeColors = new List<string>(uniqueColors); if (wordToColor.has(word.recognizedText.toLowerCase())) { inks[i].color = wordToColor.get(word.recognizedText.toLowerCase()); } - else { + else if (word.alternates) { for (const alt of word.alternates) { if (wordToColor.has(alt.recognizedString.toLowerCase())) { inks[i].color = wordToColor.get(alt.recognizedString.toLowerCase()); @@ -400,7 +424,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque } } } - }) + }); } }); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 9ce0324ed..9182eb4c0 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -124,50 +124,71 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu private _firstY: number = -1; + handle1PointerHoldStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): any => { - this.addHoldMoveListeners(); - this.addHoldEndListeners(); - this.onRadialMenu(e, me); - const pt = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0]; - this._firstX = pt.pageX; - this._firstY = pt.pageY; + this.removeMoveListeners(); + this.removeEndListeners(); + document.removeEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); + console.log(SelectionManager.SelectedDocuments()); + console.log("START"); + if (RadialMenu.Instance._display === false) { + this.addHoldMoveListeners(); + this.addHoldEndListeners(); + this.onRadialMenu(e, me); + const pt = me.touchEvent.touches[me.touchEvent.touches.length - 1]; + this._firstX = pt.pageX; + this._firstY = pt.pageY; + } } handle1PointerHoldMove = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => { - const pt = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0]; - console.log(pt.pageX, this._firstX, pt.pageY, this._firstY); + + const pt = me.touchEvent.touches[me.touchEvent.touches.length - 1]; + 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 => { + this.removeHoldMoveListeners(); + this.removeHoldEndListeners(); RadialMenu.Instance.closeMenu(); this._firstX = -1; this._firstY = -1; + SelectionManager.DeselectAll(); + me.touchEvent.stopPropagation(); + me.touchEvent.preventDefault(); + e.stopPropagation(); + + } @action onRadialMenu = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): void => { - const pt = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0]; + console.log("DISPLAYMENUUUU"); + console.log(me.touchEvent.touches); + // console.log(InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)); + // const pt = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0]; + const pt = me.touchEvent.touches[me.touchEvent.touches.length - 1]; + RadialMenu.Instance.openMenu(pt.pageX - 15, pt.pageY - 15); - 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: "map-pin", selected: -1 }); + RadialMenu.Instance.addItem({ description: "Delete this document", event: () => { this.props.ContainingCollectionView?.removeDocument(this.props.Document), RadialMenu.Instance.closeMenu() }, icon: "layer-group", selected: -1 }); + RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, undefined, "onRight"), icon: "trash", selected: -1 }); + RadialMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.Document), icon: "folder", selected: -1 }); + + // if (SelectionManager.IsSelected(this, true)) { + // SelectionManager.SelectDoc(this, false); + // } + SelectionManager.DeselectAll(); - 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 @@ -189,7 +210,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._mainCont.current && (this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this))); } @action @@ -315,9 +336,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu } handle1PointerDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>) => { + SelectionManager.DeselectAll(); if (this.Document.onPointerDown) return; - const touch = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0]; - console.log("down"); + const touch = me.touchEvent.changedTouches.item(0); if (touch) { this._downX = touch.clientX; this._downY = touch.clientY; @@ -344,7 +365,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu this.removeMoveListeners(); } else if (!e.cancelBubble && (SelectionManager.IsSelected(this, true) || this.props.parentActive(true) || this.Document.onDragStart || this.Document.onClick) && !this.Document.lockedPosition && !this.Document.inOverlay) { - const touch = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0]; + + const touch = me.touchEvent.changedTouches.item(0); if (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3) { if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.Document.onClick)) { this.cleanUpInteractions(); @@ -499,11 +521,14 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu } onPointerUp = (e: PointerEvent): void => { + this.cleanUpInteractions(); + if (this.onPointerUpHandler && this.onPointerUpHandler.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { this.onPointerUpHandler.script.run({ this: this.Document.isTemplateForField && this.props.DataDoc ? this.props.DataDoc : this.props.Document }, console.log); document.removeEventListener("pointerup", this.onPointerUp); return; } + document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2); diff --git a/src/client/views/nodes/RadialMenu.tsx b/src/client/views/nodes/RadialMenu.tsx index 74c5f53bd..a6fb72a7b 100644 --- a/src/client/views/nodes/RadialMenu.tsx +++ b/src/client/views/nodes/RadialMenu.tsx @@ -24,12 +24,19 @@ export class RadialMenu extends React.Component { private _reactionDisposer?: IReactionDisposer; + catchTouch = (te: React.TouchEvent) => { + console.log("caught"); + te.stopPropagation(); + te.preventDefault(); + } + @action onPointerDown = (e: PointerEvent) => { this._mouseDown = true; this._mouseX = e.clientX; this._mouseY = e.clientY; document.addEventListener("pointermove", this.onPointerMove); + } @observable @@ -42,7 +49,6 @@ export class RadialMenu extends React.Component { const deltX = this._mouseX - curX; const deltY = this._mouseY - curY; const scale = Math.hypot(deltY, deltX); - if (scale < 150 && scale > 50) { const rad = Math.atan2(deltY, deltX) + Math.PI; let closest = 0; @@ -83,6 +89,7 @@ export class RadialMenu extends React.Component { @action componentDidMount = () => { + console.log(this._pageX); document.addEventListener("pointerdown", this.onPointerDown); document.addEventListener("pointerup", this.onPointerUp); this.previewcircle(); @@ -98,7 +105,7 @@ export class RadialMenu extends React.Component { @observable private _pageX: number = 0; @observable private _pageY: number = 0; - @observable private _display: boolean = false; + @observable _display: boolean = false; @observable private _yRelativeToTop: boolean = true; @@ -124,35 +131,34 @@ export class RadialMenu extends React.Component { displayMenu = (x: number, y: number) => { //maxX and maxY will change if the UI/font size changes, but will work for any amount //of items added to the menu - - this._pageX = x; - this._pageY = y; + this._mouseX = x; + this._mouseY = y; this._shouldDisplay = true; } - - get pageX() { - const x = this._pageX; - if (x < 0) { - return 0; - } - const width = this._width; - if (x + width > window.innerWidth - RadialMenu.buffer) { - return window.innerWidth - RadialMenu.buffer - width; - } - return x; - } - - get pageY() { - const y = this._pageY; - if (y < 0) { - return 0; - } - const height = this._height; - if (y + height > window.innerHeight - RadialMenu.buffer) { - return window.innerHeight - RadialMenu.buffer - height; - } - return y; - } + // @computed + // get pageX() { + // const x = this._pageX; + // if (x < 0) { + // return 0; + // } + // const width = this._width; + // if (x + width > window.innerWidth - RadialMenu.buffer) { + // return window.innerWidth - RadialMenu.buffer - width; + // } + // return x; + // } + // @computed + // get pageY() { + // const y = this._pageY; + // if (y < 0) { + // return 0; + // } + // const height = this._height; + // if (y + height > window.innerHeight - RadialMenu.buffer) { + // return window.innerHeight - RadialMenu.buffer - height; + // } + // return y; + // } @computed get menuItems() { return this._items.map((item, index) => <RadialMenuItem {...item} key={item.description} closeMenu={this.closeMenu} max={this._items.length} min={index} selected={this._closest} />); @@ -166,7 +172,10 @@ export class RadialMenu extends React.Component { } @action - openMenu = () => { + openMenu = (x: number, y: number) => { + + this._pageX = x; + this._pageY = y; this._shouldDisplay; this._display = true; } @@ -207,12 +216,12 @@ export class RadialMenu extends React.Component { if (!this._display) { return null; } - const style = this._yRelativeToTop ? { left: this._mouseX - 150, top: this._mouseY - 150 } : - { left: this._mouseX - 150, top: this._mouseY - 150 }; + const style = this._yRelativeToTop ? { left: this._pageX - 130, top: this._pageY - 130 } : + { left: this._pageX - 130, top: this._pageY - 130 }; return ( - <div className="radialMenu-cont" style={style}> + <div className="radialMenu-cont" onTouchStart={this.catchTouch} style={style}> <canvas id="newCanvas" style={{ position: "absolute" }} height="300" width="300"> Your browser does not support the HTML5 canvas tag.</canvas> {this.menuItems} </div> diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index 4dde3a075..f00c77203 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -78,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, @@ -102,6 +102,7 @@ export default class MobileInkOverlay extends React.Component { const complete = new DragManager.DragCompleteEvent(false, dragData); if (target) { + console.log("dispatching upload doc!!!!", target, doc); target.dispatchEvent( new CustomEvent<DragManager.DropEvent>("dashOnDrop", { diff --git a/src/pen-gestures/ndollar.ts b/src/pen-gestures/ndollar.ts index 365896197..bb92f62e1 100644 --- a/src/pen-gestures/ndollar.ts +++ b/src/pen-gestures/ndollar.ts @@ -185,7 +185,7 @@ export class NDollarRecognizer { this.Multistrokes[3] = new Multistroke(GestureUtils.Gestures.EndBracket, useBoundedRotationInvariance, new Array( // new Array(new Point(150, 21), new Point(149, 150), new Point(26, 152)) // new Array(new Point(150, 150), new Point(150, 0), new Point(150, 150), new Point(0, 150)) - new Array(new Point(10, 100), new Point(50, 100), new Point(100, 12), new Point(150, 103), new Point(190, 100)) + new Array(new Point(10, 100), new Point(100, 100), new Point(150, 12), new Point(200, 103), new Point(300, 100)) )); // diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 71da0b380..a7cc6d3e9 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -156,7 +156,7 @@ export class CurrentUserUtils { static setupMobileUploadDoc(userDoc: Doc) { // const addButton = Docs.Create.FontIconDocument({ onDragStart: ScriptField.MakeScript('addWebToMobileUpload()'), title: "Add Web Doc to Upload Collection", icon: "plus", backgroundColor: "black" }) - const webDoc = Docs.Create.WebDocument("https://www.britannica.com/animal/cat", { + const webDoc = Docs.Create.WebDocument("https://www.britannica.com/biography/Miles-Davis", { title: "Upload Images From the Web", _chromeStatus: "enabled", lockedPosition: true }); const uploadDoc = Docs.Create.StackingDocument([], { |