Skip to content

Commit

Permalink
Add cancelling the dragging
Browse files Browse the repository at this point in the history
  • Loading branch information
mohamedsalem401 committed Sep 20, 2024
1 parent 150a1e6 commit e6e9c2f
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 71 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/block_manager/view/BlockView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export default class BlockView extends View<Block> {
// things (throws false positives). As this method just need to drop away
// the block helper I use the trick of 'moved = 0' to void those errors.
sorter.moved = 0;
sorter.endMove();
sorter.cancelDrag();
}

render() {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/commands/view/MoveComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export default extend({}, SelectPosition, SelectComponent, {
var key = e.which || e.keyCode;
if (key == 27 || force) {
this.sorter.moved = false;
this.sorter.endMove();
this.sorter.cancelDrag();
}
return;
},
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/commands/view/SelectPosition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default {
this.posIndex = this.posMethod == 'after' && this.cDim.length !== 0 ? this.posIndex + 1 : this.posIndex; //Normalize
if (this.sorter) {
this.sorter.moved = 0;
this.sorter.endMove();
this.sorter.cancelDrag();
}
if (this.cDim) {
this.posIsLastEl = this.cDim.length !== 0 && this.posMethod == 'after' && this.posIndex == this.cDim.length;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/utils/Droppable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ export default class Droppable {
sorter.startSort(el ? [el] : []);
this.sorter = sorter;
dragStop = () => {
sorter.endMove();
sorter.endDrag();
};
}

Expand Down
24 changes: 19 additions & 5 deletions packages/core/src/utils/sorter/ComponentSorter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ import { BaseComponentNode } from "./BaseComponentNode";
import Sorter from "./Sorter";
import { SorterContainerContext, PositionOptions, SorterDragBehaviorOptions, SorterEventHandlers } from './types';

const targetSpotType = CanvasSpotBuiltInTypes.Target;

const spotTarget = {
id: 'sorter-target',
type: targetSpotType,
};

export default class ComponentSorter extends Sorter<Component, BaseComponentNode> {
targetIsText: boolean = false;
constructor({
Expand Down Expand Up @@ -66,7 +73,7 @@ export default class ComponentSorter extends Sorter<Component, BaseComponentNode
}

onMouseMove = (mouseEvent: MouseEvent) => {
const insertingTextableIntoText = this.targetIsText && this.sourceNodes?.some(node => node.model?.get?.('textable'))
const insertingTextableIntoText = this.targetIsText && this.sourceNodes?.some(node => node.isTextable())
if (insertingTextableIntoText) {
this.updateTextViewCursorPosition(mouseEvent);
}
Expand Down Expand Up @@ -99,7 +106,6 @@ export default class ComponentSorter extends Sorter<Component, BaseComponentNode
}

private addSourceNodeToTarget(sourceNode: BaseComponentNode, targetNode: BaseComponentNode, index: number) {
sourceNode.clearState();
if (!targetNode.canMove(sourceNode, index)) {
return;
}
Expand All @@ -119,9 +125,19 @@ export default class ComponentSorter extends Sorter<Component, BaseComponentNode
return addedNode;
}

/**
* Finalize the move by removing any helpers and selecting the target model.
*
* @private
*/
protected finalizeMove(): void {
this.em?.Canvas.removeSpots(spotTarget);
this.sourceNodes?.forEach(node => node.clearState());
super.finalizeMove();
}

private onTargetChange = (oldTargetNode: BaseComponentNode | undefined, newTargetNode: BaseComponentNode | undefined) => {
oldTargetNode?.clearState();

if (!newTargetNode) {
return
}
Expand All @@ -138,7 +154,6 @@ export default class ComponentSorter extends Sorter<Component, BaseComponentNode
}
}


private updateTextViewCursorPosition(e: any) {
const { em } = this;
if (!em) return;
Expand Down Expand Up @@ -172,7 +187,6 @@ export default class ComponentSorter extends Sorter<Component, BaseComponentNode
range && sel?.addRange(range);
}


/**
* Toggle cursor while sorting
* @param {Boolean} active
Expand Down
94 changes: 52 additions & 42 deletions packages/core/src/utils/sorter/DropLocationDeterminer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class DropLocationDeterminer<T, NodeType extends SortableTreeNode<T>> ext
this.positionOptions = options.positionOptions;
this.dragBehavior = options.dragBehavior;
this.eventHandlers = options.eventHandlers || {};
bindAll(this, 'startSort', 'onMove', 'endMove', 'onDragStart');
bindAll(this, 'startSort', 'onDragStart', 'onMove', 'endDrag');
this.containerOffset = {
top: 0,
left: 0
Expand All @@ -63,7 +63,7 @@ export class DropLocationDeterminer<T, NodeType extends SortableTreeNode<T>> ext
private bindDragEventHandlers(docs: Document[]) {
on(this.containerContext.container, 'dragstart', this.onDragStart);
on(this.containerContext.container, 'mousemove dragover', this.onMove);
on(docs, 'mouseup dragend touchend', this.endMove);
on(docs, 'mouseup dragend touchend', this.endDrag);
}

onMove(mouseEvent: MouseEvent): void {
Expand Down Expand Up @@ -112,55 +112,31 @@ export class DropLocationDeterminer<T, NodeType extends SortableTreeNode<T>> ext
this.eventHandlers.onDragStart && this.eventHandlers.onDragStart(mouseEvent);
}

/**
* Retrieves the first element that has a data model associated with it.
* Traverses up the DOM tree from the given element until it reaches the container
* or an element with a data model.
*
* @param mouseTargetEl - The element to start searching from.
* @returns The first element with a data model, or null if not found.
*/
private getFirstElementWithAModel(mouseTargetEl: HTMLElement | null): HTMLElement | null {
const isModelPresent = (el: HTMLElement) => $(el).data("model") !== undefined;

while (mouseTargetEl && mouseTargetEl !== this.containerContext.container) {
if (isModelPresent(mouseTargetEl)) {
return mouseTargetEl;
}

mouseTargetEl = mouseTargetEl.parentElement;
}

return null;
endDrag(): void {
this.dropDragged();
this.finalizeMove();
}

private getValidParentNode(targetNode: NodeType) {
let finalNode = targetNode;
// TODO change the hard coded values
while (finalNode.getParent() !== null) {
const canMove = this.sourceNodes.some(node => finalNode.canMove(node, 0));
if (canMove) break
finalNode = finalNode.getParent()! as NodeType;
}
cancelDrag() {
this.eventHandlers.onTargetChange?.(this.targetNode, undefined);
this.finalizeMove();
}

return finalNode;
private finalizeMove() {
this.cleanupEventListeners();
this.triggerOnDragEndEvent();
this.eventHandlers.onEndMove?.();
}

/**
* End the move action.
* Handles the cleanup and final steps after an item is moved.
*/
endMove(): void {
private dropDragged() {
const targetNode = this.targetNode;
const lastPos = this.lastPos;
let index = -1;
if (lastPos) {
index = lastPos.method === 'after' ? lastPos.indexEl + 1 : lastPos.indexEl
index = lastPos.method === 'after' ? lastPos.indexEl + 1 : lastPos.indexEl;
}
this.eventHandlers.onDrop?.(targetNode, this.sourceNodes, index)
this.eventHandlers.onEndMove?.()
this.cleanupEventListeners();
this.triggerOnDragEndEvent();

this.eventHandlers.onDrop?.(targetNode, this.sourceNodes, index);
}

private triggerOnDragEndEvent() {
Expand All @@ -185,6 +161,40 @@ export class DropLocationDeterminer<T, NodeType extends SortableTreeNode<T>> ext
return { lastPos, targetNode };
}

/**
* Retrieves the first element that has a data model associated with it.
* Traverses up the DOM tree from the given element until it reaches the container
* or an element with a data model.
*
* @param mouseTargetEl - The element to start searching from.
* @returns The first element with a data model, or null if not found.
*/
private getFirstElementWithAModel(mouseTargetEl: HTMLElement | null): HTMLElement | null {
const isModelPresent = (el: HTMLElement) => $(el).data("model") !== undefined;

while (mouseTargetEl && mouseTargetEl !== this.containerContext.container) {
if (isModelPresent(mouseTargetEl)) {
return mouseTargetEl;
}

mouseTargetEl = mouseTargetEl.parentElement;
}

return null;
}

private getValidParentNode(targetNode: NodeType) {
let finalNode = targetNode;
// TODO change the hard coded values
while (finalNode.getParent() !== null) {
const canMove = this.sourceNodes.some(node => finalNode.canMove(node, 0));
if (canMove) break
finalNode = finalNode.getParent()! as NodeType;
}

return finalNode;
}

/**
* Clean up event listeners that were attached during the move.
*
Expand All @@ -197,7 +207,7 @@ export class DropLocationDeterminer<T, NodeType extends SortableTreeNode<T>> ext
const docs = this.docs;
off(container, 'dragstart', this.onDragStart);
off(container, 'mousemove dragover', this.onMove);
off(docs, 'mouseup dragend touchend', this.endMove);
off(docs, 'mouseup dragend touchend', this.endDrag);
}

/**
Expand Down
43 changes: 23 additions & 20 deletions packages/core/src/utils/sorter/Sorter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { bindAll, isFunction, contains } from 'underscore';
import { $, View } from '../../common';
import { bindAll } from 'underscore';
import { $ } from '../../common';
import EditorModel from '../../editor/model/Editor';
import { off, on } from '../dom';
import { SortableTreeNode } from './SortableTreeNode';
Expand All @@ -13,12 +13,11 @@ export type RequiredEmAndTreeClassPartialSorterOptions<T, NodeType extends Sorta
em: EditorModel;
treeClass: new (model: T) => NodeType;
};

export default class Sorter<T, NodeType extends SortableTreeNode<T>> {
em: EditorModel;
treeClass: new (model: T) => NodeType;
placeholder: PlaceholderClass;
dropLocationDeterminer!: DropLocationDeterminer<T, NodeType>;
dropLocationDeterminer: DropLocationDeterminer<T, NodeType>;

positionOptions: PositionOptions;
containerContext: SorterContainerContext;
Expand All @@ -30,7 +29,7 @@ export default class Sorter<T, NodeType extends SortableTreeNode<T>> {
constructor(sorterOptions: SorterOptions<T, NodeType>) {
const mergedOptions = getMergedOptions<T, NodeType>(sorterOptions);

bindAll(this, 'startSort', 'endMove', 'rollback', 'updateOffset');
bindAll(this, 'startSort', 'cancelDrag', 'rollback', 'updateOffset');
this.containerContext = mergedOptions.containerContext;
this.positionOptions = mergedOptions.positionOptions;
this.dragBehavior = mergedOptions.dragBehavior;
Expand Down Expand Up @@ -152,16 +151,19 @@ export default class Sorter<T, NodeType extends SortableTreeNode<T>> {
}

/**
* End the move action.
* Handles the cleanup and final steps after an item is moved.
*/
endMove(): void {
const docs = this.docs;
this.cleanupEventListeners(docs);
this.placeholder.hide();
this.dropLocationDeterminer.endMove();
this.finalizeMove();
this.eventHandlers.legacyOnEnd?.({ sorter: this })
* Called when the drag operation should be cancelled
*/
cancelDrag(): void {
this.placeholder.hide();
this.dropLocationDeterminer.cancelDrag()
this.finalizeMove();
}

/**
* Called to drop an item onto a valid target.
*/
endDrag() {
this.dropLocationDeterminer.endDrag()
}

/**
Expand All @@ -175,13 +177,14 @@ export default class Sorter<T, NodeType extends SortableTreeNode<T>> {
}

/**
* Finalize the move by removing any helpers and selecting the target model.
* Finalize the move.
*
* @private
*/
private finalizeMove(): void {
// @ts-ignore
this.em?.Canvas.removeSpots(this.spotTarget);
protected finalizeMove(): void {
const docs = this.docs;
this.cleanupEventListeners(docs);
this.eventHandlers.legacyOnEnd?.({ sorter: this })
}

/**
Expand All @@ -194,7 +197,7 @@ export default class Sorter<T, NodeType extends SortableTreeNode<T>> {
const ESC_KEY = 'Escape';

if (e.key === ESC_KEY) {
// TODO add canceling
this.cancelDrag();
}
}
}

0 comments on commit e6e9c2f

Please sign in to comment.