본문 바로가기
ETC/Libralies

[CKEditor5] 한 페이지에 여러 개의 CKEditor5 사용하기

by 은z 2024. 8. 22.

상황

CKEditor5를 사용하여 게시글을 작성할 수 있도록 기능을 구현했다.

그런데 한 화면에 여러개의 에디터를 사용할 수 있도록 기능을 변경해달라는 요구사항이 들어왔다.

(아래 사진에는 [추가] [삭제] 버튼이 안보이지만, 요구사항에는 [추가] 버튼 클릭 시에 에디터 하나가 더 늘어나고 [삭제] 버튼을 클릭하면 에디터 하나가 제거되는 기능도 있어야 한다.)

 

에디터의 개수는 동적으로 늘어나고 줄어들 수 있도록 기능 변경

 


 

html, js를 하나씩 뜯어보자.

✔️html

<table>
    <colgroup>
        <col width="20%">
        <col width="*">
    </colgroup>
    <tbody>
    <tr>
        <th>
            제목
        </th>
        <td>
            <div>
                <div>
                    <input type="text" id="title_0" name="title">
                </div>
            </div>
        </td>
    </tr>
    <tr class="editor_0">
        <th>내용</th>
        <td>
            <div>
                <div>
                    <div class="box-textarea" data-index="0">
                        <textarea id="contents_0" type="textarea" name="contents"></textarea>
                    </div>
                </div>
            </div>
        </td>
    </tr>
    </tbody>
</table>


...


<script type="text/javascript" src="/app/js/settingEditors.js"></script>

 

📌소스에서 box-textarea class 부분은 display none 처리 되고, 그 자리에 에디터 객체가 생성된다.

여러개의 에디터를 생성해야 하기 때문에 tr 태그의 class명을 "editor_0" 이렇게 선언했다.

그리고 에디터 관련된 설정 파일(settingEditors.js)을 import 하여 삽입했다. (마지막 라인)

 

 

✔️js

📌이제 js파일을 살펴보자.

/**
 * 한 페이지에 여러개의 에디터 객체가 있는 경우 사용한다.
 */

window.editors = {}; // 에디터 객체 저장할 객체 초기화

let settingEditors = {
	
	/**
	 *
	 * @param className 에디터가 위치할 태그를 감싸고 있는 클래스명
	 */
	// 에디터 객체 생성
	fnCreateEditor : function (className) {
		// 에디터 이미지 업로더 객체 생성
		class CustomUploadAdapter {
			constructor( loader ) {
				this.loader = loader;
			}

			upload() {
				return this.loader.file
						.then( file => new Promise( ( resolve, reject ) => {
							this._initRequest();
							this._initListeners( resolve, reject, file );
							this._sendRequest( file );
						} ) );
			}

			abort() {
				if ( this.xhr ) {
					this.xhr.abort();
				}
			}

			_initRequest() {
				const xhr = this.xhr = new XMLHttpRequest();
				xhr.open( 'POST', '에디터 안에서 이미지 업로드 api mapping url 삽입', true );
			}

			_initListeners( resolve, reject, file ) {
				const xhr = this.xhr;
				const loader = this.loader;
				const genericErrorText = `Couldn't upload file: ${ file.name }.`;
				xhr.addEventListener( 'error', () => reject( genericErrorText ) );
				xhr.addEventListener( 'abort', () => reject() );
				xhr.addEventListener( 'load', () => {
					const response = xhr.response;
					if ( !response || response.error ) {
						return reject( response && response.error ? response.error.message : genericErrorText );
					}
					resolve( {
						default: response.url
					} );
				} );
				if ( xhr.upload ) {
					xhr.upload.addEventListener( 'progress', evt => {
						if ( evt.lengthComputable ) {
							loader.uploadTotal = evt.total;
							loader.uploaded = evt.loaded;
						}
					} );
				}
			}

			_sendRequest( file ) {
				const data = new FormData();
				data.append( 'upload', file );
				this.xhr.send( data );
			}
		}

		ClassicEditor
        .create( document.querySelector( className ), {

            // 제거할 플러그인 목록
            removePlugins: [
                'Markdown', // 플러그인 기능 제대로 동작하지 않는 현상이 있어 제거
                'Title', // 제목, 내용 영역 구분되지 않도록 제거
                'MediaEmbedToolbar' // 'widget-toolbar-no-items' 콘솔 에러 해결을 위해 제거 (필요 시 제거 구문 삭제 후 툴바 관련 별도 설정 필요)
            ],

            // placeholder 문구 설정
            placeholder: '내용을 입력해 주세요.',

            // 폰트 설정 (cf. https://ckeditor.com/docs/ckeditor5/latest/features/font.html)
            fontFamily: {
                options: [
                    'default', // 웹페이지 스타일에 정의된 기본 글꼴이 사용됨
                    '굴림체',
                    '궁서체',
                    '돋움체',
                    '맑은 고딕',
                    '바탕체',
                    'Arial, Helvetica, sans-serif',
                    'Courier New, Courier, monospace',
                    'Georgia, serif',
                    'Lucida Sans Unicode, Lucida Grande, sans-serif',
                    'Tahoma, Geneva, sans-serif',
                    'Times New Roman, Times, serif',
                    'Trebuchet MS, Helvetica, sans-serif',
                    'Verdana, Geneva, sans-serif'
                ],
                supportAllValues: true // options에 지정되지 않은 폰트 값 제거되지 않도록, 모든 폰트에 대한 지원을 활성화
            },

            // 폰트 사이즈 설정
            fontSize: {
                options: [
                    // 'tiny', 'small', 'big', 'huge',
                    8, 9, 10, 11, 12, 14, 'default', 18, 20, 22, 24, 26, 27, 28, 36, 40
                ],
                supportAllValues: true // options에 지정되지 않은 폰트 사이즈 값 제거되지 않도록, 모든 폰트 사이즈에 대한 지원을 활성화
            },

            // 미디어 설정
            mediaEmbed: {
                previewsInData: true // true 설정 시 'youtube, vimeo, spotify, dailymotion'플랫폼 미디어는 Previewable HTML을 생성해준다.
            },

            // 이미지 설정
            image: {
                resizeUnit: 'px' // 에디터 이미지 리사이징 % -> px
            },
        } )

        .then( editor => {
            let index = document.querySelector( className ).getAttribute("data-index");
            window.editors[index] = editor; //에디터 객체
            editor.plugins.get("FileRepository").createUploadAdapter = (loader) => {
                return new CustomUploadAdapter(loader);
            };
        } )
        .catch( error => {
            console.error( 'Oops, something went wrong!' );
            console.error( 'Please, report the following error on https://github.com/ckeditor/ckeditor5/issues with the build id and the error stack trace:' );
            console.warn( 'Build id: v9p5egss3j3b-hoyae661l7f7' );
            console.error( error );
        } );


	},

	/**
	 * 컨텐츠의 내용 삽입
	 * @param contents 에디터에 삽입할 내용을 넘겨준다.
	 */
	fnSetContents: function (index, contents) {
		// 에디터가 로드되는 데 시간이 걸려서 setTimeout으로 데이터 셋팅 지연시킴
		setTimeout(function() {
			window.editors[index].setData(contents); // 에디터 내용 set
		}, 100);
	},


};

$(function(){
	settingEditors.init();
});

 

📌  window.editors = {}; 라고 최상단에 빈 객체를 선언해주고, window.editors[index] 로 에디터 객체를 세팅해주면 된다.

 

'ETC > Libralies' 카테고리의 다른 글

[CKEditor] CKEditor4 사용하기  (0) 2021.12.17
[Lombok] 롬복 설치 및 STS, eclipse 연동  (0) 2021.10.18

댓글