Last Updated:

Connect a text (wysiwyg) editor to Laravel

Hello. In one of my articles "Connecting CKEditor to Laravel 5.1 and integrating the elFinder file manager into it", I described how to integrate CKEditor into a Laravel application. And everything would be fine, but CKEditor has turned into a "monster" with support for huge functionality, which is unlikely to be useful to me in my projects. And the size of the editor is very inflated. So I decided to find a simple WYSIWYG editor. And my choice fell on Summernote. Very small (about 500 kilobytes and this with all modules and localizations), with support for standard functions.

Next, I will tell you how to connect Summernote to Laravel, make it possible to upload files to the server. And all this we will do on the example of creating articles.

 

A little bit about Summernote

It is a simple and lightweight wysiwyg editor that uses bootstrap. Supports:

  • Localization
  • Format text
  • Insert lists
  • Insert tables
  • Links
  • Ability to upload videos and images
  • Ability to edit code

Laravel Project Preparation

Let's assume that you already have Laravel installed and configured.

I have Laravel 5.5 installed and configured.

To work with the files, I will use the Intervention Image package. How to connect and integrate this package into Laravel I described in the article "Downloading and working with images in Laravel - The Intervention Image package".

Let's create a migration that will create the articles table. Go to the console and run the following command.

    php artisan make:migration CreateArticlesTable --create=articles

Now let's open the migration file and change the up method:

    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->text('text');
            $table->timestamps();
        });
    }

Start the migration.

    php artisan migrate

Perfect migration done, table created.

Now let's create an Article model and an ArticleController controller

    php artisan make:model Article -c

The model and controller are created. Open the Article model and add the following code:

    <?php
        namespace App;

        use Illuminate\Database\Eloquent\Model;

        class Article extends Model
        {
            protected $fillable = [
                'title', 'text'
            ];
}

The model is ready. Now let's move on to the ArticleController. This controller will have four methods:

  • Index – all articles
  • Create – form for creating an article
  • Store – to save the article
  • uploadFile – no server to upload a file

Let's describe the first index method:

    public function index()
    {
        $articles = Article::all();
        return view('index',['articles' => $articles]);
    }

We get all the articles and transfer them to the index.blade.php. Let's create this pack:

<!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>

Now let's describe the second create method.

    public function create()
    {
        return view('create');
    }

This method simply returns a binder with the form of adding the article. Let's create this bunch.

<!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">Add</button>
            </form>
        </div>
    </div>
</body>
</html>

Now let's describe the store method:

    public function store(Request $request)
    {
        Article::create(['title' => $request->title, 'text' => $request->text]);
        return redirect()->route('all');
    }

It remains to add three threads. Open the routes/web.php file and add the following code:

<?php

    Route::get('','ArticleController@index')->name('all');
    Route::get('/create','ArticleController@create')->name('create');
    Route::post('/create','ArticleController@store')->name('store');

Let's check what we got. Follow the link <domain>/create and see the add form. Let's add one article.

Perfectly the functionality itself works. Now let's connect the wysiwyg editor to our article add form.

Connecting the wysiwyg editor to Laravel

Open our vyushka, which contains the form of adding an article. For the Summernote editor to work properly, you need to connect bootstrap and jquery. And then connect the editor itself (file with styles and file with javascritpt). And so let's change the create.blade code.php

After connecting the fonts, add:

<!-- include boostrap -->

<link href="http://netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.css" rel="stylesheet">

<!-- include Summernote styles -->

<link href="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.7/summernote.css" rel="stylesheet">  

And at the end, before the tag </body> add:

<!-- include jquery -->

<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>

<!-- include bootstrap.js -->

<script src="http://netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.js"></script>

<!-- connect summernote itself -->

<script src="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.7/summernote.js"></script>

<script>

$(document).ready(function() {

     $('#text').summernote();

});

</script>  

Let's see what we got:

Great, we plugged in the editor. A little not beautifully displayed, here you can play with styles. I won't stop there. Now let's set up file uploads.

Customize file downloads using the Summernote text editor

Let's open our story with the form of adding an article. And the first thing we will do is replace

<input type="text" name="text" id="text">

on

<textarea name="text" id="text"></textarea>

Second, let's change the script code:

$(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);
        }
   });
}

When you add a file in the editor, the sendFile function will be called. Now let's write a route for /upload

Route::post('upload','ArticleController@upload')->name('upload');

And add the upload method to the ArticleController controller.

    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;
    }

It remains only in the index.blade binder.php to slightly correct the code so that the template engine does not escape the output of the text. To do this, borrow:

<div>{{ $article->text }}</div>

on

<div>{!! $article->text !!}</div>

All. You can check.

Conclusion

We have connected to the project on Laravel a lightweight wysiwyg editor - Summernote, which allows you to upload files (we have configured this), edit the text and much more.