Подключаем текстовый (wysiwyg) редактор к Laravel
Доброго времени суток. В одной из своих статей «Подключаем CKEditor к Laravel 5.1 и интегрируем в него файловый менеджер elFinder» я описал как интегрировать CKEditor в приложение на Laravel. И все бы хорошо, но CKEditor превратился в «монстра» с поддержкой огромного функционала, который мне в моих проектах вряд ли пригодится. Да и размер редактора уж очень раздулся. Поэтому решил я найти простенький WYSIWYG редактор. И мой выбор пал на Summernote. Очень маленький (около 500 килобайт и это со всеми модулями и локализациями), с поддержкой стандартных функций.
Дальше я расскажу как подключить Summernote к Laravel, сделать возможность загрузки файлов на сервер. А все это мы будем делать на примере создания статей.
Немного о Summernote
Это простой и легкий wysiwyg редактор, использующий bootstrap. Поддерживает:
- Локализацию
- Форматирование текста
- Вставку списков
- Вставку таблиц
- Ссылок
- Возможность загрузки видео и изображений
- Возможность редактировать код
Подготовка проекта на Laravel
Будем считать, что у вас уже установлен и настроен Laravel.
У меня установлен и настроен Laravel 5.5.
Для работы с файлами я буду использовать пакет Intervention Image. Как подключить и интегрировать данный пакет в Laravel я описал в статье «Загрузка и работа с изображениями в Laravel — пакет Intervention Image».
Давайте создадим миграцию, которая будет создавать таблицу articles. Переходим в консоль и выполняем следующую команду.
php artisan make:migration CreateArticlesTable --create=articles
Теперь давайте откроем файл миграции и изменим метод up:
public function up() { Schema::create('articles', function (Blueprint $table) { $table->increments('id'); $table->string('title'); $table->text('text'); $table->timestamps(); }); }
Запускаем миграцию.
php artisan migrate
Отлично миграция выполнена, таблица создана.
Теперь создадим модель Article и контроллер ArticleController
php artisan make:model Article -c
Модель и контроллер созданы. Открываем модель Article и добавляем следующий код:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Article extends Model { protected $fillable = [ 'title', 'text' ]; }
Модель готова. Теперь переходим к контроллеру ArticleController. Данный контроллер будет иметь четыре метода:
- Index – все статьи
- Create – форма для создания статьи
- Store – для сохранения статьи
- uploadFile – для загрузки файла не сервер
Давайте опишем первый метод index:
public function index() { $articles = Article::all(); return view('index',['articles' => $articles]); }
Получаем все статьи и передаем их во вьюшку index.blade.php. Давайте создадим данную вьюшку:
<!doctype html> <html lang="{{ app()->getLocale() }}"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Laravel</title> <!-- Fonts --> <link href="https://fonts.googleapis.com/css?family=Raleway:100,600" rel="stylesheet" type="text/css"> <!-- Styles --> <style> html, body { background-color: #fff; color: #636b6f; font-family: 'Raleway', sans-serif; font-weight: 100; height: 100vh; margin: 0; } .full-height { height: 100vh; } .position-ref { position: relative; } .top-right { position: absolute; right: 10px; top: 18px; } .content { text-align: center; } .title { font-size: 84px; } .links > a { color: #636b6f; padding: 0 25px; font-size: 12px; font-weight: 600; letter-spacing: .1rem; text-decoration: none; text-transform: uppercase; } .m-b-md { margin-bottom: 30px; } </style> </head> <body> <div class=" position-ref full-height"> <div class="content"> @foreach($articles as $article) <h1>{{ $article->title }}</h1> <div>{{ $article->text }}></div> <hr><br> @endforeach </div> </div> </body> </html>
Теперь давайте опишем второй метод create.
public function create() { return view('create'); }
Данный метод просто возвращает вьюшку с формой добавления статьи. Давайте создадим данную вьюшку.
<!doctype html> <html lang="{{ app()->getLocale() }}"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="csrf-token" id="csrf-token" content="{{ csrf_token() }}"> <title>Laravel</title> <!-- Fonts --> <link href="https://fonts.googleapis.com/css?family=Raleway:100,600" rel="stylesheet" type="text/css"> <!-- Styles --> <style> html, body { background-color: #fff; color: #636b6f; font-family: 'Raleway', sans-serif; font-weight: 100; height: 100vh; margin: 0; } .full-height { height: 100vh; } .position-ref { position: relative; } .top-right { position: absolute; right: 10px; top: 18px; } .content { text-align: center; } .title { font-size: 84px; } .links > a { color: #636b6f; padding: 0 25px; font-size: 12px; font-weight: 600; letter-spacing: .1rem; text-decoration: none; text-transform: uppercase; } .m-b-md { margin-bottom: 30px; } </style> </head> <body> <div class=" position-ref full-height"> <div class="content"> <form action=" {{ route('store') }} " method="POST"> {{ csrf_field() }} <label for="title">Заголовок</label><br /> <input type="text" name="title" id="title"><br /> <label for="text">Текст</label><br /> <input type="text" name="text" id="text"><br /> <button type="submit">Добавить</button> </form> </div> </div> </body> </html>
Теперь опишем метод store:
public function store(Request $request) { Article::create(['title' => $request->title, 'text' => $request->text]); return redirect()->route('all'); }
Осталось добавить три роута. Открываем файл routes/web.php и добавляем следующий код:
<?php Route::get('','ArticleController@index')->name('all'); Route::get('/create','ArticleController@create')->name('create'); Route::post('/create','ArticleController@store')->name('store');
Проверяем, что у нас получилось. Переходим по ссылке <домен>/create и видим форму добавления. Давайте добавим одну статью.
Отлично сам функционал работает. Теперь давайте к нашей форме добавления статьи подключим wysiwyg редактор.
Подключение wysiwyg редактора к Laravel
Открываем нашу вюшку, которая содержит форму добавления статьи. Для полноценной работы редактора Summernote необходимо подключить bootstrap и jquery. А затем подключить сам редактор (файл со стилями и файл с javascritpt). И так давайте изменим код create.blade.php
После подключения шрифтов добавим:
<!-- подключаем boostrap --> <link href="http://netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.css" rel="stylesheet"> <!-- подключаем стили Summernote --> <link href="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.7/summernote.css" rel="stylesheet">
А в конец, перед тегом </body> добавим:
<!-- подключаем jquery --> <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script> <!-- подключаем bootstrap.js --> <script src="http://netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.js"></script> <!-- подключаем сам summernote --> <script src="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.7/summernote.js"></script> <script> $(document).ready(function() { $('#text').summernote(); }); </script>
Давайте посмотрим, что у нас получилось:
Отлично, редактор мы подключили. Немного не красиво отображается, тут можно поиграть со стилями. На этом я не буду останавливаться. Теперь давайте настроим загрузку файлов.
Настройка загрузки файлов, используя текстовый редактор Summernote
Открываем нашу вьюшку с формой добавления статьи. И первое, что мы сделаем заменим
<input type="text" name="text" id="text">
на
<textarea name="text" id="text"></textarea>
Второе поменяем код скрипта:
$(document).ready(function() { $('#text').summernote({ callbacks: { onImageUpload: function(files) { var el = $(this); sendFile(files[0],el); } } }); }); function sendFile(file, el) { var data = new FormData(); data.append("file", file); var url = '{{ route('upload') }}'; $.ajax({ data: data, type: "POST", headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')}, url: url, cache: false, contentType: false, processData: false, success: function(url2) { el.summernote('insertImage', url2); } }); }
При добавлении файла в редакторе будет вызываться функция sendFile. Теперь давайте пропишем маршрут для /upload
Route::post('upload','ArticleController@upload')->name('upload');
А в контроллер ArticleController добавим метод upload.
public function upload(Request $request) { $path = public_path().'\images\\'; $file = $request->file('file'); $filename = str_random(20) .'.' . $file->getClientOriginalExtension() ?: 'png'; $img = Image::make($file); $img->save($path . $filename); echo '/images/'.$filename; }
Осталось только во вьюшке index.blade.php немного поправить код, чтобы шаблонизатор не экранировал вывод текста. Для этого заемним:
<div>{{ $article->text }}</div>
на
<div>{!! $article->text !!}</div>
Все. Можно проверить.
Заключение
Мы с вами подключили к проекту на Laravel легковесный wysiwyg редактор – Summernote, который позволяет загружать файлы (мы это настроили), редактировать текст и многое другое.
Не работает загрузка изображений в редакторе :(
Странно. А версия Laravel какая? И какую ошибку выдает?
Два вопроса:
— А как удаляются картинки с диска, если они перестают использоваться в тексте?
— А как загружать не картинки, а прикрепляемые файлы и получать на них ссылки? И чтобы имена файлов были не рандомными а родными?
Все просто. Посмотрите загрузка файлов
Работа с файлами
Не загружаются фотографии с компьютера, а с интернета работают, что делать?
Почему не загружается фотография в редактор при выборе картинки из пк, а если картинку с компьютера скопировать и вставить в редактор то работает?