summernoteの使い方 Laravelの管理画面側でCMS機能をサクッと実装するよ（AdminLTE）

summernoteの記事あんまないよな〜って思ったので書きま〜す😎

# 前提
LaravelでAdminLTEを使用した管理画面側での動作確認しか行っていませんので、他の環境で動くかは保証できません🤷‍♂️
が、たぶん動くんじゃないかな？🥺

# summernoteとは
簡単に言うとブログなどを書く機能をサクッと実装できちゃういいヤツ🥺
こんな感じ
![スクリーンショット 2021-03-07 18.50.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588802/e1c91d96-cd78-a8c6-36b6-5d943c9d47c2.png)

詳しくはこちらをどうぞ😇
[summernote公式](https://summernote.org/)

# 実装方法
簡単に実装方法をまとめます🙆‍♂️

まず、共通で使用している `layouts/app.blade.php` の `<head>` 内に

````resources/views/layouts/app.blade.php
<head>

...

<!-- include libraries(jQuery, bootstrap) -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>

<!-- include summernote css/js -->
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.js"></script>
</head>

````

こいつを書き書き🤗


そしたら次に対象のbladeファイルに（ここでは例で `summernote.blade.php` としますう〜🤗）

````resources/views/summernote.blade.php
@extends('layouts.app')
@section('title', タイトルをいれてね)
@section('content')

  {{-- summernoteのエディター --}}
  <div id="summernote"></div>

  {{-- これから書くjsファイル読み込んでね --}}
  <script src="{{ asset('summernote.js') }}"></script>
@endsection
````


次にｊｓファイルいくよお〜😇

新規追加

````resources/js/summernote.js
import axios from 'axios';

$(function () {

  /**
  * テキストエディター summernote
  */
  $(document).ready(function() {
    $('#summernote').summernote({
      toolbar: [
        // ツールバーリスト
        // 他にも種類があるので公式サイトを見てみてくださいね♪
        ['style', ['bold', 'italic', 'underline', 'clear']],
        ['font', ['strikethrough', 'superscript', 'subscript']],
        ['fontsize', ['fontsize']],
        ['color', ['color']],
        ['para', ['ul', 'ol', 'paragraph']],
        ['height', ['height']]
      ],
    });
  });
});
````

あとは `webpack.mix.js` に追加したjaファイルを追記

````webpack.mix.js

...

mix.js('resources/js/app.js', 'public/js')
    .js('resources/js/summernote.js', 'public/js/summernote.js') // 追記
    .sass('resources/sass/app.scss', 'public/css');
````

`npm run watch-poll` などなどコンパイルしてもらうと

エディターが表示されます🤗
![スクリーンショット 2021-03-07 18.50.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588802/e1c91d96-cd78-a8c6-36b6-5d943c9d47c2.png)

# summernoteの問題点
summernoteは便利でエディターで書いた文章が実際には以下のように変換されて保存するときにはそのまま文字列としてリクエストが送られます🙆‍♂️

````
<p>ブログも書けるよ〜</p>
<p style="cssの記述">背景色も設定できるよ〜</p>
````

ただ、画像を添付した際には
Base64にエンコードされたとてつもない文字数のデータになって保存されます🥲

例でいうと

````
<p>ブログも書けるよ〜</p>
<p style="cssの記述">背景色も設定できるよ〜</p>
<img src="Base64でエンコードされた文字列が何千文字となってここに格納されます">
````

これはこのまま使うとなんか微妙ですよね🤔

# 画像が選択されたら非同期で画像をS3にアップロードしたい🥺

できれば画像が選択された時にS3にアップロードしてimgタグにそのURLを挿入したいところですよね🤔 
そうすれば無駄に長い文字列を保存しなくて済みます😇

````
改善前
<img src="Base64でエンコードされた画像データの文字列3０００~5０００文字ぐらい？">
改善後
<img src="S3にアップロードしたURLを挿入（多分30文字ぐらいだと思う）">
````

# 実装するよっ😇

summernoteの公式を確認すると `onImageUpload` 関数があります。
画像が選択されるとこいつが呼ばれて、
`insertImage` でエディターのimgタグのsrcに値を格納することができます😇
そいつをjsファイルに追記してあげましょう🤗


````resources/js/summernote.js
import axios from 'axios';

$(function () {

  /**
   * テキストエディター summernote
   */
  $(document).ready(function() {
    $('#summernote').summernote({
      toolbar: [
        // ツールバーリスト
        // 他にも種類があるので公式サイトを見てみてくださいね♪
        ['style', ['bold', 'italic', 'underline', 'clear']],
        ['font', ['strikethrough', 'superscript', 'subscript']],
        ['fontsize', ['fontsize']],
        ['color', ['color']],
        ['para', ['ul', 'ol', 'paragraph']],
        ['height', ['height']]
      ],

      // ここから追記

      callbacks: {
       // 画像挿入
       async onImageUpload(files) {
          // 画像アップロード
          const res = await uploadS3(files[0]);
          // レスポンスが正常か判定
          if(res) {
            // 正常な場合はエディターに反映
            $('#summernote').summernote('insertImage', res.data.url);
          }
        }
      }
    });
  });

  /**
   * 画像をS3にアップロードする
   * @param file
   * @returns {Promise<AxiosResponse<any> | void>}
   */
  function uploadS3(file) {
    const data = new FormData();
    // これで画像ファイルをbase64にエンコードしてくれます
    data.append('file', file);
    return axios.post(
      エンドポイント,
      data
    ).catch((error) => {
      // エラーハンドリング
    });
  }
});
````

こんな感じであとはサーバー側でルーティングとコントローラーでS3にアップロードする処理を書いてあげれば実装完了です🤗

あ、jsファイル編集したらコンパイル忘れないでね🥺

# ユーザー側に表示する場合

ユーザー側とか表示する場合は

````
{!! $記事の内容 !!}
````

みたいにして `｛！！ !!}` で囲んであげてくださいな😎
`{{ }}` だとタグもそのままデちゃうよ🥲

以上、summernote実装方法でした〜😆

わからないことがあればコメントしてね🥺




# おわり😇

お・わ・り🌟