Browse Source

Refactor droplocationdeteminer and improve performance

refactor-sorter
mohamedsalem401 1 year ago
parent
commit
2bd54b62ca
  1. 4
      packages/core/src/commands/view/SelectPosition.ts
  2. 4
      packages/core/src/navigator/view/ItemsView.ts
  3. 4
      packages/core/src/style_manager/view/LayersView.ts
  4. 6
      packages/core/src/utils/Droppable.ts
  5. 14
      packages/core/src/utils/sorter/ComponentSorter.ts
  6. 228
      packages/core/src/utils/sorter/DropLocationDeterminer.ts
  7. 20
      packages/core/src/utils/sorter/PlaceholderClass.ts
  8. 4
      packages/core/src/utils/sorter/SortableTreeNode.ts
  9. 40
      packages/core/src/utils/sorter/Sorter.ts
  10. 21
      packages/core/src/utils/sorter/SorterUtils.ts
  11. 5
      packages/core/src/utils/sorter/StyleManagerSorter.ts
  12. 20
      packages/core/src/utils/sorter/types.ts

4
packages/core/src/commands/view/SelectPosition.ts

@ -1,6 +1,6 @@
import { $ } from '../../common';
import CanvasComponentNode from '../../utils/sorter/CanvasComponentNode';
import { SorterDirection } from '../../utils/sorter/types';
import { DragDirection } from '../../utils/sorter/types';
import { CommandObject } from './CommandAbstract';
export default {
/**
@ -31,7 +31,7 @@ export default {
canvasRelative: true,
},
dragBehavior: {
dragDirection: SorterDirection.BothDirections,
dragDirection: DragDirection.BothDirections,
nested: true,
}
});

4
packages/core/src/navigator/view/ItemsView.ts

@ -5,7 +5,7 @@ import EditorModel from '../../editor/model/Editor';
import ItemView from './ItemView';
import Components from '../../dom_components/model/Components';
import LayerManager from '..';
import { SorterDirection } from '../../utils/sorter/types';
import { DragDirection } from '../../utils/sorter/types';
import LayersComponentNode from '../../utils/sorter/LayersComponentNode';
export default class ItemsView extends View {
@ -51,7 +51,7 @@ export default class ItemsView extends View {
placeholderElement: this.placeholderElement
},
dragBehavior: {
dragDirection: SorterDirection.Vertical,
dragDirection: DragDirection.Vertical,
ignoreViewChildren: true,
nested: true,
}

4
packages/core/src/style_manager/view/LayersView.ts

@ -1,6 +1,6 @@
import { View } from '../../common';
import EditorModel from '../../editor/model/Editor';
import { SorterDirection } from '../../utils/sorter/types';
import { DragDirection } from '../../utils/sorter/types';
import Layer from '../model/Layer';
import Layers from '../model/Layers';
import LayerView from './LayerView';
@ -46,7 +46,7 @@ export default class LayersView extends View<Layer> {
placeholderElement: this.placeholderElement
},
dragBehavior: {
dragDirection: SorterDirection.Vertical,
dragDirection: DragDirection.Vertical,
ignoreViewChildren: true,
nested: true,
},

6
packages/core/src/utils/Droppable.ts

@ -3,7 +3,7 @@ import CanvasModule from '../canvas';
import { ObjectStrings } from '../common';
import EditorModel from '../editor/model/Editor';
import { getDocumentScroll, off, on } from './dom';
import { SorterDirection } from './sorter/types';
import { DragDirection } from './sorter/types';
import CanvasNewComponentNode from './sorter/CanvasNewComponentNode';
// TODO move in sorter
@ -158,7 +158,7 @@ export default class Droppable {
dragStop = (cancel?: boolean) => dragger.stop(ev, { cancel });
dragContent = (cnt: any) => (content = cnt);
} else {
const handleOnDrop = (targetNode: CanvasNewComponentNode | undefined, sourceNodes: CanvasNewComponentNode[], index: number): void => {
const handleOnDrop = (targetNode: CanvasNewComponentNode | undefined, sourceNodes: CanvasNewComponentNode[], index: number | undefined): void => {
if (!targetNode) return
const insertingTextableIntoText = targetNode.model?.isInstanceOf?.('text') && sourceNodes?.some(node => node.model?.get?.('textable'));
let sourceModel;
@ -184,7 +184,7 @@ export default class Droppable {
document: this.el.ownerDocument,
},
dragBehavior: {
dragDirection: SorterDirection.BothDirections,
dragDirection: DragDirection.BothDirections,
ignoreViewChildren: true,
nested: true,
},

14
packages/core/src/utils/sorter/ComponentSorter.ts

@ -42,7 +42,7 @@ export default class ComponentSorter extends Sorter<Component, BaseComponentNode
eventHandlers.onStartSort?.(sourceNodes, containerElement);
this.onStartSort();
},
onDrop: (targetNode: BaseComponentNode | undefined, sourceNodes: BaseComponentNode[], index: number) => {
onDrop: (targetNode: BaseComponentNode | undefined, sourceNodes: BaseComponentNode[], index: number | undefined) => {
eventHandlers.onDrop?.(targetNode, sourceNodes, index);
this.onDrop(targetNode, sourceNodes, index);
},
@ -58,7 +58,7 @@ export default class ComponentSorter extends Sorter<Component, BaseComponentNode
});
}
onStartSort() {
private onStartSort() {
this.em.clearSelection();
this.toggleSortCursor(true);
const model = this.sourceNodes?.[0].model;
@ -72,15 +72,16 @@ export default class ComponentSorter extends Sorter<Component, BaseComponentNode
});
}
onMouseMove = (mouseEvent: MouseEvent) => {
private onMouseMove = (mouseEvent: MouseEvent) => {
const insertingTextableIntoText = this.targetIsText && this.sourceNodes?.some(node => node.isTextable())
if (insertingTextableIntoText) {
this.updateTextViewCursorPosition(mouseEvent);
}
}
onDrop = (targetNode: BaseComponentNode | undefined, sourceNodes: BaseComponentNode[], index: number) => {
private onDrop = (targetNode: BaseComponentNode | undefined, sourceNodes: BaseComponentNode[], index: number | undefined) => {
if (!targetNode) return
index = typeof index === 'number' ? index : -1;
const legacyOnEndMove = this.eventHandlers.legacyOnEndMove;
const model = this.sourceNodes?.[0].model;
const data = {
@ -101,7 +102,6 @@ export default class ComponentSorter extends Sorter<Component, BaseComponentNode
legacyOnEndMove?.(null, this, { ...data, cancelled: 1 });
}
this.placeholder.hide();
}
@ -199,8 +199,4 @@ export default class ComponentSorter extends Sorter<Component, BaseComponentNode
// Noticeable with "fast" drag of blocks
cv && (active ? cv.startAutoscroll() : cv.stopAutoscroll());
}
get scale() {
return () => this.em!.getZoomDecimal()
}
}

228
packages/core/src/utils/sorter/DropLocationDeterminer.ts

@ -4,36 +4,63 @@ import EditorModel from '../../editor/model/Editor';
import { isTextNode, off, on } from '../dom';
import { getModel } from '../mixins';
import { SortableTreeNode } from './SortableTreeNode';
import { Dimension, Position, PositionOptions, SorterContainerContext, SorterDirection, SorterDragBehaviorOptions, SorterEventHandlers } from './types';
import { Dimension, Placement, PositionOptions, DragDirection, SorterEventHandlers, CustomTarget } from './types';
import { bindAll, each } from 'underscore';
import { matches, findPosition, offset, isInFlow } from './SorterUtils';
type ContainerContext = {
container: HTMLElement;
itemSel: string;
customTarget?: CustomTarget;
};
interface DropLocationDeterminerOptions<T, NodeType extends SortableTreeNode<T>> {
em: EditorModel;
treeClass: new (model: T) => NodeType;
containerContext: SorterContainerContext;
containerContext: ContainerContext;
positionOptions: PositionOptions;
dragBehavior: SorterDragBehaviorOptions;
dragDirection: DragDirection;
eventHandlers: SorterEventHandlers<NodeType>;
}
/**
* Represents the data related to the last move event during drag-and-drop sorting.
* This type is discriminated by the presence or absence of a valid target node.
*/
type LastMoveData<NodeType> =
| {
/** The target node under the mouse pointer during the last move. */
lastTargetNode: NodeType;
/** The index where the placeholder or dragged element should be inserted. */
lastIndex: number;
/** Placement relative to the target ('before' or 'after'). */
lastPlacement: Placement;
/** The dimensions of the child elements within the target node. */
lastChildrenDimensions: Dimension[];
}
| {
/** Indicates that there is no valid target node. */
lastTargetNode: undefined;
lastIndex: undefined;
lastPlacement: undefined;
lastChildrenDimensions: undefined;
};
export class DropLocationDeterminer<T, NodeType extends SortableTreeNode<T>> extends View {
em: EditorModel;
treeClass: new (model: any) => NodeType;
positionOptions: PositionOptions;
containerContext: SorterContainerContext;
dragBehavior: SorterDragBehaviorOptions;
containerContext: ContainerContext;
dragDirection: DragDirection;
eventHandlers: SorterEventHandlers<NodeType>;
targetNode?: NodeType;
lastPos?: Position;
targetDimensions?: Dimension[];
sourceNodes!: NodeType[];
docs!: Document[];
containerOffset: {
top: number;
left: number;
sourceNodes: NodeType[] = [];
lastMoveData!: LastMoveData<NodeType>;
docs: Document[] = [];
containerOffset = {
top: 0,
left: 0,
}
constructor(options: DropLocationDeterminerOptions<T, NodeType>) {
@ -42,13 +69,11 @@ export class DropLocationDeterminer<T, NodeType extends SortableTreeNode<T>> ext
this.em = options.em;
this.containerContext = options.containerContext;
this.positionOptions = options.positionOptions;
this.dragBehavior = options.dragBehavior;
this.dragDirection = options.dragDirection;
this.eventHandlers = options.eventHandlers || {};
bindAll(this, 'startSort', 'onDragStart', 'onMove', 'endDrag');
this.containerOffset = {
top: 0,
left: 0
};
this.restLastMoveData();
}
/**
@ -66,51 +91,124 @@ export class DropLocationDeterminer<T, NodeType extends SortableTreeNode<T>> ext
on(docs, 'mouseup dragend touchend', this.endDrag);
}
onMove(mouseEvent: MouseEvent): void {
private onMove(mouseEvent: MouseEvent): void {
this.eventHandlers.onMouseMove?.(mouseEvent);
const customTarget = this.containerContext.customTarget;
this.cacheContainerPosition(this.containerContext.container);
const { mouseXRelativeToContainer, mouseYRelativeToContainer } = this.getMousePositionRelativeToContainer(mouseEvent);
let mouseTargetEl: HTMLElement | null = customTarget ? customTarget({ event: mouseEvent }) : mouseEvent.target as HTMLElement;
const targetEl = this.getFirstElementWithAModel(mouseTargetEl);
if (!targetEl) return
const targetModel = $(targetEl)?.data("model");
const mouseTargetNode = new this.treeClass(targetModel);
const targetNode = this.getValidParentNode(mouseTargetNode);
const { mouseXRelativeToContainer: mouseX, mouseYRelativeToContainer: mouseY } = this.getMousePositionRelativeToContainer(mouseEvent);
const targetNode = this.getTargetNode(mouseEvent);
if (!targetNode) {
this.eventHandlers.onPlaceholderPositionChange?.(false);
return
this.eventHandlers.onTargetChange?.(this.lastMoveData.lastTargetNode, undefined);
this.restLastMoveData();
this.triggerMoveEvent(mouseX, mouseY);
return;
}
const dims = this.dimsFromTarget(targetNode);
const pos = findPosition(dims, mouseXRelativeToContainer, mouseYRelativeToContainer);
this.eventHandlers.onPlaceholderPositionChange?.(true, dims, pos);
this.eventHandlers.onTargetChange?.(this.targetNode, targetNode);
this.targetNode = targetNode;
this.lastPos = pos;
this.targetDimensions = dims;
// Handle movement over the valid target node
const index = this.handleMovementOnTarget(targetNode, mouseX, mouseY);
this.triggerMoveEvent(mouseX, mouseY);
this.triggerLegacyOnMoveCallback(mouseEvent, index);
}
private restLastMoveData() {
this.lastMoveData = {
lastTargetNode: undefined,
lastIndex: undefined,
lastPlacement: undefined,
lastChildrenDimensions: undefined,
};
}
// For compatibility with old sorter
private triggerLegacyOnMoveCallback(mouseEvent: MouseEvent, index: number) {
this.eventHandlers.legacyOnMoveClb?.({
event: mouseEvent,
target: this.sourceNodes.map(node => node.model),
parent: this.targetNode.model,
index: pos.index + (pos.method == 'after' ? 1 : 0),
parent: this.lastMoveData.lastTargetNode?.model,
index: index,
});
}
private triggerMoveEvent(mouseX: number, mouseY: number) {
const { lastTargetNode: targetNode, lastPlacement: placement, lastIndex: index, lastChildrenDimensions: childrenDimensions } = this.lastMoveData;
const legacyIndex = index ? (index + (placement === 'after' ? -1 : 0)) : 0;
this.em.trigger('sorter:drag', {
target: targetEl,
targetModel,
sourceModel: this.sourceNodes.map(node => node.model),
dims,
pos,
x: mouseXRelativeToContainer,
y: mouseYRelativeToContainer,
target: targetNode?.element || null,
targetModel: this.lastMoveData.lastTargetNode?.model,
sourceModel: this.sourceNodes[0].model,
dims: childrenDimensions || [],
pos: {
index: legacyIndex,
indexEl: legacyIndex,
placement
},
x: mouseX,
y: mouseY,
});
}
/**
* Handles the movement of the dragged element over a target node.
* Updates the placeholder position and triggers relevant events when necessary.
*
* @param hoveredNode - The node currently being hovered over.
* @param mouseX - The x-coordinate of the mouse relative to the container.
* @param mouseY - The y-coordinate of the mouse relative to the container.
* @returns The index at which the placeholder should be positioned.
*/
private handleMovementOnTarget(hoveredNode: NodeType, mouseX: number, mouseY: number): number {
const { lastTargetNode, lastChildrenDimensions } = this.lastMoveData;
const targetChanged = !hoveredNode.equals(lastTargetNode);
this.eventHandlers.onTargetChange?.(lastTargetNode, hoveredNode);
const childrenDimensions = targetChanged ? this.dimsFromTarget(hoveredNode) : lastChildrenDimensions!;
let { index, placement } = findPosition(childrenDimensions, mouseX, mouseY);
const elementDimension = childrenDimensions[index];
index = index + (placement == 'after' ? 1 : 0);
if (this.hasDropPositionChanged(targetChanged, index, placement)) {
this.eventHandlers.onPlaceholderPositionChange?.(true, elementDimension, placement);
}
this.lastMoveData = {
lastTargetNode: hoveredNode,
lastChildrenDimensions: childrenDimensions,
lastIndex: index,
lastPlacement: placement,
};
return index;
}
/**
* Checks if the drop position has changed.
*
* @param targetChanged - Whether the target node has changed.
* @param newIndex - The new index for the placeholder.
* @param newPlacement - The new placement for the placeholder.
* @returns Whether the drop position has changed.
*/
private hasDropPositionChanged(targetChanged: boolean, newIndex: number, newPlacement: Placement): boolean {
const { lastIndex, lastPlacement } = this.lastMoveData;
return targetChanged || lastIndex !== newIndex || lastPlacement !== newPlacement;
}
private getTargetNode(mouseEvent: MouseEvent) {
const customTarget = this.containerContext.customTarget;
this.cacheContainerPosition(this.containerContext.container);
let mouseTargetEl: HTMLElement | null = customTarget ? customTarget({ event: mouseEvent }) : mouseEvent.target as HTMLElement;
const targetEl = this.getFirstElementWithAModel(mouseTargetEl);
if (!targetEl) return
const targetModel = $(targetEl)?.data("model");
const mouseTargetNode = new this.treeClass(targetModel);
const targetNode = this.getValidParentNode(mouseTargetNode);
return targetNode;
}
private onDragStart(mouseEvent: MouseEvent): void {
this.eventHandlers.onDragStart && this.eventHandlers.onDragStart(mouseEvent);
}
@ -121,7 +219,8 @@ export class DropLocationDeterminer<T, NodeType extends SortableTreeNode<T>> ext
}
cancelDrag() {
this.eventHandlers.onTargetChange?.(this.targetNode, undefined);
const { lastTargetNode } = this.lastMoveData;
this.eventHandlers.onTargetChange?.(lastTargetNode, undefined);
this.finalizeMove();
}
@ -132,36 +231,31 @@ export class DropLocationDeterminer<T, NodeType extends SortableTreeNode<T>> ext
}
private dropDragged() {
const targetNode = this.targetNode;
const lastPos = this.lastPos;
let index = -1;
if (lastPos) {
index = lastPos.method === 'after' ? lastPos.indexEl + 1 : lastPos.indexEl;
}
this.eventHandlers.onDrop?.(targetNode, this.sourceNodes, index);
const { lastTargetNode, lastIndex } = this.lastMoveData;
this.eventHandlers.onDrop?.(lastTargetNode, this.sourceNodes, lastIndex);
}
private triggerOnDragEndEvent() {
const targetNode = this.targetNode;
const lastPos = this.lastPos;
const { lastTargetNode: targetNode } = this.lastMoveData;
// For backward compatibility, leave it to a single node
const sourceNode = this.sourceNodes[0];
this.em.trigger('sorter:drag:end', {
targetCollection: this.targetNode ? this.targetNode.getChildren() : null,
modelToDrop: this.sourceNodes.map(node => node.model),
targetCollection: targetNode ? targetNode.getChildren() : null,
modelToDrop: sourceNode.model,
warns: [''],
validResult: {
result: true,
src: this.sourceNodes.map(node => node.element),
srcModel: this.sourceNodes.map(node => node.model),
srcModel: sourceNode.model,
trg: targetNode?.element,
trgModel: targetNode?.model,
draggable: true,
droppable: true,
},
dst: targetNode?.element,
srcEl: this.sourceNodes.map(node => node.element),
srcEl: sourceNode.element,
});
return { lastPos, targetNode };
}
/**
@ -255,11 +349,11 @@ export class DropLocationDeterminer<T, NodeType extends SortableTreeNode<T>> ext
// TODO
const dim = this.getDim(el, containerOffset.left, containerOffset.top, this.positionOptions.relative!, !!this.positionOptions.canvasRelative, this.positionOptions.windowMargin!, this.em);
let dir = this.dragBehavior.dragDirection;
let dir = this.dragDirection;
let dirValue: boolean;
if (dir === SorterDirection.Vertical) dirValue = true;
else if (dir === SorterDirection.Horizontal) dirValue = false;
if (dir === DragDirection.Vertical) dirValue = true;
else if (dir === DragDirection.Horizontal) dirValue = false;
else dirValue = isInFlow(el, targetElement);
dim.dir = dirValue;

20
packages/core/src/utils/sorter/PlaceholderClass.ts

@ -1,5 +1,5 @@
import { View } from '../../common';
import { Dimension, Position } from './types';
import { Dimension, Placement } from './types';
export class PlaceholderClass extends View {
pfx: string;
@ -41,13 +41,12 @@ export class PlaceholderClass extends View {
/**
* Updates the position of the placeholder.
* @param {Dimension[]} elementsDimension Array of element dimensions.
* @param {Position} position Object representing position details (index and method).
* @param {Dimension} [targetDimension] Optional target dimensions ([top, left, height, width]).
* @param {Dimension} elementDimension element dimensions.
* @param {Position} placement either before or after the target.
*/
move(
elementsDimension: Dimension[],
position: Position,
elementDimension: Dimension,
placement: Placement,
) {
const marginOffset = 0;
const unit = 'px';
@ -55,12 +54,7 @@ export class PlaceholderClass extends View {
let left = 0;
let width = '';
let height = '';
const { method, index } = position;
const elementDimension = elementsDimension[index];
this.setOrientation(elementDimension);
const { top: elTop, left: elLeft, height: elHeight, width: elWidth, dir } = elementDimension;
if (!dir) {
@ -68,13 +62,13 @@ export class PlaceholderClass extends View {
width = 'auto';
height = (elHeight - marginOffset * 2) + unit;
top = elTop + marginOffset;
left = method === 'before' ? elLeft - marginOffset : elLeft + elWidth - marginOffset;
left = placement === 'before' ? elLeft - marginOffset : elLeft + elWidth - marginOffset;
this.setToVertical();
} else {
width = elWidth + unit;
height = 'auto';
top = method === 'before' ? elTop - marginOffset : elTop + elHeight - marginOffset;
top = placement === 'before' ? elTop - marginOffset : elTop + elHeight - marginOffset;
left = elLeft;
}

4
packages/core/src/utils/sorter/SortableTreeNode.ts

@ -79,4 +79,8 @@ export abstract class SortableTreeNode<T> {
get model(): T {
return this._model;
}
equals(node?: SortableTreeNode<T>): boolean {
return !!node?._model && this._model === node._model;
}
}

40
packages/core/src/utils/sorter/Sorter.ts

@ -6,7 +6,7 @@ import { SortableTreeNode } from './SortableTreeNode';
import { DropLocationDeterminer } from './DropLocationDeterminer';
import { PlaceholderClass } from './PlaceholderClass';
import { getMergedOptions, getDocument, matches, closest } from './SorterUtils';
import { SorterContainerContext, PositionOptions, SorterDragBehaviorOptions, SorterEventHandlers, Dimension, Position, OnPlaceholderPositionChangeHandler } from './types';
import { SorterContainerContext, PositionOptions, SorterDragBehaviorOptions, SorterEventHandlers, Dimension, OnPlaceholderPositionChangeHandler, Placement } from './types';
import { SorterOptions } from './types';
export type RequiredEmAndTreeClassPartialSorterOptions<T, NodeType extends SortableTreeNode<T>> = Partial<SorterOptions<T, NodeType>> & {
@ -29,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', 'cancelDrag', 'rollback', 'updateOffset');
bindAll(this, 'startSort', 'cancelDrag', 'rollback', 'updateOffset', 'handlePlaceholderMove');
this.containerContext = mergedOptions.containerContext;
this.positionOptions = mergedOptions.positionOptions;
this.dragBehavior = mergedOptions.dragBehavior;
@ -41,36 +41,34 @@ export default class Sorter<T, NodeType extends SortableTreeNode<T>> {
this.em.on(this.em.Canvas.events.refresh, this.updateOffset);
this.placeholder = this.createPlaceholder();
const onPlaceholderPositionChange = this.handlePlaceholderMove().bind(this) as OnPlaceholderPositionChangeHandler;
this.dropLocationDeterminer = new DropLocationDeterminer({
em: this.em,
treeClass: this.treeClass,
containerContext: this.containerContext,
positionOptions: this.positionOptions,
dragBehavior: this.dragBehavior,
dragDirection: this.dragBehavior.dragDirection,
eventHandlers: {
...this.eventHandlers,
onPlaceholderPositionChange
onPlaceholderPositionChange: this.handlePlaceholderMove as OnPlaceholderPositionChangeHandler
},
});
}
private handlePlaceholderMove() {
return (
show: boolean,
dims: Dimension[],
newPosition: Position) => {
if (show) {
this.ensurePlaceholderElement();
this.placeholder.show();
this.updatePlaceholderPosition(dims, newPosition);
} else {
this.placeholder.hide();
}
};
private handlePlaceholderMove(
show: boolean,
elementDimension: Dimension,
placement: Placement,
) {
if (show) {
this.ensurePlaceholderElement();
this.placeholder.show();
this.updatePlaceholderPosition(elementDimension, placement);
} else {
this.placeholder.hide();
}
}
/**
* Creates a new placeholder element for the drag-and-drop operation.
*
@ -157,8 +155,8 @@ export default class Sorter<T, NodeType extends SortableTreeNode<T>> {
this.dropLocationDeterminer.updateDocs(docs);
}
private updatePlaceholderPosition(dims: Dimension[], pos: Position) {
this.placeholder.move(dims, pos)
private updatePlaceholderPosition(targetDimension: Dimension, placement: Placement) {
this.placeholder.move(targetDimension, placement)
}
/**

21
packages/core/src/utils/sorter/SorterUtils.ts

@ -4,7 +4,7 @@ import { isTextNode } from '../dom';
import { matches as matchesMixin } from '../mixins';
import { SortableTreeNode } from './SortableTreeNode';
import { RequiredEmAndTreeClassPartialSorterOptions } from './Sorter';
import { Dimension, Position, SorterDirection } from './types';
import { Dimension, Placement, DragDirection } from './types';
/**
* Find the position based on passed dimensions and coordinates
@ -13,8 +13,8 @@ import { Dimension, Position, SorterDirection } from './types';
* @param {number} posY Y coordindate
* @return {Object}
* */
export function findPosition(dims: Dimension[], posX: number, posY: number): Position {
const result: Position = { index: 0, indexEl: 0, method: 'before' };
export function findPosition(dims: Dimension[], posX: number, posY: number) {
const result = { index: 0, placement: 'before' as Placement };
let leftLimit = 0;
let xLimit = 0;
let dimRight = 0;
@ -42,24 +42,23 @@ export function findPosition(dims: Dimension[], posX: number, posY: number): Pos
(leftLimit && dimRight < leftLimit))
continue;
result.index = i;
result.indexEl = dim.indexEl!;
// If it's not in flow (like 'float' element)
if (!dim.dir) {
if (posY < dimDown) yLimit = dimDown;
//If x lefter than center
if (posX < xCenter) {
xLimit = xCenter;
result.method = 'before';
result.placement = 'before';
} else {
leftLimit = xCenter;
result.method = 'after';
result.placement = 'after';
}
} else {
// If y upper than center
if (posY < yCenter) {
result.method = 'before';
result.placement = 'before';
break;
} else result.method = 'after'; // After last element
} else result.placement = 'after'; // After last element
}
}
@ -300,7 +299,7 @@ export function getMergedOptions<T, NodeType extends SortableTreeNode<T>>(sorter
canvasRelative: false
},
dragBehavior: {
dragDirection: SorterDirection.Vertical,
dragDirection: DragDirection.Vertical,
nested: false,
ignoreViewChildren: false,
selectOnEnd: true,
@ -330,7 +329,3 @@ export function getMergedOptions<T, NodeType extends SortableTreeNode<T>>(sorter
};
return mergedOptions;
}
export function hasPointerPositionChanged(pos: Position, lastPos?: Position) {
return !lastPos || lastPos.index !== pos.index || lastPos.method !== pos.method;
}

5
packages/core/src/utils/sorter/StyleManagerSorter.ts

@ -30,7 +30,7 @@ export default class StyleManagerSorter extends Sorter<Layers | Layer, LayerNode
eventHandlers.onStartSort?.(sourceNodes, containerElement);
this.onLayerStartSort(sourceNodes);
},
onDrop: (targetNode: LayerNode | undefined, sourceNodes: LayerNode[], index: number) => {
onDrop: (targetNode: LayerNode | undefined, sourceNodes: LayerNode[], index: number | undefined) => {
eventHandlers.onDrop?.(targetNode, sourceNodes, index);
this.onLayerDrop(targetNode, sourceNodes, index);
},
@ -48,10 +48,11 @@ export default class StyleManagerSorter extends Sorter<Layers | Layer, LayerNode
});
}
onLayerDrop = (targetNode: LayerNode | undefined, sourceNodes: LayerNode[], index: number) => {
onLayerDrop = (targetNode: LayerNode | undefined, sourceNodes: LayerNode[], index: number | undefined) => {
if (!targetNode) {
return;
}
index = typeof index === 'number' ? index : -1;
for (let idx = 0; idx < sourceNodes.length; idx++) {
const sourceNode = sourceNodes[idx];
if (!targetNode.canMove(sourceNode, idx)) {

20
packages/core/src/utils/sorter/types.ts

@ -13,18 +13,18 @@ export interface Dimension {
indexEl?: number;
}
export interface Position {
index: number;
indexEl: number;
method: string;
}
export type Placement = 'before' | 'after';
export enum SorterDirection {
export enum DragDirection {
Vertical = "Vertical",
Horizontal = "Horizontal",
BothDirections = "BothDirections"
}
export type CustomTarget = ({ event }: {
event: MouseEvent;
}) => HTMLElement | null;
export interface SorterContainerContext {
container: HTMLElement;
containerSel: string;
@ -32,7 +32,7 @@ export interface SorterContainerContext {
pfx: string;
document: Document;
placeholderElement: HTMLElement;
customTarget?: ({ event }: { event: MouseEvent }) => HTMLElement | null;
customTarget?: CustomTarget;
}
export interface PositionOptions {
@ -60,11 +60,11 @@ type OnStartSortHandler<NodeType> = (sourceNodes: NodeType[], container?: HTMLEl
*/
type OnDragStartHandler = (mouseEvent: MouseEvent) => void;
type OnMouseMoveHandler = (mouseEvent: MouseEvent) => void;
type OnDropHandler<NodeType> = (targetNode: NodeType | undefined, sourceNodes: NodeType[], index: number) => void;
type OnDropHandler<NodeType> = (targetNode: NodeType | undefined, sourceNodes: NodeType[], index: number | undefined) => void;
type OnTargetChangeHandler<NodeType> = (oldTargetNode: NodeType | undefined, newTargetNode: NodeType | undefined) => void;
export type OnPlaceholderPositionChangeHandler = {
(show: false): void;
(show: true, dims: Dimension[], newPosition: Position): void;
(show: true, targetDimension: Dimension, placement: Placement): void;
};
type OnEndMoveHandler = () => void;
@ -88,7 +88,7 @@ export interface SorterEventHandlers<NodeType> {
}
export interface SorterDragBehaviorOptions {
dragDirection: SorterDirection;
dragDirection: DragDirection;
ignoreViewChildren?: boolean;
nested?: boolean;
selectOnEnd?: boolean;

Loading…
Cancel
Save