/** * Summernote Custom JavaScript * - 에디터 초기화, 이미지 처리, 붙여넣기 처리 등 */ /** * 이미지 다이얼로그에 안내 문구 추가 * @param {jQuery} $modal - 모달 jQuery 객체 */ function addImageUploadGuide($modal) { // 이미 안내 문구가 있으면 무시 if ($modal.find('.image-upload-guide').length) return; var guideHtml = '
' + 'info' + '지원 형식: JPG, PNG, GIF, BMP, WEBP / 최대 크기: 10MB' + '
'; // summernote-lite 다이얼로그 구조: .note-modal > .note-modal-content > .note-modal-body var $modalBody = $modal.find('.note-modal-body'); if ($modalBody.length) { $modalBody.prepend(guideHtml); } else { // 대체 위치: 모달 콘텐츠의 첫 번째 자식 앞에 삽입 var $modalContent = $modal.find('.note-modal-content'); if ($modalContent.length) { $modalContent.find('.note-modal-header').after(guideHtml); } } } /** * Summernote 에디터 공통 초기화 함수 * - 이미지 붙여넣기 시 data-uri(Base64) 방식으로 처리 * - 이미지 리사이징 지원 * @param {string} selector - 에디터 selector (예: '#contents') * @param {object} customOptions - 추가 옵션 (선택사항) */ function initSummernote(selector, customOptions) { customOptions = customOptions || {}; // 기본 설정 var defaultOptions = { placeholder: customOptions.placeholder || '여기에 내용을 입력하세요.', height: customOptions.height || 300, lang: 'ko-KR', toolbar: customOptions.toolbar || [ ['font', ['bold', 'underline', 'clear']], ['fontsize', ['fontsize']], ['color', ['color']], ['para', ['ul', 'ol', 'paragraph']], ['table', ['table']], ['insert', ['link', 'picture']], ['view', ['fullscreen', 'codeview', 'help']] ], fontSizes: ['8', '9', '10', '11', '12', '14', '16', '18', '20', '24', '28', '36'], // 이미지 팝오버 설정 - 리사이징 지원 popover: { image: [ ['resize', ['resizeFull', 'resizeHalf', 'resizeQuarter', 'resizeNone']], ['float', ['floatLeft', 'floatRight', 'floatNone']], ['remove', ['removeMedia']] ] }, callbacks: { onInit: function() { var $editable = $(selector).next('.note-editor').find('.note-editable'); $editable.addClass('editor-content'); $editable.on('keydown', function(e) { if (e.keyCode === 8) { e.stopPropagation(); } }); // 커스텀 onInit 콜백 호출 if (customOptions.callbacks && customOptions.callbacks.onInit) { customOptions.callbacks.onInit.call(this); } }, // 이미지 업로드 처리 - data-uri(Base64) 방식 onImageUpload: function(files) { for (var i = 0; i < files.length; i++) { insertImageAsDataUri(files[i], $(selector)); } }, // 붙여넣기 시 이미지 처리 (MS Office 등에서 복사한 이미지 포함) onPaste: function(e) { var clipboardData = e.originalEvent.clipboardData; if (!clipboardData || !clipboardData.items) return; var items = clipboardData.items; var imageFile = null; // 1. 먼저 순수 이미지 파일이 있는지 확인 for (var i = 0; i < items.length; i++) { if (items[i].type.indexOf('image') !== -1) { imageFile = items[i].getAsFile(); break; } } // 2. 이미지 파일이 있으면 data-uri로 변환하여 삽입 if (imageFile) { e.preventDefault(); e.stopPropagation(); insertImageAsDataUri(imageFile, $(selector)); return; } // 3. HTML 붙여넣기인 경우 (MS Office 등) - 이미지 태그 정리 var htmlData = clipboardData.getData('text/html'); if (htmlData && htmlData.indexOf(' maxSize) { alert('이미지 크기는 10MB를 초과할 수 없습니다.'); return; } // 이미지 타입 확인 if (!file.type.match(/image\/(jpeg|jpg|png|gif|bmp|webp)/i)) { alert('지원하지 않는 이미지 형식입니다. (jpeg, png, gif, bmp, webp만 지원)'); return; } var reader = new FileReader(); reader.onload = function(e) { var dataUri = e.target.result; $editor.summernote('insertImage', dataUri, function($image) { // 이미지 스타일 설정 $image.css({ 'max-width': '100%', 'height': 'auto' }); $image.attr('data-filename', file.name); }); }; reader.onerror = function() { alert('이미지 읽기에 실패했습니다.'); }; reader.readAsDataURL(file); } /** * 붙여넣기된 HTML 정리 (MS Office 등에서 복사한 내용) * - 불필요한 Office 속성 제거 * - 이미지 태그 정리 (alt, v:shapes 등 제거) * @param {string} html - 원본 HTML * @returns {string} 정리된 HTML */ function cleanPastedHtml(html) { // 임시 div에서 HTML 파싱 var $temp = $('
').html(html); // 이미지 태그 정리 $temp.find('img').each(function() { var $img = $(this); var src = $img.attr('src'); // src가 없거나 file:// 프로토콜이면 제거 if (!src || src.indexOf('file://') === 0) { $img.remove(); return; } // 불필요한 속성 제거 (Office 관련) var attributesToRemove = ['alt', 'v:shapes', 'o:title', 'style', 'class', 'id', 'name']; attributesToRemove.forEach(function(attr) { $img.removeAttr(attr); }); // 깨끗한 스타일만 적용 $img.css({ 'max-width': '100%', 'height': 'auto' }); }); // VML 태그 제거 (v:, o:, w: 등) var cleanedHtml = $temp.html(); cleanedHtml = cleanedHtml.replace(/]*>[\s\S]*?<\/v:[^>]*>/gi, ''); cleanedHtml = cleanedHtml.replace(/]*>[\s\S]*?<\/o:[^>]*>/gi, ''); cleanedHtml = cleanedHtml.replace(/]*>[\s\S]*?<\/w:[^>]*>/gi, ''); cleanedHtml = cleanedHtml.replace(/]*>[\s\S]*?/gi, ''); // Office 네임스페이스 속성 제거 cleanedHtml = cleanedHtml.replace(/\s*v:[a-z]+="[^"]*"/gi, ''); cleanedHtml = cleanedHtml.replace(/\s*o:[a-z]+="[^"]*"/gi, ''); return cleanedHtml; }