리액트 TOAST UI Editor 유튜브 동영상 넣기

안녕하세요·2024년 5월 8일
0

react

목록 보기
25/32

Toast UI Editor를 위한 사용자 정의 HTML 렌더러

이 섹션에서는 Toast UI Editor 내에서 iframe과 div 태그를 처리하기 위해 사용자 정의 HTML 렌더러를 구현합니다. 이 렌더러는 각 HTML 블록의 태그를 개방, 내용 삽입, 종료하는 과정으로 구성됩니다.

const customHTMLRenderer = {
        htmlBlock: {
            iframe(node) {
                return [
                    {
                        type: 'openTag',
                        tagName: 'iframe',
                        outerNewLine: true,
                        attributes: node.attrs
                    },
                    { type: 'html', content: node.childrenHTML },
                    { type: 'closeTag', tagName: 'iframe', outerNewLine: true },
                ];
            },
            div(node) {
                return [
                    { type: 'openTag', tagName: 'div', outerNewLine: true, attributes: node.attrs },
                    { type: 'html', content: node.childrenHTML ?? '' },
                    { type: 'closeTag', tagName: 'div', outerNewLine: true },
                ];
            }
        }
    };

이 렌더러는 iframe에 유튜브 동영상을 삽입하기 위한 커스텀 설정을 제공합니다.

툴바에 유튜브 버튼 추가 및 팝업 이벤트 구현

다음 코드는 Toast UI Editor 툴바에 유튜브 버튼을 추가하고, 버튼 클릭 시 동영상 주소를 입력받을 수 있는 팝업을 생성하는 로직을 구현합니다. 이 과정에서 사용자는 동영상 주소를 입력하고, '확인' 버튼을 클릭하여 동영상을 업로드할 수 있습니다.

   useEffect(() => {
        const videoButton = document.createElement('div');
        videoButton.classList.add('toastui-editor-button-container');

        const urlInput = document.createElement('input');
        urlInput.type = 'text';
        urlInput.style.width = '400px';

        const okButton = document.createElement('button');
        okButton.type = 'button';
        okButton.className = 'toastui-editor-ok-button';
        okButton.textContent = '확인';
        okButton.onclick = async () => {
            await onUploadVideo(urlInput.value);
            urlInput.value = ''
        };

        const cancelButton = document.createElement('button');
        cancelButton.type = 'button';
        cancelButton.className = 'toastui-editor-close-button';
        cancelButton.textContent = '취소';
        cancelButton.onclick = () => {
            editorRef.current.getInstance().eventEmitter.emit('closePopup');
            urlInput.value = ''
        }

        videoButton.appendChild(cancelButton);
        videoButton.appendChild(okButton);

        const container = document.createElement('div');
        const description = document.createElement('label');
        description.textContent = '동영상 주소를 넣어주세요';
        container.appendChild(description);
        container.appendChild(urlInput);
        container.appendChild(videoButton);

        editorRef.current?.getInstance().insertToolbarItem(
            { groupIndex: 3, itemIndex: 3 },
            {
                name: 'youtube',
                tooltip: '유튜브 동영상',
                className: 'toastui-editor-toolbar-icons youtubeBtn',
                style: { background: 'url(./img/youtube.png) 50% 50% ' },
                popup: {
                    body: container,
                    style: { width: 'auto' },
                    className: 'youtubePopup'
                },
            }
        );
    }, []);

동영상 업로드 로직 구현

마지막으로, 아래의 코드는 유튜브 동영상 URL에서 비디오 ID를 추출하고, 추출된 ID를 사용하여 Markdown 모드에서 동영상을 삽입하는 로직을 구현합니다.

    const extractYouTubeID = (url) => {
        const regex = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)([^&?\/]+)/;
        const match = url.match(regex);
        return match ? match[1] : null;
    }


    const onUploadVideo = async (urlInput) => {
        const editorInstance = editorRef.current.getInstance();

        // 현재 모드를 저장
        const currentMode = editorInstance.mode;

        // Markdown 모드로 변경
        if (currentMode !== 'markdown') {
            editorInstance.changeMode('markdown');
            await new Promise(resolve => setTimeout(resolve, 50)); // UI 업데이트를 위한 잠시 대기
        }
        const str = `<div class = videoBox><iframe  width="300" height="200" src="https://www.youtube.com/embed/${extractYouTubeID(urlInput)}" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>`;

        // 텍스트 삽입
        editorInstance.insertText(str);
        await new Promise(resolve => setTimeout(resolve, 50)); // 텍스트 삽입 반영 대기
        // // 원래 모드로 복귀
        if (currentMode !== 'markdown') {
            editorInstance.changeMode(currentMode);
        }

        // 팝업 닫기
        editorInstance.eventEmitter.emit('closePopup');
    };

0개의 댓글