[React] Toast-UI Editor 유튜브 삽입 툴바 버튼 커스텀하기

sua_ahn·2023년 4월 23일
4

React

목록 보기
5/6

Toast-UI Editor에서 Youtube 영상을 주소로 쉽게 삽입할 수 있도록 툴바 버튼을 만들어보았다.

1. Editor 컴포넌트 설정

Editor 컴포넌트에 유튜브 공유용 iframe 태그 사용 설정 & 커스텀할 툴바 버튼 추가

toolbarItemscustomHTMLRenderer 옵션에 주목! (나머진 기본 설정)

<Editor
    placeholder="내용을 입력해주세요."
    initialValue={content}
    previewStyle={window.innerWidth > 1000 ? 'vertical' : 'tab'}
    initialEditType="wysiwyg"
	height="300px"
    language="ko-KR"
	ref={editorRef}
    onChange={() => setContent(editorRef.current.getInstance().getHTML())}
    hooks={{ addImageBlobHook: onUploadImage }}
	useCommandShortcut={false}
    toolbarItems={[
        ['heading', 'bold', 'italic', 'strike'],
        ['hr', 'quote'],
        ['ul', 'ol', 'task'],
        ['table', 'image', 'link'],
        ['code', 'codeblock'],
		// 유튜브 삽입을 위해 툴바 버튼 커스터마이징
        [{
            name: 'Youtube',
            tooltip: 'Youtube',
            el: myCustomEl,
            popup: {
                body: container,
                style: { width: 'auto' },
              }
        }]
    ]}
    // 유튜브 공유용 iframe 태그 사용 설정
    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 }
            ];
        }}
    }}
/>

customHTMLRenderer
: 마크다운 AST(Abstract Syntax Tree)를 HTML 문자열로 변환할 때 커스터마이징할 수 있는 옵션

 

2. 노드 & 로직 생성

툴바 아이템 노드 생성
→ 팝업 바디 노드 생성
→ 이벤트리스너로 유튜브 주소 확인 후 iframe태그 삽입

import youtubeicon from '../asset/icon_youtube.png';
.
.
.
	// 유튜브 삽입을 위한 커스텀 툴바 아이템 생성
    const myCustomEl = document.createElement('span');
    myCustomEl.style = 'cursor: pointer;'

    const icon = document.createElement('img');
    icon.setAttribute('src', youtubeicon);
    icon.setAttribute('width', '32');
    myCustomEl.appendChild(icon);
    
	// 팝업 바디 생성
    const container = document.createElement('div');
    const description = document.createElement('p');
    description.textContent = "Youtube 주소를 입력하고 Enter를 누르세요!";

    const urlInput = document.createElement('input');
    urlInput.style.width = '100%';
	
	// 팝업 input 창에 내용 입력 시 호출됨
    urlInput.addEventListener('keyup', (e) => {
      
      	// 엔터를 누르면, 입력값이 Youtube 주소인지 정규식으로 검사
        if (e.key === 'Enter') {
            if((/https:\/\/youtu.be\/.{11,}/).test(e.target.value)
                || (/https:\/\/www.youtube.com\/watch\?v=.{11,}/).test(e.target.value)) {

                let str = '<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/'
                + e.target.value.slice(-11)
                + '" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>';
                
				// 마크다운 모드에서 iframe 태그 삽입 후, 팝업을 닫고 위지윅 모드로 변환              	
              	editorRef.current.getInstance().changeMode('markdown');
                editorRef.current.getInstance().insertText(str);
                editorRef.current.getInstance().eventEmitter.emit('closePopup');
                editorRef.current.getInstance().changeMode('wysiwyg');
            }
        }
    });
    
    container.appendChild(description);
    container.appendChild(urlInput);

iframe 태그 삽입 시 서비스 워커로 인한 오류

The service worker navigation preload request was cancelled before 'preloadResponse' settled. If you intend to use 'preloadResponse', use waitUntil() or respondWith() to wait for the promise to settle.

서비스 워커는 웹에서의 네트워크 요청과 같은 이벤트를 가로채어 수정하기도 한다. 그런데 서비스 워커가 네트워크 요청이 preload 될 가능성을 고려하지 않고 휴먼상태이므로 요청이 차단되었음을 의미한다.

🔎 참고
스택오버 플로우
유튜브 고객센터

필자는 url에 nocookie를 추가하여 개인정보 강화모드를 사용하는 것으로 마무리지었으나, 더 깊이 파헤쳐보고싶다면 아래 글을 참고하길 바란다!
love2dev 번역글

 

3. Viewer 컴포넌트 설정

Viewer 컴포넌트에 customHTMLRenderer 속성 추가

<Viewer 
  initialValue={content || ''} 
  // 유튜브 공유용 iframe 태그를 렌더링할 수 있도록 설정
  customHTMLRenderer={{
    htmlBlock: {
      iframe(node) {
        return [
          {
            type: "openTag",
            tagName: "iframe",
            outerNewLine: true,
            attributes: node.attrs,
          },
          { type: "html", content: node.childrenHTML },
          { type: "closeTag", tagName: "iframe", outerNewLine: false }
        ];
    }}
  }}
/>

 


🪄 결과

 

※ 참고
[React] Toast-UI Editor/Viewer 유튜브 동영상 삽입/표시 방법
Toast-UI Editor 깃허브 - 커스텀 블록 노드와 HTML 노드
Toast-UI Editor 깃허브 - 툴바

profile
해보자구

0개의 댓글