Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/#175 캐럿 관리방식 변경 #176

Merged
merged 12 commits into from
Nov 25, 2024
71 changes: 71 additions & 0 deletions client/src/utils/caretUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { BlockLinkedList, TextLinkedList } from "@noctaCrdt/LinkedList";
import { BlockId } from "@noctaCrdt/NodeId";

interface SetCaretPositionProps {
blockId: BlockId;
linkedList: BlockLinkedList | TextLinkedList;
clientX?: number;
clientY?: number;
position?: number; // 특정 위치로 캐럿을 설정하고 싶을 때 사용
}

export const setCaretPosition = ({
blockId,
linkedList,
clientX,
clientY,
position,
}: SetCaretPositionProps): boolean => {
try {
const selection = window.getSelection();
if (!selection) return false;

const blockElements = Array.from(
document.querySelectorAll('.d_flex.pos_relative.w_full[data-group="true"]'),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이부분이 브라우저의 에디터 요소를 찾는 구문이군요..
기존에 key입력마다 처리하는 방법에서 브라우저를 활용한다면 더욱 편하게 관리할 수 있을 듯 합니다.
다만 몇개 버그를 찾은 것 같습니다!

12321.mp4

위와같은 현상은 아직 page별로 캐럿이 제대로 관리되지 않아서 생기는 현상일까요?

아마 이전에 focus된 캐럿으로 다른 page를 눌러도 새로운 page로 캐럿위치가 업데이트 되지 않는것 같군요..

);
const currentIndex = linkedList.spread().findIndex((b) => b.id === blockId);
const targetElement = blockElements[currentIndex];
if (!targetElement) return false;

const editableDiv = targetElement.querySelector('[contenteditable="true"]') as HTMLDivElement;
if (!editableDiv) return false;

editableDiv.focus();

let range: Range;

if (clientX !== undefined && clientY !== undefined) {
// 클릭 위치에 따른 캐럿 설정
const clickRange = document.caretRangeFromPoint(clientX, clientY);
if (!clickRange) return false;
range = clickRange;
} else if (position !== undefined) {
// 특정 위치에 캐럿 설정
range = document.createRange();
const textNode =
Array.from(editableDiv.childNodes).find((node) => node.nodeType === Node.TEXT_NODE) || null;
if (!textNode) {
// 텍스트 노드가 없으면 새로운 텍스트 노드를 추가
const newTextNode = document.createTextNode("");
editableDiv.appendChild(newTextNode);
range.setStart(newTextNode, 0);
} else {
// position이 텍스트 길이를 초과하지 않도록 조정
const safePosition = Math.min(position, textNode.textContent?.length || 0);
range.setStart(textNode, safePosition);
}

range.collapse(true);
} else {
return false;
}

selection.removeAllRanges();
selection.addRange(range);

return true;
} catch (error) {
console.error("Error setting caret position:", error);
return false;
}
};