aboutsummaryrefslogtreecommitdiff
path: root/src/client/util/DragManager.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/util/DragManager.ts')
-rw-r--r--src/client/util/DragManager.ts54
1 files changed, 38 insertions, 16 deletions
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 1f093a33c..f6af6196f 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -1,10 +1,24 @@
+/**
+ * The DragManager handles all dragging interactions that occur entirely within Dash (as opposed to external drag operations from the file system, etc)
+ *
+ * Events are generated for
+ * a pause in the drag movement (dashDragMovePause) as a Doc(s) is dragged,
+ * just before (dashPreDrop) a Doc(s) is dropped,
+ * and just after (dashDropEvent) a Doc(s) is dropped
+ * If the document is dragged and paused over the golden layout header tabs, the
+ * drag interaction will switch to a golden layout tab drag.
+ *
+ * All drag operations can be aborted by hitting the Esc key
+ *
+ */
+
import { action, observable, runInAction } from 'mobx';
import { DateField } from '../../fields/DateField';
import { Doc, Field, Opt, StrListCast } from '../../fields/Doc';
import { List } from '../../fields/List';
import { PrefetchProxy } from '../../fields/Proxy';
import { ScriptField } from '../../fields/ScriptField';
-import { ScriptCast, StrCast } from '../../fields/Types';
+import { ScriptCast } from '../../fields/Types';
import { emptyFunction, Utils } from '../../Utils';
import { Docs, DocUtils } from '../documents/Documents';
import { CollectionFreeFormDocumentView } from '../views/nodes/CollectionFreeFormDocumentView';
@@ -16,7 +30,15 @@ import { UndoManager } from './UndoManager';
import { DocData } from '../../fields/DocSymbols';
const { default : { contextMenuZindex } } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore
-export type dropActionType = 'embed' | 'copy' | 'move' | 'add' | 'same' | 'inSame' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove
+export enum dropActionType {
+ embed = 'embed', // create a new embedding of the dragged document for the new location
+ copy = 'copy', // copy the dragged document
+ move = 'move', // move the dragged document to the drop location after removing it from where it was
+ add = 'add', // add the dragged document to the drop location without removing it from where it was
+ same = 'same', // only allow drop within same collection (or same hierarchical tree collection)
+ inPlace = 'inSame', // keep document in place (unless overridden by a drag modifier)
+ proto = 'proto',
+} // undefined = move, same = move but doesn't call dropPropertiesToRemove
/**
* Initialize drag
@@ -129,9 +151,9 @@ export namespace DragManager {
treeViewDoc?: Doc;
offset: number[];
canEmbed?: boolean;
- userDropAction: dropActionType; // the user requested drop action -- this will be honored as specified by modifier keys
+ userDropAction?: dropActionType; // the user requested drop action -- this will be honored as specified by modifier keys
defaultDropAction?: dropActionType; // an optionally specified default drop action when there is no user drop actionl - this will be honored if there is no user drop action
- dropAction: dropActionType; // a drop action request by the initiating code. the actual drop action may be different -- eg, if the request is 'embed', but the document is dropped within the same collection, the drop action will be switched to 'move'
+ dropAction?: dropActionType; // a drop action request by the initiating code. the actual drop action may be different -- eg, if the request is 'embed', but the document is dropped within the same collection, the drop action will be switched to 'move'
dropPropertiesToRemove?: string[];
moveDocument?: MoveFunction;
removeDocument?: RemoveFunction;
@@ -170,8 +192,8 @@ export namespace DragManager {
dropDocCreator: (annotationOn: Doc | undefined) => Doc;
dropDocument?: Doc;
offset: number[];
- dropAction: dropActionType;
- userDropAction: dropActionType;
+ dropAction?: dropActionType;
+ userDropAction?: dropActionType;
}
let defaultPreDropFunc = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => {
@@ -189,7 +211,7 @@ export namespace DragManager {
const handler = (e: Event) => dropFunc(e, (e as CustomEvent<DropEvent>).detail);
const preDropHandler = (e: Event) => {
const de = (e as CustomEvent<DropEvent>).detail;
- (preDropFunc ?? defaultPreDropFunc)(e, de, StrCast(doc.dropAction) as dropActionType);
+ (preDropFunc ?? defaultPreDropFunc)(e, de, doc.dropAction as any as dropActionType);
};
element.addEventListener('dashOnDrop', handler);
element.addEventListener('dashPreDrop', preDropHandler);
@@ -218,19 +240,19 @@ export namespace DragManager {
dragData.draggedDocuments.map(async d =>
!dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart)
? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result)
- : docDragData.dropAction === 'embed'
+ : docDragData.dropAction === dropActionType.embed
? Doc.BestEmbedding(d)
- : docDragData.dropAction === 'add'
+ : docDragData.dropAction === dropActionType.add
? d
- : docDragData.dropAction === 'proto'
+ : docDragData.dropAction === dropActionType.proto
? d[DocData]
- : docDragData.dropAction === 'copy'
+ : docDragData.dropAction === dropActionType.copy
? (await Doc.MakeClone(d)).clone
: d
)
)
).filter(d => d);
- !['same', 'proto'].includes(docDragData.dropAction as any) &&
+ ![dropActionType.same, dropActionType.proto].includes(docDragData.dropAction as any) &&
docDragData.droppedDocuments
// .filter(drop => !drop.dragOnlyWithinContainer || ['embed', 'copy'].includes(docDragData.dropAction as any))
.forEach((drop: Doc, i: number) => {
@@ -504,7 +526,7 @@ export namespace DragManager {
const moveHandler = (e: PointerEvent) => {
e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop
if (dragData instanceof DocumentDragData) {
- dragData.userDropAction = e.ctrlKey && e.altKey ? 'copy' : e.shiftKey ? 'move' : e.ctrlKey ? 'embed' : dragData.defaultDropAction;
+ dragData.userDropAction = e.ctrlKey && e.altKey ? dropActionType.copy : e.shiftKey ? dropActionType.move : e.ctrlKey ? dropActionType.embed : dragData.defaultDropAction;
}
if (['lm_tab', 'lm_title_wrap', 'lm_tabs', 'lm_header'].includes(typeof (e.target as any).className === 'string' ? (e.target as any)?.className : '') && dragData.draggedDocuments.length === 1) {
if (!startWindowDragTimer) {
@@ -530,7 +552,7 @@ export namespace DragManager {
if (target && !Doc.UserDoc()._noAutoscroll && !options?.noAutoscroll && !dragData.draggedDocuments?.some((d: any) => d._freeform_noAutoPan)) {
const autoScrollHandler = () => {
target.dispatchEvent(
- new CustomEvent<React.DragEvent>('dashDragAutoScroll', {
+ new CustomEvent<React.DragEvent>('dashDragMovePause', {
bubbles: true,
detail: {
shiftKey: e.shiftKey,
@@ -552,7 +574,7 @@ export namespace DragManager {
screenY: e.screenY,
detail: e.detail,
view: e.view ? e.view : (new Window() as any),
- nativeEvent: new DragEvent('dashDragAutoScroll'),
+ nativeEvent: new DragEvent('dashDragMovePause'),
currentTarget: target,
target: target,
bubbles: true,
@@ -566,7 +588,7 @@ export namespace DragManager {
isPropagationStopped: () => ('not implemented for this event' ? false : false),
persist: emptyFunction,
timeStamp: e.timeStamp,
- type: 'dashDragAutoScroll',
+ type: 'dashDragMovePause',
},
})
);