diff options
Diffstat (limited to 'src/client/util/DragManager.ts')
-rw-r--r-- | src/client/util/DragManager.ts | 227 |
1 files changed, 147 insertions, 80 deletions
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 9ffe964ef..4bd654e15 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,13 +1,14 @@ -import { DocumentDecorations } from "../views/DocumentDecorations"; -import { CollectionDockingView } from "../views/collections/CollectionDockingView"; -import { Document } from "../../fields/Document" import { action } from "mobx"; -import { ImageField } from "../../fields/ImageField"; +import { Document } from "../../fields/Document"; +import { FieldWaiting } from "../../fields/Field"; import { KeyStore } from "../../fields/KeyStore"; -import { CollectionView } from "../views/collections/CollectionView"; -import { DocumentView } from "../views/nodes/DocumentView"; +import { emptyFunction } from "../../Utils"; +import { CollectionDockingView } from "../views/collections/CollectionDockingView"; +import { DocumentDecorations } from "../views/DocumentDecorations"; +import * as globalCssVariables from "../views/globalCssVariables.scss"; +import { MainOverlayTextBox } from "../views/MainOverlayTextBox"; -export function setupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc: () => Document, removeFunc: (containingCollection: CollectionView) => void = () => { }) { +export function SetupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc: () => Document, moveFunc?: DragManager.MoveFunction, copyOnDrop: boolean = false) { let onRowMove = action((e: PointerEvent): void => { e.stopPropagation(); e.preventDefault(); @@ -15,8 +16,9 @@ export function setupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc: document.removeEventListener("pointermove", onRowMove); document.removeEventListener('pointerup', onRowUp); var dragData = new DragManager.DocumentDragData([docFunc()]); - dragData.removeDocument = removeFunc; - DragManager.StartDocumentDrag([_reference.current!], dragData); + dragData.copyOnDrop = copyOnDrop; + dragData.moveDocument = moveFunc; + DragManager.StartDocumentDrag([_reference.current!], dragData, e.x, e.y); }); let onRowUp = action((e: PointerEvent): void => { document.removeEventListener("pointermove", onRowMove); @@ -24,20 +26,45 @@ export function setupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc: }); let onItemDown = (e: React.PointerEvent) => { // if (this.props.isSelected() || this.props.isTopMost) { - if (e.button == 0) { + if (e.button === 0) { e.stopPropagation(); if (e.shiftKey) { CollectionDockingView.Instance.StartOtherDrag([docFunc()], e); } else { document.addEventListener("pointermove", onRowMove); - document.addEventListener('pointerup', onRowUp); + document.addEventListener("pointerup", onRowUp); } } //} - } + }; return onItemDown; } +export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: number, sourceDoc: Document) { + let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document); + let draggedDocs = (srcTarg && srcTarg !== FieldWaiting) ? + srcTarg.GetList(KeyStore.LinkedToDocs, [] as Document[]).map(linkDoc => + (linkDoc.GetT(KeyStore.LinkedToDocs, Document)) as Document) : []; + let draggedFromDocs = (srcTarg && srcTarg !== FieldWaiting) ? + srcTarg.GetList(KeyStore.LinkedFromDocs, [] as Document[]).map(linkDoc => + (linkDoc.GetT(KeyStore.LinkedFromDocs, Document)) as Document) : []; + draggedDocs.push(...draggedFromDocs); + if (draggedDocs.length) { + let moddrag = [] as Document[]; + for (const draggedDoc of draggedDocs) { + let doc = await draggedDoc.GetTAsync(KeyStore.AnnotationOn, Document); + if (doc) moddrag.push(doc); + } + let dragData = new DragManager.DocumentDragData(moddrag.length ? moddrag : draggedDocs); + DragManager.StartDocumentDrag([dragEle], dragData, x, y, { + handlers: { + dragComplete: action(emptyFunction), + }, + hideSource: false + }); + } +} + export namespace DragManager { export function Root() { const root = document.getElementById("root"); @@ -50,7 +77,9 @@ export namespace DragManager { let dragDiv: HTMLDivElement; export enum DragButtons { - Left = 1, Right = 2, Both = Left | Right + Left = 1, + Right = 2, + Both = Left | Right } interface DragOptions { @@ -63,8 +92,7 @@ export namespace DragManager { (): void; } - export class DragCompleteEvent { - } + export class DragCompleteEvent { } export interface DragHandlers { dragComplete: (e: DragCompleteEvent) => void; @@ -74,21 +102,27 @@ export namespace DragManager { handlers: DropHandlers; } export class DropEvent { - constructor(readonly x: number, readonly y: number, readonly data: { [id: string]: any }) { } + constructor( + readonly x: number, + readonly y: number, + readonly data: { [id: string]: any } + ) { } } - - export interface DropHandlers { drop: (e: Event, de: DropEvent) => void; } - - export function MakeDropTarget(element: HTMLElement, options: DropOptions): DragDropDisposer { + export function MakeDropTarget( + element: HTMLElement, + options: DropOptions + ): DragDropDisposer { if ("canDrop" in element.dataset) { - throw new Error("Element is already droppable, can't make it droppable again"); + throw new Error( + "Element is already droppable, can't make it droppable again" + ); } - element.dataset["canDrop"] = "true"; + element.dataset.canDrop = "true"; const handler = (e: Event) => { const ce = e as CustomEvent<DropEvent>; options.handlers.drop(e, ce.detail); @@ -96,84 +130,102 @@ export namespace DragManager { element.addEventListener("dashOnDrop", handler); return () => { element.removeEventListener("dashOnDrop", handler); - delete element.dataset["canDrop"] + delete element.dataset.canDrop; }; } + export type MoveFunction = (document: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean; export class DocumentDragData { constructor(dragDoc: Document[]) { this.draggedDocuments = dragDoc; this.droppedDocuments = dragDoc; + this.xOffset = 0; + this.yOffset = 0; } draggedDocuments: Document[]; droppedDocuments: Document[]; - xOffset?: number; - yOffset?: number; + xOffset: number; + yOffset: number; aliasOnDrop?: boolean; - removeDocument?: (collectionDrop: CollectionView) => void; + copyOnDrop?: boolean; + moveDocument?: MoveFunction; [id: string]: any; } - export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, options?: DragOptions) { - StartDrag(eles, dragData, options, (dropData: { [id: string]: any }) => dropData.droppedDocuments = dragData.aliasOnDrop ? dragData.draggedDocuments.map(d => d.CreateAlias()) : dragData.draggedDocuments); + export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) { + StartDrag(eles, dragData, downX, downY, options, + (dropData: { [id: string]: any }) => (dropData.droppedDocuments = dragData.aliasOnDrop ? dragData.draggedDocuments.map(d => d.CreateAlias()) : dragData.copyOnDrop ? dragData.draggedDocuments.map(d => d.Copy(true) as Document) : dragData.draggedDocuments)); } export class LinkDragData { - constructor(linkSourceDoc: DocumentView) { - this.linkSourceDocumentView = linkSourceDoc; + constructor(linkSourceDoc: Document) { + this.linkSourceDocument = linkSourceDoc; } - linkSourceDocumentView: DocumentView; + droppedDocuments: Document[] = []; + linkSourceDocument: Document; [id: string]: any; } - export function StartLinkDrag(ele: HTMLElement, dragData: LinkDragData, options?: DragOptions) { - StartDrag([ele], dragData, options); + + export function StartLinkDrag(ele: HTMLElement, dragData: LinkDragData, downX: number, downY: number, options?: DragOptions) { + StartDrag([ele], dragData, downX, downY, options); } - function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, options?: DragOptions, finishDrag?: (dropData: { [id: string]: any }) => void) { + + function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: { [id: string]: any }) => void) { if (!dragDiv) { dragDiv = document.createElement("div"); - dragDiv.className = "dragManager-dragDiv" + dragDiv.className = "dragManager-dragDiv"; DragManager.Root().appendChild(dragDiv); } + MainOverlayTextBox.Instance.SetTextDoc(); let scaleXs: number[] = []; let scaleYs: number[] = []; let xs: number[] = []; let ys: number[] = []; - const docs: Document[] = dragData instanceof DocumentDragData ? dragData.draggedDocuments : []; + const docs: Document[] = + dragData instanceof DocumentDragData ? dragData.draggedDocuments : []; let dragElements = eles.map(ele => { - const w = ele.offsetWidth, h = ele.offsetHeight; + const w = ele.offsetWidth, + h = ele.offsetHeight; const rect = ele.getBoundingClientRect(); - const scaleX = rect.width / w, scaleY = rect.height / h; - let x = rect.left, y = rect.top; - xs.push(x); ys.push(y); - scaleXs.push(scaleX); scaleYs.push(scaleY); + const scaleX = rect.width / w, + scaleY = rect.height / h; + let x = rect.left, + y = rect.top; + xs.push(x); + ys.push(y); + scaleXs.push(scaleX); + scaleYs.push(scaleY); let dragElement = ele.cloneNode(true) as HTMLElement; dragElement.style.opacity = "0.7"; dragElement.style.position = "absolute"; + dragElement.style.margin = "0"; + dragElement.style.top = "0"; dragElement.style.bottom = ""; - dragElement.style.left = ""; + dragElement.style.left = "0"; dragElement.style.transformOrigin = "0 0"; - dragElement.style.zIndex = "1000"; + dragElement.style.zIndex = globalCssVariables.contextMenuZindex;// "1000"; dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; dragElement.style.width = `${rect.width / scaleX}px`; dragElement.style.height = `${rect.height / scaleY}px`; - // bcz: PDFs don't show up if you clone them because they contain a canvas. + // bcz: if PDFs are rendered with svg's, then this code isn't needed + // bcz: PDFs don't show up if you clone them when rendered using a canvas. // however, PDF's have a thumbnail field that contains an image of their canvas. // So we replace the pdf's canvas with the image thumbnail - if (docs.length) { - var pdfBox = dragElement.getElementsByClassName("pdfBox-cont")[0] as HTMLElement; - let thumbnail = docs[0].GetT(KeyStore.Thumbnail, ImageField); - if (pdfBox && pdfBox.childElementCount && thumbnail) { - let img = new Image(); - img!.src = thumbnail.toString(); - img!.style.position = "absolute"; - img!.style.width = `${rect.width / scaleX}px`; - img!.style.height = `${rect.height / scaleY}px`; - pdfBox.replaceChild(img!, pdfBox.children[0]) - } - } + // if (docs.length) { + // var pdfBox = dragElement.getElementsByClassName("pdfBox-cont")[0] as HTMLElement; + // let thumbnail = docs[0].GetT(KeyStore.Thumbnail, ImageField); + // if (pdfBox && pdfBox.childElementCount && thumbnail) { + // let img = new Image(); + // img.src = thumbnail.toString(); + // img.style.position = "absolute"; + // img.style.width = `${rect.width / scaleX}px`; + // img.style.height = `${rect.height / scaleY}px`; + // pdfBox.replaceChild(img, pdfBox.children[0]) + // } + // } dragDiv.appendChild(dragElement); return dragElement; @@ -187,26 +239,42 @@ export namespace DragManager { hideSource = options.hideSource(); } } - eles.map(ele => ele.hidden = hideSource); + eles.map(ele => (ele.hidden = hideSource)); + let lastX = downX; + let lastY = downY; const moveHandler = (e: PointerEvent) => { e.stopPropagation(); e.preventDefault(); - if (dragData instanceof DocumentDragData) + if (dragData instanceof DocumentDragData) { dragData.aliasOnDrop = e.ctrlKey || e.altKey; + } if (e.shiftKey) { abortDrag(); - CollectionDockingView.Instance.StartOtherDrag(docs, { pageX: e.pageX, pageY: e.pageY, preventDefault: () => { }, button: 0 }); + CollectionDockingView.Instance.StartOtherDrag(docs, { + pageX: e.pageX, + pageY: e.pageY, + preventDefault: emptyFunction, + button: 0 + }); } - dragElements.map((dragElement, i) => dragElement.style.transform = `translate(${xs[i] += e.movementX}px, ${ys[i] += e.movementY}px) scale(${scaleXs[i]}, ${scaleYs[i]})`); + //TODO: Why can't we use e.movementX and e.movementY? + let moveX = e.pageX - lastX; + let moveY = e.pageY - lastY; + lastX = e.pageX; + lastY = e.pageY; + dragElements.map((dragElement, i) => (dragElement.style.transform = + `translate(${(xs[i] += moveX)}px, ${(ys[i] += moveY)}px) + scale(${scaleXs[i]}, ${scaleYs[i]})`) + ); }; const abortDrag = () => { document.removeEventListener("pointermove", moveHandler, true); document.removeEventListener("pointerup", upHandler); dragElements.map(dragElement => dragDiv.removeChild(dragElement)); - eles.map(ele => ele.hidden = false); - } + eles.map(ele => (ele.hidden = false)); + }; const upHandler = (e: PointerEvent) => { abortDrag(); FinishDrag(eles, e, dragData, options, finishDrag); @@ -218,29 +286,28 @@ export namespace DragManager { function FinishDrag(dragEles: HTMLElement[], e: PointerEvent, dragData: { [index: string]: any }, options?: DragOptions, finishDrag?: (dragData: { [index: string]: any }) => void) { let removed = dragEles.map(dragEle => { let parent = dragEle.parentElement; - if (parent) - parent.removeChild(dragEle); + if (parent) parent.removeChild(dragEle); return [dragEle, parent]; }); const target = document.elementFromPoint(e.x, e.y); removed.map(r => { - let dragEle: HTMLElement = r[0]!; - let parent: HTMLElement | null = r[1]; - if (parent) - parent.appendChild(dragEle); + let dragEle = r[0]; + let parent = r[1]; + if (parent && dragEle) parent.appendChild(dragEle); }); if (target) { - if (finishDrag) - finishDrag(dragData); - - target.dispatchEvent(new CustomEvent<DropEvent>("dashOnDrop", { - bubbles: true, - detail: { - x: e.x, - y: e.y, - data: dragData - } - })); + if (finishDrag) finishDrag(dragData); + + target.dispatchEvent( + new CustomEvent<DropEvent>("dashOnDrop", { + bubbles: true, + detail: { + x: e.x, + y: e.y, + data: dragData + } + }) + ); if (options) { options.handlers.dragComplete({}); @@ -248,4 +315,4 @@ export namespace DragManager { } DocumentDecorations.Instance.Hidden = false; } -}
\ No newline at end of file +} |