fix: improve text selection handling in copy handler for message formatting
This commit is contained in:
@@ -28,54 +28,69 @@ export const setupCopyHandler = (
|
||||
const messages: Array<{ sender: string; time: string; content: string }> = [];
|
||||
|
||||
// Get all message elements in the container
|
||||
const messageElements = container.querySelectorAll('[data-message-id]');
|
||||
const messageElements = Array.from(container.querySelectorAll('[data-message-id]'));
|
||||
|
||||
messageElements.forEach((msgEl) => {
|
||||
// Check if this message element intersects with the selection
|
||||
if (!selection.containsNode(msgEl, true)) return;
|
||||
|
||||
const eventId = msgEl.getAttribute('data-message-id');
|
||||
if (!eventId) return;
|
||||
|
||||
const data = getMessageData(eventId);
|
||||
if (!data) return;
|
||||
|
||||
// Get the selected text content within this message
|
||||
const tempRange = document.createRange();
|
||||
tempRange.selectNodeContents(msgEl);
|
||||
// Find content elements within the message (skip headers, timestamps, etc.)
|
||||
const contentEl = msgEl.querySelector('[class*="MessageTextBody"], [class*="message-content"], [class*="MessageBody"]') as HTMLElement;
|
||||
|
||||
// Check if the selection overlaps with this message
|
||||
const intersects = range.compareBoundaryPoints(Range.END_TO_START, tempRange) <= 0 &&
|
||||
range.compareBoundaryPoints(Range.START_TO_END, tempRange) >= 0;
|
||||
if (!contentEl) return;
|
||||
|
||||
if (!intersects) return;
|
||||
// Check if the content element intersects with the selection
|
||||
// by checking if selection contains any part of it
|
||||
let isSelected = false;
|
||||
try {
|
||||
// Try to detect if this node or its children are in the selection
|
||||
const walker = document.createTreeWalker(
|
||||
contentEl,
|
||||
NodeFilter.SHOW_TEXT,
|
||||
null
|
||||
);
|
||||
|
||||
let textNode = walker.nextNode();
|
||||
while (textNode && !isSelected) {
|
||||
if (range.intersectsNode(textNode)) {
|
||||
isSelected = true;
|
||||
}
|
||||
textNode = walker.nextNode();
|
||||
}
|
||||
} catch (e) {
|
||||
// Fallback: check if selection contains the content element
|
||||
isSelected = selection.containsNode(contentEl, true);
|
||||
}
|
||||
|
||||
if (!isSelected) return;
|
||||
|
||||
// Format the time
|
||||
const timeStr = timeHourMinute(data.ts, hour24Clock);
|
||||
|
||||
// Get the text content that was selected from this message
|
||||
// Use the original content if the message is fully selected, otherwise get selected portion
|
||||
// Extract the selected text from within this message's content
|
||||
let selectedText = '';
|
||||
|
||||
// Find the message content element (the actual text, not header)
|
||||
const contentElement = msgEl.querySelector('[class*="MessageTextBody"], [class*="message-content"]');
|
||||
if (contentElement) {
|
||||
const clonedRange = range.cloneRange();
|
||||
clonedRange.selectNodeContents(contentElement);
|
||||
// Create a range for this message's content
|
||||
const contentRange = document.createRange();
|
||||
contentRange.selectNodeContents(contentEl);
|
||||
|
||||
// Intersect with selection
|
||||
if (range.compareBoundaryPoints(Range.START_TO_START, clonedRange) > 0) {
|
||||
clonedRange.setStart(range.startContainer, range.startOffset);
|
||||
// Clone the selection range to avoid modifying it
|
||||
const extractRange = range.cloneRange();
|
||||
|
||||
// Constrain the extract range to be within the content element
|
||||
// If selection starts before content, move start to content start
|
||||
if (contentRange.compareBoundaryPoints(Range.START_TO_START, extractRange) > 0) {
|
||||
extractRange.setStart(contentRange.startContainer, contentRange.startOffset);
|
||||
}
|
||||
if (range.compareBoundaryPoints(Range.END_TO_END, clonedRange) < 0) {
|
||||
clonedRange.setEnd(range.endContainer, range.endOffset);
|
||||
// If selection ends after content, move end to content end
|
||||
if (contentRange.compareBoundaryPoints(Range.END_TO_END, extractRange) < 0) {
|
||||
extractRange.setEnd(contentRange.endContainer, contentRange.endOffset);
|
||||
}
|
||||
|
||||
selectedText = clonedRange.toString().trim();
|
||||
} else {
|
||||
// Fallback: use all selected text in this message
|
||||
selectedText = range.toString().trim();
|
||||
}
|
||||
selectedText = extractRange.toString().trim();
|
||||
|
||||
if (selectedText) {
|
||||
messages.push({
|
||||
|
||||
Reference in New Issue
Block a user