반응형
심플업로드 아니고 커스텀이니 알아서 알아들어요.
extraPlugins는 적용안됩니다. 해당 내용을 적용하려면 업로드 시작에서 강탈해야하는데, 안그러면 에디터 자체에서 폐기해버려
아무 반응없음.
실행순서가 input -> click-> editor -> plugin 이라 너무 늦음.
해당 이벤트는 CKeditor onReady 자체에 적용해야합니다.
그래야 이벤트를 강탈 가능.
해당 라이브러리는 @ckeditor/ckeditor5-react를 사용함
// utils/ckeditor.ts
// MIME → 확장자 변환 (있으면 유지)
export function mimesToExts(mimes: string[]) {
const mapping: Record<string, string> = {
'image/jpeg': 'jpeg',
'image/jpg': 'jpg',
'image/png': 'png',
'image/gif': 'gif',
'image/webp': 'webp',
'image/avif': 'avif',
'image/bmp': 'bmp',
};
const exts = new Set<string>();
mimes.forEach((m) => {
const ext = mapping[m.toLowerCase()];
if (ext) exts.add(ext);
});
if (exts.has('jpeg')) exts.add('jpg');
return Array.from(exts);
}
/**
* CKEditor 내부에서 생성되는 input[type="file"]을 가로채서
* 이미지 외 파일 업로드를 막는 강제 검증 함수
*/
export function setupFileInputValidation(
editor: any,
allowedTypes: string[],
onError?: (msg: string) => void
) {
const editorRoot =
editor.ui?.view?.element ||
editor.sourceElement?.parentElement ||
document.querySelector('.ck-editor');
if (!editorRoot) {
console.warn('⚠ 에디터 root 를 찾을 수 없음');
return;
}
// file input에 검증 붙이는 함수
const attachValidation = (input: HTMLInputElement) => {
if (input.dataset.validationAttached === 'true') return;
input.dataset.validationAttached = 'true';
// accept 초기화 (CKEditor가 제한적으로 input을 생성하는 것을 방지)
input.removeAttribute('accept');
input.addEventListener(
'change',
(e) => {
const files = (e.target as HTMLInputElement).files;
if (!files || files.length === 0) return;
const file = files[0];
// 파일 MIME 체크
if (!allowedTypes.includes(file.type)) {
const allowedExts = mimesToExts(allowedTypes)
.map((ext) => ext.toUpperCase())
.join(', ');
onError?.(
`허용되지 않은 파일 형식입니다.\n파일: ${file.name}\n허용 형식: ${allowedExts}`
);
(e.target as HTMLInputElement).value = '';
e.preventDefault();
e.stopImmediatePropagation();
return false;
}
},
{ capture: true }
);
};
// MutationObserver: 동적으로 생성되는 input 캐치
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node.nodeType !== Node.ELEMENT_NODE) return;
const element = node as HTMLElement;
const fileInputs: HTMLInputElement[] = [];
if (element.matches('input[type="file"]')) {
fileInputs.push(element as HTMLInputElement);
}
fileInputs.push(
...Array.from(element.querySelectorAll('input[type="file"]'))
);
fileInputs.forEach(attachValidation);
});
});
});
// 이미 존재하는 input에도 검증 추가
const existingInputs = editorRoot.querySelectorAll('input[type="file"]');
existingInputs.forEach(attachValidation);
// DOM 변경 감지 시작
observer.observe(editorRoot, {
childList: true,
subtree: true,
});
// editor destroy 시 정리
editor.on('destroy', () => observer.disconnect());
}728x90
'취업 > 자바스크립트' 카테고리의 다른 글
| [JS] ckeditor5 bug? No! preview not working ios error! (0) | 2025.12.11 |
|---|---|
| [JS] INPUT 소수점 컨트롤 및 소수점 한번만 입력하게 하기 (0) | 2022.11.16 |
| [JS] input 숫자만 또는 숫자, 영문만 입력하게하기 (0) | 2022.11.16 |
| [JS] AJAX 로딩바 사용시 async: false를 꺼줘야 한다. (0) | 2022.08.08 |
| [JS] Masonry 레이아웃 구성하기. (1) | 2022.08.05 |