3. DOMException Crash in Caret Split via Premature deleteContents()
π Affected Locations
src/components/modules/caret.ts (Lines 197β233)
π Deep Technical Diagnosis
When pressing Enter to split a block, Caret.extractFragmentFromCaretPosition() is called to split content from the caret to the end of the block.
// src/components/modules/caret.ts: Lines 200-231
if (selection.rangeCount) {
const selectRange = selection.getRangeAt(0);
const currentBlockInput = this.Editor.BlockManager.currentBlock.currentInput;
selectRange.deleteContents(); // <-- BUG: Mutates DOM before boundary inspection!
if (currentBlockInput) {
if ($.isNativeInput(currentBlockInput)) {
// ...
} else {
const range = selectRange.cloneRange();
range.selectNodeContents(currentBlockInput);
range.setStart(selectRange.endContainer, selectRange.endOffset); // <-- CRASH!
return range.extractContents();
}
}
}
Why It Crashes:
selectRange.deleteContents() deletes the selected nodes from the document tree.
- In browsers (especially Chrome/WebKit), deleting nodes collapses text nodes and can completely remove the
selectRange.endContainer node from the DOM, or reduce its character length below selectRange.endOffset.
- When
range.setStart(selectRange.endContainer, selectRange.endOffset) runs immediately after:
- If
endContainer is no longer inside currentBlockInput, the browser throws:
DOMException: Failed to execute 'setStart' on 'Range': The node provided is not a child of this node.
- If
endOffset exceeds the remaining text length, the browser throws:
DOMException: Failed to execute 'setStart' on 'Range': The offset is larger than the node's length.
- This completely halts the block-splitting operation and leaves the editor in a corrupt, uneditable state.
π§ͺ Reproduction Steps
- Insert a paragraph with formatting:
Hello <b>world and extra</b> text.
- Select text spanning across the tag boundary: e.g., select from
world to extra.
- Press
Enter.
- Observed: Console throws uncaught
DOMException: Failed to execute 'setStart' on 'Range'. Block does not split.
π‘ Proposed Solution & Patch
Clone the boundary points or collapse the range cleanly before extracting contents:
src/components/modules/caret.ts
@@ -201,8 +201,6 @@ export default class Caret extends Module {
const selectRange = selection.getRangeAt(0);
const currentBlockInput = this.Editor.BlockManager.currentBlock.currentInput;
- selectRange.deleteContents();
-
if (currentBlockInput) {
if ($.isNativeInput(currentBlockInput)) {
/**
@@ -213,6 +211,7 @@ export default class Caret extends Module {
const input = currentBlockInput as HTMLInputElement | HTMLTextAreaElement;
const newFragment = document.createDocumentFragment();
+ selectRange.deleteContents();
const inputRemainingText = input.value.substring(0, input.selectionStart);
const fragmentText = input.value.substring(input.selectionStart);
@@ -222,8 +221,11 @@ export default class Caret extends Module {
return newFragment;
} else {
- const range = selectRange.cloneRange();
+ selectRange.deleteContents();
+ const range = document.createRange();
range.selectNodeContents(currentBlockInput);
- range.setStart(selectRange.endContainer, selectRange.endOffset);
+ const safeSelection = Selection.get();
+ const anchorRange = safeSelection.rangeCount ? safeSelection.getRangeAt(0) : selectRange;
+ range.setStart(anchorRange.startContainer, anchorRange.startOffset);
return range.extractContents();
}
3.
DOMExceptionCrash in Caret Split via PrematuredeleteContents()π Affected Locations
src/components/modules/caret.ts(Lines 197β233)π Deep Technical Diagnosis
When pressing
Enterto split a block,Caret.extractFragmentFromCaretPosition()is called to split content from the caret to the end of the block.Why It Crashes:
selectRange.deleteContents()deletes the selected nodes from the document tree.selectRange.endContainernode from the DOM, or reduce its character length belowselectRange.endOffset.range.setStart(selectRange.endContainer, selectRange.endOffset)runs immediately after:endContaineris no longer insidecurrentBlockInput, the browser throws:DOMException: Failed to execute 'setStart' on 'Range': The node provided is not a child of this node.endOffsetexceeds the remaining text length, the browser throws:DOMException: Failed to execute 'setStart' on 'Range': The offset is larger than the node's length.π§ͺ Reproduction Steps
Hello <b>world and extra</b> text.worldtoextra.Enter.DOMException: Failed to execute 'setStart' on 'Range'. Block does not split.π‘ Proposed Solution & Patch
Clone the boundary points or collapse the range cleanly before extracting contents:
src/components/modules/caret.ts