어제 xly.kr에 44개의 컨텐트를 업로드하고 조급한 마음에 검수를 철저히 안하고 공유했더니 일부 글이 제대로 표현되지 않는 문제가 있었습니다.
문제의 원인은 컨텐트 본문에 포함된 예제 코드들이 문제를 일으킨 것이었습니다. 이메일로 발송했던 걸 HTML로 변환해서 넣고 이를 다시 뷰에 표현하는 과정에서 문제가 발생한 것인데요. 이래저래 다양한 방법을 시도해보다가 어차피 나중에 추가해야하는 기능이라 이번 참에 WYSIWYG 에디터를 도입해결하기로 결심했어요. 아무래도 개발 컨텐트다 보니 코드도 쉽게 작성할 수 있어야하고 해서 마크다운으로 작성이 가능한 에디터를 찾아보니 NHN에서 공개한 TOAST UI 에디터가 눈에 띄었습니다.
TOAST UI 에디터는 해외에서도 굉장히 호평을 받고 있는 것 같습니다. 그런데 라라벨에서 TOAST UI 에디터를 사용하는 방법을 정리한 글을 찾기가 힘들더군요. 그래서 라라벨에서 TOAST UI 에디터를 사용하는 방법을 정리해봤습니다.
`<span class="il">laravel</span> new tui
`
resources/views/tui.blade.php
를 만들고 아래와 같이 작성합니다.
`<!DOCTYPE html>
<html>
<head>
<script src="{{ mix('/css/app.css') }}"></script>
</head>
<body>
<h1>TOAST UI 에디터 예제</h1>
<div id="editSection"></div>
</body>
<script src="{{ mix('/js/app.js') }}"></script>
</html>
`
/
에 접근시 준비한 뷰를 보여줄 수 있도록 라우트를 아래와 같이 변경합니다.
`<?php
Route::get('/', function () {
return view('tui');
});
`
에셋이 컴파일되지 않아서 뷰의 mix('/js/app.js')
구문에서 에러가 납니다. 에셋을 컴파일합니다.
`npm install
npm run dev
`
웹 브라우저로 /
를 방문해봅니다.
`npm install --save tui-editor
`
app.js
파일에 다음의 내용을 추가합니다.
`// 에디터에 필요한 의존성 추가
require('codemirror/lib/codemirror.css'); // codemirror
require('tui-editor/dist/tui-editor.css'); // editor ui
require('tui-editor/dist/tui-editor-contents.css'); // editor content
require('[highlight.js/styles/](http://highlight.js/styles/)github.css'); // code block highlight
var Editor = require('tui-editor');
var editor = new Editor({
el: document.querySelector('#editSection'),
initialEditType: 'markdown',
previewStyle: 'vertical',
height: '300px'
});
`
변경된 내용이 있으니 에셋을 다시 컴파일합니다.
`npm run dev
`
이제 ‘/‘에 접근하면 다음과 같이 에디터가 나타날 것입니다.
에디터에 작성하기만 해서는 아무짝에도 쓸모가 없습니다. 에디터로 작성한 내용을 서버로 전송해서 저장을 하고 이를 불러와서 화면에 표현할 수 있어야 의미가 있겠죠. 간단한 CRUD 예제를 만들어봅시다.
`php artisan make:model Post -a
`
-a
는 마이그레이션, 팩토리, 리소스 컨트롤러도 함께 만드는 옵션입니다.
새로 추가된 마이그레이션 파일(XXX_create_posts_table.php라는 이름으로 생성되어있을 겁니다.)을 열어 content
컬럼을 추가해줍니다.
`public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->bigIncrements('id');
$table->text('content');
$table->timestamps();
});
}
`
마이그레이션을 실행합니다.
`php artisan migrate
`
DB 설정이 잘못되어 있으면 에러가 날텐데, 잘 해결하시리라 믿습니다. ^^
에디터를 띄운 /
에 폼을 추가해보도록 하겠습니다.
resources/views/tui.blade.php
를 다음과 같이 수정합니다.
`<!DOCTYPE html>
<html>
<head>
<script src="{{ mix('/css/app.css') }}"></script>
</head>
<body>
<h1>TOAST UI 에디터 예제</h1>
<div id="editSection"></div>
<form action="/posts" method="POST">
@csrf
<textarea name="content" style="display:none"></textarea>
<input type="submit">
</form>
</body>
<script src="{{ mix('/js/app.js') }}"></script>
</html>
`
textarea가 보이지 않도록 display:none 으로 설정했습니다. 제출 버튼을 누르면 TOAST UI 에디터에 작성한 내용을 textarea에 채워서 전송할 겁니다. 이 작업을 편히 하기 위해 jquery를 추가합니다.
`npm install jquery
`
resources/js/app.js 파일에 아래 구문을 추가합니다.
`window.$ = require("jquery");
`
다시 에셋을 컴파일하면 어디서든 $로 jquery를 사용할 수 있습니다.
에디터 객체도 페이지에서 사용할 수 있도록 Editor도 window에 할당합니다. Editor 객체 초기화하는 코드는 뷰로 옮깁니다. 이 단계에서 app.js
는 다음과 같습니다.
`require('./bootstrap');
// deps for editor
require('codemirror/lib/codemirror.css'); // codemirror
require('tui-editor/dist/tui-editor.css'); // editor ui
require('tui-editor/dist/tui-editor-contents.css'); // editor content
require('[highlight.js/styles/](http://highlight.js/styles/)github.css'); // code block highlight
window.Editor = require('tui-editor');
window.$ = require("jquery");
`
뷰는 다음과 같이 바꿉니다.
`<!DOCTYPE html>
<html>
<head>
<script src="{{ mix('/css/app.css') }}"></script>
</head>
<body>
<h1>TOAST UI 에디터 예제</h1>
<div id="editSection"></div>
<form action="/posts" method="POST">
@csrf
<textarea name="content" style="display:none"></textarea>
<input type="submit">
</form>
</body>
<script src="{{ mix('/js/app.js') }}"></script>
<script>
var editor = new Editor({
el: document.querySelector('#editSection'),
initialEditType: 'markdown',
previewStyle: 'vertical',
height: '300px'
});
$('form').submit(function(e){
e.preventDefault();
$('textarea').val(editor.getHtml());
this.submit();
});
</script>
</html>
`
app.js
에 있던 Editor 초기화 코드를 옮겨왔습니다.
폼을 전송하면 이를 가로채서 에디터의 내용을 textarea에 넣어 보냅니다. 에디터의 내용을 가져올 때 editor.getHtml()
을 사용했습니다. HTML로 변환되기 전의 컨텐트를 가져오려면 editor.value()
를 쓰면 됩니다.
라우트에 Post 리소스 라우트를 추가합니다.
`// routes/web.php
Route::resource('posts', 'PostController');
`
PostController
의 store
메소드를 작성합니다.
`public function store(Request $request)
{
$post = Post::create($request->all());
return redirect(route('posts.show', $post->id));
}
`
content
값을 저장할 수 있도록 Post
에 $fillable
을 설정해줍니다.
`class Post extends Model
{
protected $fillable = ['content'];
}
`
resources/views/posts/show.blade.php
파일을 만들고 아래 내용을 입력합니다.
`<!DOCTYPE html>
<html>
<head>
<script src="{{ mix('/css/app.css') }}"></script>
</head>
<body>
<h1>TOAST UI 에디터 예제</h1>
<div>{{ $post->content }}</div>
</body>
<script src="{{ mix('/js/app.js') }}"></script>
</html>
`
에디터로 입력했던 값이 HTML 태그와 함께 보여질 것입니다. {{ }}
는 기본적으로 이스케이핑을 하기 때문입니다. HTML 태그가 실제로 동작하게 하려면 {{ }}
를 {!! !!}
로 바꿔줍니다.
`<!DOCTYPE html>
<html>
<head>
<script src="{{ mix('/css/app.css') }}"></script>
</head>
<body>
<h1>TOAST UI 에디터 예제</h1>
<div>{!! $post->content !!}</div>
</body>
<script src="{{ mix('/js/app.js') }}"></script>
</html>
`
이상으로 라라벨에서 TOAST UI 에디터를 이용해서 글을 작성, 저장, 조회 해봤습니다. 허접한 코드지만 동작은 하니 아예 감을 못잡으시는 분들께는 도움이 될거라 생각합니다. 이제 도구는 마련해두었으니 내일은 제대로 글을 읽으실 수 있게 싹 손 봐두겠습니다. (내일까진 안보이는 글이 꽤 있을거에요 ㅠ) xly.kr에 버그가 있으면 언제든 연락주세요~!
1일 1식 라라벨 54호
2019년 9월 17일
메쉬 코리아 개발자. 바쁜 팀장님 대신 알려주는 신입 PHP 개발자 안내서를 쓰고, 클린 아키텍처 인 PHP를 번역했습니다. 처음부터 제대로 배우는 라라벨(Laravel Up & Running 2nd Edition)을 번역했습니다.