Improve Wysiwyg editor
This commit is contained in:
156
ts_web/elements/wysiwyg/wysiwyg.dragdrophandler.ts
Normal file
156
ts_web/elements/wysiwyg/wysiwyg.dragdrophandler.ts
Normal file
@ -0,0 +1,156 @@
|
||||
import { type IBlock } from './wysiwyg.types.js';
|
||||
|
||||
export class WysiwygDragDropHandler {
|
||||
private component: any;
|
||||
private draggedBlockId: string | null = null;
|
||||
private dragOverBlockId: string | null = null;
|
||||
private dragOverPosition: 'before' | 'after' | null = null;
|
||||
|
||||
constructor(component: any) {
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current drag state
|
||||
*/
|
||||
get dragState() {
|
||||
return {
|
||||
draggedBlockId: this.draggedBlockId,
|
||||
dragOverBlockId: this.dragOverBlockId,
|
||||
dragOverPosition: this.dragOverPosition
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles drag start
|
||||
*/
|
||||
handleDragStart(e: DragEvent, block: IBlock): void {
|
||||
if (!e.dataTransfer) return;
|
||||
|
||||
this.draggedBlockId = block.id;
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
e.dataTransfer.setData('text/plain', block.id);
|
||||
|
||||
// Update UI state
|
||||
this.updateComponentState();
|
||||
|
||||
// Add slight delay to show dragging state
|
||||
setTimeout(() => {
|
||||
this.component.requestUpdate();
|
||||
}, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles drag end
|
||||
*/
|
||||
handleDragEnd(): void {
|
||||
this.draggedBlockId = null;
|
||||
this.dragOverBlockId = null;
|
||||
this.dragOverPosition = null;
|
||||
this.updateComponentState();
|
||||
this.component.requestUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles drag over
|
||||
*/
|
||||
handleDragOver(e: DragEvent, block: IBlock): void {
|
||||
e.preventDefault();
|
||||
if (!e.dataTransfer || !this.draggedBlockId || this.draggedBlockId === block.id) return;
|
||||
|
||||
e.dataTransfer.dropEffect = 'move';
|
||||
|
||||
const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
|
||||
const midpoint = rect.top + rect.height / 2;
|
||||
|
||||
this.dragOverBlockId = block.id;
|
||||
this.dragOverPosition = e.clientY < midpoint ? 'before' : 'after';
|
||||
this.updateComponentState();
|
||||
this.component.requestUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles drag leave
|
||||
*/
|
||||
handleDragLeave(block: IBlock): void {
|
||||
if (this.dragOverBlockId === block.id) {
|
||||
this.dragOverBlockId = null;
|
||||
this.dragOverPosition = null;
|
||||
this.updateComponentState();
|
||||
this.component.requestUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles drop
|
||||
*/
|
||||
handleDrop(e: DragEvent, targetBlock: IBlock): void {
|
||||
e.preventDefault();
|
||||
|
||||
if (!this.draggedBlockId || this.draggedBlockId === targetBlock.id) return;
|
||||
|
||||
const blocks = [...this.component.blocks];
|
||||
const draggedIndex = blocks.findIndex(b => b.id === this.draggedBlockId);
|
||||
const targetIndex = blocks.findIndex(b => b.id === targetBlock.id);
|
||||
|
||||
if (draggedIndex === -1 || targetIndex === -1) return;
|
||||
|
||||
// Remove the dragged block
|
||||
const [draggedBlock] = blocks.splice(draggedIndex, 1);
|
||||
|
||||
// Calculate the new index
|
||||
let newIndex = targetIndex;
|
||||
if (this.dragOverPosition === 'after') {
|
||||
newIndex = draggedIndex < targetIndex ? targetIndex : targetIndex + 1;
|
||||
} else {
|
||||
newIndex = draggedIndex < targetIndex ? targetIndex - 1 : targetIndex;
|
||||
}
|
||||
|
||||
// Insert at new position
|
||||
blocks.splice(newIndex, 0, draggedBlock);
|
||||
|
||||
// Update blocks
|
||||
this.component.blocks = blocks;
|
||||
this.component.updateValue();
|
||||
this.handleDragEnd();
|
||||
|
||||
// Focus the moved block
|
||||
setTimeout(() => {
|
||||
const blockOps = this.component.blockOperations;
|
||||
if (draggedBlock.type !== 'divider') {
|
||||
blockOps.focusBlock(draggedBlock.id);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates component drag state
|
||||
*/
|
||||
private updateComponentState(): void {
|
||||
this.component.draggedBlockId = this.draggedBlockId;
|
||||
this.component.dragOverBlockId = this.dragOverBlockId;
|
||||
this.component.dragOverPosition = this.dragOverPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a block is being dragged
|
||||
*/
|
||||
isDragging(blockId: string): boolean {
|
||||
return this.draggedBlockId === blockId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a block has drag over state
|
||||
*/
|
||||
isDragOver(blockId: string): boolean {
|
||||
return this.dragOverBlockId === blockId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets drag over CSS classes for a block
|
||||
*/
|
||||
getDragOverClasses(blockId: string): string {
|
||||
if (!this.isDragOver(blockId)) return '';
|
||||
return this.dragOverPosition === 'before' ? 'drag-over-before' : 'drag-over-after';
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user