
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、インターネットの世界がとてつもなく広いというのは皆さんもよく感じることだと思うのですが、私の場合も「えっ、そんなの聞いたことない」と驚くことがあります。
今回ご紹介するのはそんな「もっと早く知りたかった」というテクノロジーで、その名もSummernote
という
リッチエディタ(wysiwyg エディタ)
です。
リッチエディタで有名どころといえば、やはり「CKEditor」と「Quill」だと思いますが、Summernote も第3の選択肢として充分使えそうなので今回ご紹介することにしました。
参考ページ: 【Laravel】シンプルにCMSを実装する(CKEditor 5)
ちなみに Summernote
は、jQuery
ベースで作成されているので、レガシーな環境でも使いやすいですし、Bootstrap 3
&4
にも対応しています
ということで、今回はリッチエディタ「Summernote」の使い方をご紹介したいと思います。
ぜひ何かの参考になりましたら嬉しいです。
「アップロード部分は Laravel で
チャチャっとつくります」
開発環境: Laravel 8.x、Vue 3
目次 [非表示]
基本的な使い方
では、まずは基本の使い方をご紹介します。(Bootstrap
無しバージョンです)
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.20/dist/summernote-lite.min.css" rel="stylesheet">
</head>
<body>
<div id="summernote">
<p>ここが初期テキストになります。</p>
<p>改行もOK!</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-lite.min.js"></script>
<script>
$(() => {
$('#summernote').summernote();
});
</script>
</body>
</html>
みなさんご存知のとおり、#
に続くID
を指定することでSummernote
を初期化します。
なお、指定したタグの中にテキストを入れておくと、それが初期状態で表示されるようになります。
ちなみに、(2022.01.01現在)Bootstrap
無しバージョンでは、テキストが空の場合に行がずれるので、もし気になるようでしたら以下のような初期値にするといいでしょう。
<div id="summernote">
<p><br></p>
</div>
たったこれだけでリッチエディタが使えるというのは素晴らしいですね
Bootstrap 4と一緒に使う
続いて、Summernote
はBootstrap 3
& 4
に対応しているので、一緒に使うバージョンもご紹介します。
<html>
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.20/dist/summernote-bs4.min.css" rel="stylesheet">
</head>
<body>
<div class="p-5">
<div id="summernote"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.20/dist/summernote-bs4.min.js"></script>
<script>
$(() => {
$('#summernote').summernote();
});
</script>
</body>
</html>
先ほどと違うのは、(もちろんですが)Bootstrap
の.js
と.css
を読み込んでいるところと、Summernote
の「Bootstrap 専用 JavaScript & CSS」を読み込んでいる部分です。
コードは直接変更しなくていいので、便利ですね
Bootstrap 5 では微妙にうまくいかないっぽいです
公式ページでは、「Supports Bootstrap 3.x.x to 4.x.x」と書かれているのですが、Bootstrap
の最新版はバージョン5系(2022.01.01現在)なので試してみたところ、微妙にうまくいかない部分がありました。
例えば、ポップアップのCSSが効いていない部分があったり、閉じるボタンが機能しないようでした。
おそらくBootstrap 5
からはjQuery
を使わなくなったので、そのあたりの影響もあるんじゃないかと思います。
Summernote を日本語化する
Summernote
は、初期状態では英語が使用されていますが、簡単に多言語対応できるようにしてくれています。
というこで、日本語に対応させてみましょう。
// 省略
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.20/src/lang/summernote-ja-JP.js"></script>
<script>
$(() => {
$('#summernote').summernote({
lang: 'ja-JP'
});
});
</script>
このように専用のJavaScript
を読み込んで言語の設定をするだけでOKです。
Vue 3と連携してみる
Summernote
はjQuery
ベースですが、Vue
と連携して使いたいときもあると思います。
そこで、Summernote
にテキストを入力したら、自動的にVue
のデータに反映されるようにしてみましょう。
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.20/dist/summernote-lite.min.css" rel="stylesheet">
</head>
<body>
<div id="app">
<div id="summernote" v-html="params.description"></div>
<br>
【プレビュー】
<div v-html="params.description"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.20/dist/summernote-lite.min.js"></script>
<script src="https://unpkg.com/vue@3.0.11/dist/vue.global.prod.js"></script>
<script>
Vue.createApp({
data() {
return {
params: {
description: '<p>初期テキスト</p>'
}
}
},
mounted() {
$('#summernote').summernote({
callbacks: {
onChange: (contents, $editable) => { // this が使えなくなるのであえて省略形は使ってません
this.params.description = contents;
}
}
});
}
}).mount('#app');
</script>
</body>
</html>
残念ながら、v-model
で直接バインディングすることはできないので、コールバック関数のonChange
でテキストの変更をVue
側へ伝える必要があります。
また、以下のように省略形のメソッドにするとスコープthis
が変わってしまうので、あえてこの形にしています。
//
これはうまくいかない例です
onChange(contents, $editable) => {
this.params.description = contents; // this はメソッド本体になる
}
画像をアップロードできるようにする
Summernote
は画像のアップロードにも対応していますが、実際に画像を受け取って保存する部分は自分で用意する必要があります。
ということで、この「アップロード部分」をLaravel
でつくってみます。
以下のコマンドを実行してください。
php artisan make:controller SummernoteController
すると、ファイルが作成されるので中身を以下のようにしてください。
app/Http/Controllers/SummernoteController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class SummernoteController extends Controller
{
public function index()
{
return view('summernote.index');
}
public function upload_image(Request $request)
{
$request->validate([
'image' => ['required', 'image', 'mimes:jpeg,png', 'max:2048'],
]);
$file = $request->file('image');
$extension = $file->extension();
$path = 'public/summernote_images';
$filename = date('Ymd-His') .'_'. Str::random(5) .'.'. $extension;
$request->file('image')->storeAs($path, $filename);
return [
'result' => true,
'image_filename' => $filename,
'image_url' => url('/storage/summernote_images/'. $filename)
];
}
}
なお、アップロード先はpublic
フォルダの中になるよう、以下のコマンドを実行して「シンボリックリンク」をつくっておいてください。
php artisan storage:link
次にビューをつくります。
resources/views/summernote/index.blade.php
<html>
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.20/dist/summernote-bs4.min.css" rel="stylesheet">
</head>
<body>
<div id="summernote"></div>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.20/dist/summernote-bs4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script>
$(() => {
$('#summernote').summernote({
callbacks: {
onImageUpload(files) {
const file = files[0];
if(file instanceof File) {
const url = '{{ route('summernote.upload_image') }}';
let formData = new FormData();
formData.append('image', files[0]);
axios.post(url, formData)
.then(response => {
if(response.data.result === true) {
const imageUrl = response.data.image_url;
const imageFilename = response.data.image_filename;
$('#summernote').summernote('insertImage', imageUrl, imageFilename);
}
});
}
}
}
});
});
</script>
</body>
</html>
最後にルートです。
routes/web.php
Route::get('summernote', [SummernoteController::class, 'index'])->name('summernote.index');
Route::post('summernote/upload_image', [SummernoteController::class, 'upload_image'])->name('summernote.upload_image');
これで、以下のように画像がセットできるようになります
エディタのデータをゲット&セットする
手動でエディタにデータをゲット&セットするにはsummernote('code')
を使います。
// 省略
<button id="get_button" type="button">データをゲット</button>
<button id="set_button" type="button">データをセット</button>
// 省略
<script>
$(() => {
$('#summernote').summernote();
// データをゲット
$('#get_button').on('click', () => {
const contents = $('#summernote').summernote('code');
console.log(contents);
});
// データをセット
$('#set_button').on('click', () => {
const contents = '<p>これは<b>テスト</b>です!</p>';
$('#summernote').summernote('code', contents);
});
});
</script>
デモをつくりました
せっかくなので、Summernote
のデモページをつくりました。
ぜひご自身で試してみてください。
企業様へのご提案
Summernote
はMITライセンスで提供されていますので、完全に無料で利用することができます。(CKEditor
は、アクティブユーザーが増えると有料になります)
また、冒頭でも書きましたとおり、jQuery
とBootstrap
を使って動きますので、長らく使用されているシステムにも適用がしやすいと思います。
もし既存システムでリッチエディタを使いたい場合はぜひお問い合わせからご依頼ください。
ぜひよろしくお願いいたします。m(_ _)m
おわりに
ということで、今回は「もうひとつのリッチエディタ」のSummernote
をご紹介しました。
実際に触ってみましたところ、操作感に問題があるようには感じませんでしたし、Bootstrap
と親和性が高いの特に業務系システムに向いていると思いました。
また、こういった新しいパッケージやライブラリを使う場合に「GitHubでスターが多いかどうか」というのも判断材料にしますが、Summernote
は(この記事を書いている時点で)10,000スターを超えているので、とても人気があると言っていいんじゃないでしょうか。
ぜひ皆さんもSummernote
を試してみてくださいね。
ではでは〜
「久しぶりにゲームをはじめましたが、
飽きてプログラムしてます
面白いから…」