Toast-UI Editor에서 Youtube 영상을 주소로 쉽게 삽입할 수 있도록 툴바 버튼을 만들어보았다.
Editor 컴포넌트에 유튜브 공유용 iframe 태그 사용 설정 & 커스텀할 툴바 버튼 추가
→ toolbarItems
와 customHTMLRenderer
옵션에 주목! (나머진 기본 설정)
<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 문자열로 변환할 때 커스터마이징할 수 있는 옵션
툴바 아이템 노드 생성
→ 팝업 바디 노드 생성
→ 이벤트리스너로 유튜브 주소 확인 후 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 번역글
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 깃허브 - 툴바