에루샤
erusya
Back-end Developer
Web Geek
Anime Otaku
에루샤
개발

플로라 에디터 이미지 캡션 클릭 시 스크롤 초기화 되는 문제 해결 방법

15 views as of December 27, 2024.

문제

아오오오.. 드디어 해결했다.

무슨소리냐 하면 플로라 에디터에서 이미지에 캡션을 달아둘때 그 캡션을 클릭하면 아래 처럼 스크롤이 초기화 되는 문제가 있다.


마우스 커서가 안보이긴하는데, 이미지 아래에 캡션을 클릭하면 위와같이 본문의 맨 상단으로 이동되는 버그이다.
관련 버그는 유명한지 플로라 에디터 깃헙 이슈란에서도 쉽게 찾아볼 수 있다.

Scrolling top after a click on an image and then on a caption · Issue #3888 · froala/wysiwyg-editor
Scrolling top after a click on an image and then on a caption · Issue #3888 · froala/wysiwyg-editor
This issue is occuring in the demo editor also => https://froala.com/wysiwyg-editor Expected behavior. The window should not scoll to the top. Actual behavior. A scrolling event occur and the windo...
https://github.com/froala/wysiwyg-editor/issues/3888

어떻게든 해당 캡션을 클릭하면 스크롤이 초기화 되는 이벤트를 막으면 되지 않을까 해서 event.preventDeault(); 를 오만군데에다가 다 적용해봤는데 될리가 없었다.

관련 내용만 조금만 찾아봐도 버그라고 내용이 되어있고, 플로라 에디터는 오픈 소스가 아니므로 개발사가 고쳐줄때까지 기다려야했다.

해당이슈가 20년부터 지속되어왔는데도, 최신버전인 4.3.1에서도 해결되지 않은 버그이다.


까보니 스크롤 초기화 이벤트 문제가 아니었다

관련내용을 검색해봐도 이슈보고가 엄청 적게되어있고, 어떤 로그를 봐야할지 몰라서 무작정 깃헙 이슈에서 비슷한 사례를 찾다가 다른 상황에서 비슷하게 스크롤 초기화 되는 이슈가 발견되었다.

근데 해당 내용은 문제 제의자가 좀더 상태에 대해서 까봤는지 직접적으로 특정상황에서 blur 이벤트가 작동된다는 것을 문제 삼은 내용이었다.

Blur event NOT triggered after setting an image caption · Issue #3345 · froala/wysiwyg-editor
Blur event NOT triggered after setting an image caption · Issue #3345 · froala/wysiwyg-editor
Expected behavior. Blur event should be fired when clicking outside of Froala Actual behavior. Blur event does not get fired Steps to reproduce the problem. Use the sample from issue #3237 https://...
https://github.com/froala/wysiwyg-editor/issues/3345

대충 느낌이 싹 와서 이러면 blur 이벤트쪽을 어떻게 제어할 수 있다면 위 문제에 대해서 응급조치는 가능할꺼라고 생각이 들었다.


blur 이벤트 조작

원래 플로라 에디터에서 blur 이벤트는 에디터의 포커스가 해제될때 발생되는 이벤트이다.
쉽게말해 에디터 작성이 끝나고 사용자의 포커스가 다른 영역으로 갈때 에디터에서 발생하는 이벤트라는 것이다.

실제로 이런 blur 이벤트를이용해서 자동저장 기능을 만든다던지, 에디터의 활성/비활성 상태를 사용자에게 UI로 보여준다던지의 응용이 가능한 이벤트이다.

문제는 캡션을 클릭할때 의도치않은 이 blur 이벤트가 작동되어서 에디터에서 포커스가 빠지면서 모종의 스크롤 초기화 이벤트가 발생한다는것이다.

그럼 이 경우에는 포커스를 다시 해당 캡션으로 잡아주면 될거 같아서 아래와 같이 코드를 작성했다.

'blur': function (event) {
    console.log('Editor has lost focus.', event);

    const relatedTarget = $(event.originalEvent.relatedTarget);
    const isCaption = relatedTarget.closest('.fr-img-caption').length > 0;

    if (isCaption) {
        console.log('Blur event ignored for caption click.');

        // 중첩된 span 태그 제거 처리
        const innerSpan = relatedTarget.find('span');
        if (innerSpan.length > 0) {
            console.log('Removing nested span:', innerSpan);

            // 내부 텍스트를 상위 요소로 이동
            innerSpan.contents().unwrap(); // span#isPasted 태그 제거
        }

        // 관련 요소에 포커스
        relatedTarget.focus();

        // 선택 영역을 마지막으로 설정
        const range = document.createRange();
        const sel = window.getSelection();

        // relatedTarget의 텍스트 노드 가져오기
        const textNode = relatedTarget[0].childNodes[0]; // 첫 번째 자식 노드
        if (textNode) {
            range.setStart(textNode, textNode.textContent.length); // 텍스트 마지막 위치
            range.collapse(true); // 커서를 텍스트 끝에 배치
            sel.removeAllRanges();
            sel.addRange(range);

            console.log('Cursor set to the end of the caption text.');
        } else {
            console.log('No text node found in the target element.');
        }

        return false; // 이벤트 중단
    }

    console.log('Editor blur event triggered.');
}Copy

플로라 에디터에서 이미지 캡션이 활성화된 이미지 영역은 아래와 같은 HTML 구조를 가지고있다.

<span class="fr-img-caption fr-fic fr-dib fr-draggable" style="width: 600px;" contenteditable="false" draggable="false">
    <span class="fr-img-wrap">
        <img src="https://cdn.erulabo.com/editor/gaK5dmZ2BDxaimG5TWyCEOMIX0bFMZaiAC0iSmSh_optimized.jpg" class="fr-fic fr-dib fr-draggable" style="width: 600px;">
        <span class="fr-inner" contenteditable="true">해시태그 입력하는 인풋창에 포커스를 주변 나오게 설계</span>
    </span>
</span>Copy

실제 마우스 클릭은 span.fr-inner 에서 트리거 되므로 블러 이벤트에서 이벤트 타겟을 기준으로 상위 요소에 .fr-img-caption 이 있는지 확인하면 이는 캡션 클릭에서 발생된 blur 이벤트인지 판단할 수 있을것이다.

그리고 플로라 에디터는 캡션 내부의 내용을 복사/붙여넣기로 채워넣을경우 이를 span#isPasted로 다시한번 감싸서 내용을 넣게되어 span.fr-inner 안에 또 span이 존재하게 되는 이중구조가 될 수 있는데, 이를 보정하는 코드를 넣었다.

그리고 캡션 요소에 포커스를 준다음에 캡션의 텍스트 마지막에 커서를 두기위한 작업을 한 후 기본 이벤트를 비활성화하면 아래와 같이 정상적으로 스크롤 초기화 없이 이미지 내부에 포커스가 감을 확인할 수 있다.



최종 정리 코드

'blur': function (event) {
    const relatedTarget = $(event.originalEvent.relatedTarget);
    const isCaption = relatedTarget.closest('.fr-img-caption').length > 0;

    if (isCaption) {// 중첩된 span 태그 제거 처리
        const innerSpan = relatedTarget.find('span');
        if (innerSpan.length > 0) {
            innerSpan.contents().unwrap(); // span#isPasted 태그 제거
        }

        // 관련 요소에 포커스
        relatedTarget.focus();

        // 선택 영역을 마지막으로 설정
        const range = document.createRange();
        const sel = window.getSelection();

        // relatedTarget의 텍스트 노드 가져오기
        const textNode = relatedTarget[0].childNodes[0]; // 첫 번째 자식 노드
        if (textNode) {
            range.setStart(textNode, textNode.textContent.length); // 텍스트 마지막 위치
            range.collapse(true); // 커서를 텍스트 끝에 배치
            sel.removeAllRanges();
            sel.addRange(range);
        }

        return false; // 이벤트 중단
    }
}Copy

콘솔 로그를 뺀 최종 코드이다.
이 코드를 플로라 에디터 초기화 시 events: { ... } 위치에 넣어주면 된다.

끝!
#FroalaEditor
0 개의 댓글
×