fix(wysiwyg): Improve text selection detection with block-level approach
- Remove global selectionchange listener in favor of block-level detection - Add comprehensive debugging logs to track selection detection - Add multiple event listeners (mouseup, keyup, selectstart) for better coverage - Add debounced selection checking to avoid race conditions - Add click-outside handler to hide formatting menu - Simplify selection detection logic by removing complex shadow DOM traversal
This commit is contained in:
@ -349,8 +349,10 @@ export class DeesWysiwygBlock extends DeesElement {
|
||||
console.log('Cursor position after mouseup:', pos);
|
||||
}
|
||||
|
||||
// Check for text selection
|
||||
this.checkForTextSelection();
|
||||
// Check for text selection with a longer delay
|
||||
setTimeout(() => {
|
||||
this.checkForTextSelection();
|
||||
}, 50);
|
||||
}, 0);
|
||||
|
||||
this.handleMouseUp(e);
|
||||
@ -368,6 +370,31 @@ export class DeesWysiwygBlock extends DeesElement {
|
||||
}, 0);
|
||||
});
|
||||
|
||||
// Add select event listener
|
||||
editableBlock.addEventListener('selectstart', () => {
|
||||
console.log('Selection started in block');
|
||||
});
|
||||
|
||||
// Listen for selection changes with a mutation observer
|
||||
let selectionCheckTimeout: any = null;
|
||||
const checkSelectionDebounced = () => {
|
||||
if (selectionCheckTimeout) clearTimeout(selectionCheckTimeout);
|
||||
selectionCheckTimeout = setTimeout(() => {
|
||||
this.checkForTextSelection();
|
||||
}, 100);
|
||||
};
|
||||
|
||||
// Check selection on various events
|
||||
editableBlock.addEventListener('mouseup', checkSelectionDebounced);
|
||||
editableBlock.addEventListener('keyup', checkSelectionDebounced);
|
||||
document.addEventListener('selectionchange', () => {
|
||||
// Check if this block has focus
|
||||
if (document.activeElement === editableBlock ||
|
||||
this.shadowRoot?.activeElement === editableBlock) {
|
||||
checkSelectionDebounced();
|
||||
}
|
||||
});
|
||||
|
||||
// Set initial content if needed
|
||||
if (this.block.content) {
|
||||
if (this.block.type === 'code') {
|
||||
@ -798,57 +825,51 @@ export class DeesWysiwygBlock extends DeesElement {
|
||||
const editableElement = this.block?.type === 'code'
|
||||
? this.shadowRoot?.querySelector('.block.code') as HTMLDivElement
|
||||
: this.shadowRoot?.querySelector('.block') as HTMLDivElement;
|
||||
if (!editableElement) return;
|
||||
|
||||
const selection = window.getSelection();
|
||||
if (!selection || selection.rangeCount === 0) {
|
||||
// Dispatch event to clear selection
|
||||
this.dispatchEvent(new CustomEvent('block-text-selected', {
|
||||
detail: {
|
||||
text: '',
|
||||
blockId: this.block.id,
|
||||
hasSelection: false
|
||||
},
|
||||
bubbles: true,
|
||||
composed: true
|
||||
}));
|
||||
if (!editableElement) {
|
||||
console.log('checkForTextSelection: No editable element found');
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedText = selection.toString().trim();
|
||||
const selection = window.getSelection();
|
||||
if (!selection || selection.rangeCount === 0) {
|
||||
console.log('checkForTextSelection: No selection or range count is 0');
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedText = selection.toString();
|
||||
console.log('checkForTextSelection: Selected text raw:', selectedText, 'length:', selectedText.length);
|
||||
|
||||
// Only proceed if we have selected text
|
||||
if (selectedText.length === 0) {
|
||||
// Dispatch event to clear selection
|
||||
this.dispatchEvent(new CustomEvent('block-text-selected', {
|
||||
detail: {
|
||||
text: '',
|
||||
blockId: this.block.id,
|
||||
hasSelection: false
|
||||
},
|
||||
bubbles: true,
|
||||
composed: true
|
||||
}));
|
||||
if (selectedText.trim().length === 0) {
|
||||
console.log('checkForTextSelection: Selected text is empty after trim');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the selection is within this block
|
||||
const range = selection.getRangeAt(0);
|
||||
console.log('checkForTextSelection: Range:', {
|
||||
startContainer: range.startContainer,
|
||||
endContainer: range.endContainer,
|
||||
collapsed: range.collapsed
|
||||
});
|
||||
|
||||
// Check if both start and end are within our editable element
|
||||
const startInBlock = editableElement.contains(range.startContainer);
|
||||
const endInBlock = editableElement.contains(range.endContainer);
|
||||
|
||||
console.log('checkForTextSelection: Start in block:', startInBlock, 'End in block:', endInBlock);
|
||||
|
||||
if (startInBlock && endInBlock) {
|
||||
console.log('Block detected text selection:', selectedText);
|
||||
console.log('✅ Block detected text selection:', selectedText.trim());
|
||||
|
||||
// Get the bounding rect of the selection
|
||||
const rect = range.getBoundingClientRect();
|
||||
console.log('Selection rect:', rect);
|
||||
|
||||
// Dispatch event to parent with selection details
|
||||
this.dispatchEvent(new CustomEvent('block-text-selected', {
|
||||
detail: {
|
||||
text: selectedText,
|
||||
text: selectedText.trim(),
|
||||
blockId: this.block.id,
|
||||
range: range,
|
||||
rect: rect,
|
||||
@ -857,6 +878,8 @@ export class DeesWysiwygBlock extends DeesElement {
|
||||
bubbles: true,
|
||||
composed: true
|
||||
}));
|
||||
} else {
|
||||
console.log('checkForTextSelection: Selection not contained in block');
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user