Summernote — простой и мощный WYSIWYG редактор для Laravel

Рано или поздно каждому разработчику приходится заниматься интеграцией текстового WYSIWYG редактора во фреймворк Laravel. В принципе, это касается любого другого фреймворка или CMS. Как только заходит речь о WYSIWYG редакторе, то сразу всплывает из подсознания два таких монстра, как CKEditor и TinyMCE. Бесспорно — это отличные проекты, которые имеют громадный функционал. Но также они имеют и громадный размер.

Summernote подойдёт для Laravel  и других фреймворков

Ещё встречается проблема, что прикрутить их к тому или иному web-проекту не всегда тривиальная задача. Огромные дистрибутивы, множество файлов настроек, приличный пакет документации — это только один из моментов, с которым вы столкнётесь при установке этих решений.

Что нужно от текстового WYSIWYG редактора?

  • возможность работать всегда и везде
  • очень маленький размер дистрибутива
  • минимальный набор необходимого функционала
  • быстрая скорость загрузки
  • элементарная интеграция в любое текстовое поле
  • возможность простой и быстрой настройки под свои нужды
  • загрузка файлов в сам редактор, файл при этом можно сохранить на диске
  • удаление файлов из редактора, файл при этом можно удалить с диска
  • возможность легко и быстро написать свой плагин

Как бы не были хороши редакторы CKEditor и TinyMCE, но по многим пунктам они не очень подходят. А всё потому, что они из простого решения превратились уже сами в реальные фреймворки.

Summernote — лучший визуальный редактор для Laravel

Для большинства разработчиков и пользователей нужно более простое и гибкое решение. Простой редактор, созданный на Bootstrap, который весит всего 500 Кб — Summernote. И это вместе с плагинами и файлами локализации!

В нём есть все самое необходимое, чего вполне достаточно для создания любого контента. Помимо этого он простой и лёгкий, в нём уже есть возможность вставлять видео и изображения. Но самое главное — это то, что на сохранение и удаление изображений можно легко навесить свои обработчики. А это означает, что вы можете легко и не принуждено организовать систему автозагрузки и автоудаления изображений на диске.

Установка и настройка Summernote в Laravel

Создадим файл resources/assets/js/summernote_editor_settings.js:

/**
* Settings for summernote editor.
*/
$(document).ready(function () {
$(document).ready(function () {
var editor = $('#editor-body');
var configFull = {
lang: 'ru-RU', // default: 'en-US'
shortcuts: false,
airMode: false,
minHeight: null, // set minimum height of editor
maxHeight: null, // set maximum height of editor
focus: false, // set focus to editable area after initializing summernote
disableDragAndDrop: false,
callbacks: {
onImageUpload: function (files) {
uploadFile(files);
},
onMediaDelete: function ($target, editor, $editable) {
var fileURL = $target[0].src;
deleteFile(fileURL);
// remove element in editor
$target.remove();
}
}
};
// Featured editor
editor.summernote(configFull);
// Upload file on the server.
function uploadFile(filesForm) {
data = new FormData();
// Add all files from form to array.
for (var i = 0; i < filesForm.length; i++) {
data.append("files[]", filesForm[i]);
}
$.ajax({
data: data,
type: "POST",
url: "/ajax/uploader/upload",
cache: false,
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
contentType: false,
processData: false,
success: function (images) {
//console.log(images);
// If not errors.
if (typeof images['error'] == 'undefined') {
// Get all images and insert to editor.
for (var i = 0; i < images['url'].length; i++) {
editor.summernote('insertImage', images['url'][i], function ($image) {
//$image.css('width', $image.width() / 3);
//$image.attr('data-filename', 'retriever')
});
}
}
else {
// Get user's browser language.
var userLang = navigator.language || navigator.userLanguage;
if (userLang == 'ru-RU') {
var error = 'Ошибка, не могу загрузить файл! Пожалуйста, проверьте файл или ссылку. ' +
'Изображение должно быть не менее 500px!';
}
else {
var error = 'Error, can\'t upload file! Please check file or URL. Image should be more then 500px!';
}
alert(error);
}
}
});
}
// Delete file from the server.
function deleteFile(file) {
data = new FormData();
data.append("file", file);
$.ajax({
data: data,
type: "POST",
url: "/ajax/uploader/delete",
cache: false,
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
contentType: false,
processData: false,
success: function (image) {
//console.log(image);
}
});
}
});
});

В принципе из кода понятно, что WYSIWYG редактор будет цепляться на элемент с id=»editor-body». Это должен быть textarea тэг:

<div class="form-group">
<div class="form-group{!! $errors->has('body') ? ' has-error' : '' !!}">
{!! Form::label('body', 'Body' . ':', ['class' => 'control-label']) !!}
{!! Form::textarea('body', NULL, ['class' => 'form-control', 'id' => 'editor-body']) !!}
@if ($errors->has('body'))
<span class="help-block">
<strong>{!! $errors->first('body') !!}</strong>
</span>
@endif
</div>
</div>

Что касается обработчиков, то они уже настроены на работу пакета для управления изображениями Laravel UploadImage.

Если вы используете Elixir Laravel, то нужно не забыть добавить файл настроек в gulp файл:

// Copy editor settings for summernote.
mix.copy('resources/assets/js/summernote_editor_settings.js', 'public/js/summernote_editor_settings.js');

В данном конкретном случае я просто скопировал файл. Также стоит не забывать, что у вас должен быть подключен Bootstrap:

<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js";></script>

Подключать его нужно в главном шаблоне app.blade.php

Сам же дистрибутив Summernote нужно разместить в папке public, например в public/modules/summernote

Теперь в шаблоне формы, где будет редактор, нужно подключить три файла: сам редактор, файл локализации и файл с настройками:

{{-- Add wysiwyg script --}}
<script src="{!! asset('modules/summernote/summernote.js') !!}"></script>
{{-- Include summernote-ru-RU --}}
<script src="{!! asset('modules/summernote/lang/summernote-ru-RU.js') !!}"></script>
{{-- Include editor settings file for users --}}
<script src="{!! asset('js/summernote_editor_settings.js') !!}"></script>

Вот и всё! В итоге вы получите возможность не просто добавлять тексты и форматировать их, но и легко добавлять изображения в текст, не заботясь о том, как их загрузить на сервер, а потом удалить. Всё будет происходить автоматически! При этом, за раз можно выделить сразу десять файлов и они одним махом вставятся в редактор.

FAQ по Summernote и WYSIWYG редакторам

Вы не пробовали реализовать загрузку не картинок а файлов по той же схеме с отображением в итоге ссылки на скачивание? Очень актуальная проблема. Да и как посмотрю, разработчик Summernote тоже ничего не предпринял в этом направлении.

Можно сделать к редактору плагин. Тут в принципе нет ничего сложного. По сути, ведь изображение — это тот же файл. Вопрос только в том, чтобы вместо файла не залили какой-то вредоносный код, который даст злоумышленнику доступ к вашему серверу. А значит, нужно со стороны бэкенда делать какой-то анализатор загружаемого файла.

По сути смысл в том, чтобы перехватить файл из формы и передать его аяксом на бэкенд. Бэкенд php его проверят, сохранят и возвратят назад в плагин ссылку на файл, которую потом плагин вставит в редактор.

Вот ссылка на их АПИ: https://summernote.org/deep-dive/#insertion-api. Нужно получить путь к файлу, который вы сохраните на бэке. А в колбэк аякса вернуть простую текстовую ссылку: https://mysite.com/myfile.txt

После чего вставить в виде текста в редактор, например так:

// @param {String} text$('#summernote').summernote('insertText', '<a href="' + myLink + '">' + 'Download file</a>');

Установка параметра options в «maximumImageFileSize: null» ничего не меняет, ограничения по размеру файла всё равно остаются до 3 мегабайт. Это только где-то в summernote, на сервере и в форме ограничений нет. Вы с таким не сталкивались?

Не уверен, что null корректное значение. Вот тут есть пример, https://github.com/summernote/summernote/issues/2307

If found the solution:
$(this).summernote({
maximumImageFileSize: 524288 # 512KB
});
PS: to caluclate the number, you need to multiply 1024. Example:
1024 * 512KB = 524288