이 섹션에서는 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');
};