From ae1f10b43eacc6d9be214605d2dc41c9d2b53e93 Mon Sep 17 00:00:00 2001 From: Priya Kanabar <119392691+priyakanabar-crest@users.noreply.github.com> Date: Sat, 21 Dec 2024 07:33:27 +0530 Subject: [PATCH] fix(text-cell-traversal): Debugged the issue with text cell traversal and handled all the edge cases for traversal with different decorations and elements (#395) fix(text-cell-traversal):Debugged the issue with text cell traversal and handled all the edge cases for traversal with different decorations and elements --- .../src/components/EditorComponent.vue | 121 +++++++++++++++--- 1 file changed, 104 insertions(+), 17 deletions(-) diff --git a/zt_frontend/src/components/EditorComponent.vue b/zt_frontend/src/components/EditorComponent.vue index 57876ac0..77a48632 100644 --- a/zt_frontend/src/components/EditorComponent.vue +++ b/zt_frontend/src/components/EditorComponent.vue @@ -150,33 +150,120 @@ export default { createCell(cellType: string) { this.$emit("createCell", this.cellData.id, cellType); }, - handleEditorInit(editor: any) { - this.editor = editor; + getEditorView() { + return this.editor; }, + isCursorAtStart(editor: any): boolean { const selection = editor.selection; const rng = selection.getRng(true); - const isAtStart = rng.startOffset === 0 && rng.startContainer === editor.getBody().firstChild; - return isAtStart; - }, - isCursorAtEnd(editor: any): boolean { + const body = editor.getBody(); + + if (!body || !body.childNodes.length) return true; + + const blocks = Array.from(body.childNodes as NodeListOf).flatMap((node: Node) => { + if (node.nodeName === "UL" || node.nodeName === "OL") { + return Array.from(node.childNodes).filter((child: Node) => child.nodeName === "LI"); + } + return ["P", "DIV", "LI", "H1", "H2", "H3", "H4", "H5", "H6"].includes((node as HTMLElement).nodeName) + ? [node] + : []; + }); + + if (!blocks.length) return true; + + const firstBlock = blocks[0] as HTMLElement; + const currentBlock = editor.dom.getParent(rng.startContainer, "p,div,li,h1,h2,h3,h4,h5,h6,ul,ol"); + + if (currentBlock !== firstBlock) return false; + + // Handle links at start + if (rng.startContainer.nodeType === Node.ELEMENT_NODE && + (rng.startContainer as HTMLElement).nodeName === "A") { + return rng.startOffset === 0; + } + + const isFirstBlockEmpty = !firstBlock.textContent?.trim() || firstBlock.innerHTML === "
"; + const isAtTextStart = rng.startContainer.nodeType === Node.TEXT_NODE && rng.startOffset === 0; + + return isFirstBlockEmpty || isAtTextStart; +}, +// Modify isCursorAtEnd method +isCursorAtEnd(editor: any): boolean { const selection = editor.selection; const rng = selection.getRng(true); - const lastNode = editor.getBody().lastChild; - let isAtEnd = false; + const body = editor.getBody(); + + if (!body.childNodes.length) return true; + + const blocks = Array.from(body.childNodes as NodeListOf).flatMap((node: Node) => { + if (node.nodeName === "UL" || node.nodeName === "OL") { + return Array.from(node.childNodes).filter((child: Node) => child.nodeName === "LI"); + } + return ["P", "DIV", "LI", "H1", "H2", "H3", "H4", "H5", "H6"].includes((node as HTMLElement).nodeName) + ? [node] + : []; + }); - if (rng.endContainer.nodeType === Node.TEXT_NODE) { - isAtEnd = rng.startOffset === rng.endContainer.length; - } else { - isAtEnd = rng.endContainer === lastNode && rng.startOffset === 0; + if (!blocks.length) return true; + + const lastBlock = blocks[blocks.length - 1] as HTMLElement; + const currentBlock = editor.dom.getParent(rng.endContainer, "p,div,li,h1,h2,h3,h4,h5,h6,ul,ol"); + + if (currentBlock !== lastBlock) return false; + + const isLastBlockEmpty = !lastBlock.textContent?.trim() || + lastBlock.innerHTML === "
" || + lastBlock.childNodes.length === 0; + + if (isLastBlockEmpty) return true; + + // Handle links at end + if (rng.endContainer.nodeType === Node.ELEMENT_NODE && + (rng.endContainer as HTMLElement).nodeName === "A") { + const link = rng.endContainer as HTMLElement; + return rng.endOffset === link.childNodes.length; + } + + // Handle lists + if (lastBlock.nodeName === "LI") { + const listItem = lastBlock as HTMLLIElement; + return rng.endOffset === (listItem.textContent || "").length; } - const isCursorAtEnd = isAtEnd && rng.endContainer === lastNode; - return isCursorAtEnd; + const isAtTextEnd = rng.endContainer.nodeType === Node.TEXT_NODE && + rng.endOffset === (rng.endContainer.textContent || "").length; + + return isAtTextEnd && !rng.endContainer.nextSibling; +}, + + handleEditorInit(editor: any) { + this.editor = editor; + + editor.on("keydown", (e: any) => { + try { + if (e.keyCode === 38) { + const isAtStart = this.isCursorAtStart(editor); + console.log("Up arrow pressed. Is at start:", isAtStart); + if (isAtStart) { + e.preventDefault(); + this.$emit("navigateToCell", this.cellData.id, "up"); + } + } + + if (e.keyCode === 40) { + const isAtEnd = this.isCursorAtEnd(editor); + console.log("Down arrow pressed. Is at end:", isAtEnd); + if (isAtEnd) { + e.preventDefault(); + this.$emit("navigateToCell", this.cellData.id, "down"); + } + } + } catch (error) { + console.error("Error in editor navigation:", error); + } + }); }, - getEditorView() { - return this.editor; - }, }, };