DOMException Crash in Caret Split via Premature deleteContents()
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức phù hợp với người mới
- 72/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- typescript
- Lĩnh vực
- frontend
Hướng nghiên cứu
Start in src/components/modules/caret.ts, especially Caret.extractFragmentFromCaretPosition() around lines 197–233, and reproduce the formatted paragraph split described in the issue. Trace the selection and range boundaries through the native-input and contenteditable paths. Done means pressing Enter across the formatting boundary no longer throws a DOMException and the block splits correctly.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
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.endContainernode from the DOM, or reduce its character length belowselectRange.endOffset. - When
range.setStart(selectRange.endContainer, selectRange.endOffset)runs immediately after:- If
endContaineris no longer insidecurrentBlockInput, the browser throws:
DOMException: Failed to execute 'setStart' on 'Range': The node provided is not a child of this node. - If
endOffsetexceeds the remaining text length, the browser throws:
DOMException: Failed to execute 'setStart' on 'Range': The offset is larger than the node's length.
- If
- 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
worldtoextra. - 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();
}
- Ngôn ngữ chính
- TypeScript
- Star
- 32k
- Fork
- 2.2k
- Merge trung bình
- 8 giờ 45 phút
- Pull request đã merge (30 ngày)
- 1
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của codex-team/editor.js
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
codex-team/editor.js#3037 · 1 bình luận ·
-
Floating Promise Anti-Pattern & Premature Caret in Multi-Block PasteCó thể đã có người làm @anshurajbisoyi98-ctrl đã nhận 24 ngày trước. Đang mởbug good first issue
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
codex-team/editor.js#3032 · 1 bình luận ·
-
Silent Data Loss & Broken Error Contract in Saver.save()Có thể đã có người làm @Sion612 đã nhận 34 ngày trước. Đang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
codex-team/editor.js#3030 ·
-
Complete Omission of block.destroy() in Blocks CollectionCó thể đã có người làm @Minhal128 đã nhận 33 ngày trước. Đang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
codex-team/editor.js#3029 ·
-
Bug: Link cannot be removedCó thể đã có người làm @prathmeshyelne đã nhận 140 ngày trước. Đang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
codex-team/editor.js#3005 · 1 bình luận ·
Tất cả issue của codex-team/editor.js
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 84/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 83/100
keptinventory/kept#336 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
good first issue
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
-
hemi-earn
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
vetro-protocol/vetro-monorepo#1013 ·
Maintainer thường phản hồi trong vòng 1 ngày