WYSIWYGエディタを導入してみた

  • August 23, 2023

試運転中の掲示板アプリはユーザーがスレッドを立てることが出来るのですが、
自由度が高い部分があり、HTMLをユーザー自身に書いてもらう形になっています。

その際に、エンジニアならまだしも、一般のユーザーには敷居が高いかもしれないと思い、WYSIWYGエディタを試してみることにしました。

CLEditorでサクッと

色々なWYSIWYGエディタがあるようなのですが、シンプルで簡単に導入できそうなCLEditor を使ってみました。
HPからzipファイルをダウンロードし、その中のjsファイルとcssファイルをプロジェクトに設置します。
あとの使い方はドキュメントにある通り、基本形は以下です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<html>
<head>
  <link rel="stylesheet" href="jquery.cleditor.css" />
  <script src="jquery.min.js"></script>
  <script src="jquery.cleditor.min.js"></script>
  <script>
      $(document).ready(function () { $("#input").cleditor(); });
  </script>
</head>
<body>
  <textarea id="input" name="input"></textarea>
</body>
</html>

ツールバーにたくさんの機能が表示されますが必要なものだけをcontrolsパラメータに設定すればすっきりします。

1
2
3
4
5
6
7
8
9
$(document).ready(function () { $("#input").cleditor({
    height: 400,
    controls: // controls to add to the toolbar
        "bold italic underline strikethrough | size " +
        "style | color highlight removeformat | bullets numbering | outdent " +
        "indent | undo redo | " +
        "rule image link unlink | source",
    bodyStyle: 'font-family:serif'
}); });

こんな感じになります。
sb

このCLEditorで1からHTMLを書くよりもだいぶ楽だな~という印象です。
ただ、自分だけが使うなら十分ですが一般ユーザーが使う際に使いづらいだろうなという点がありました。
画像の追加がURL指定でないとできないことです。

大抵のユーザはエディタ上においてローカルPCの画像を選択して追加できることを期待すると思いました。
ということで他のWYSIWYGエディタも漁ってみました。

イケてるCKEditor

先ほどのCLEditorと一文字違いですが、CKEditor についての情報がネット上にたくさんあって画像アップロードもいけそうだったので使ってみることにしました。

CDNからの利用もできるし、たくさんある機能の中からカスタマイズしてオンラインでビルドしたものをダウンロードできるのも便利でいいです✨✨

https://ckeditor.com/ckeditor-5/online-builder/

ただ実際にそれらの手軽な方法でインストールしたCLEditorを使ってみると、したいことが微妙にできないことが分かってきました。
まずオンラインビルドでは画像処理に必要なプラグインのCKBoxが有料になると判明…!

alter-text

月5千円くらい。まぁまぁしますw

クラウドの利用代もあるので無駄使いはしたくないということで、今度はCDNを試してみることに。
このへん を参考にコードを書いていきます。

alter-text

いい感じです。

わ~い!と思っていたのですが、使っていくとCDNでは直接HTMLを記述する機能が無いことに気づきました。
ここの機能です。 alter-text

CLEditorでは出来たのに…。

CKEditorでもSource-Editing というプラグインを利用することで実装できます。
ということで、画像処理とHTML記述機能の両方を持っているCKEditorを自分でビルドすることにしました。

カスタムビルド

こちら の手順に従います。

…が、この手順、個人的にとてもわかりずらく少しハマってしまいました。
元となるコードはGitから取得する必要があります。(そう書いてよ!)
また、Node.js, npmが必要です。

1, git clone https://github.com/ckeditor/ckeditor5.git でソースコードを取得。
2, 必要なパッケージを作業用ディレクトリに持ってくる。

私の場合はClassicのエディタで良かったのでこちら のソースコードを作業用のディレクトリにコピーしてきました。

追記:tsconfig.types.jsonの中でckeditor5リポジトリ直下にあるtsconfig.jsonを継承しているので、そちらもよしなにコピーしてくる必要があります。
そもそも作業用ディレクトリにコピーする必要もなかったかもしれません。
cloneしてきたソースコードの中でビルドを行う方が手間が無かったかもです。。

3, 依存関係のインストール
1
npm install

私はSource-Editingというプラグインが必要だったので以下でインストールします。

1
npm install @ckeditor/ckeditor5-source-editing

4, src/ckeditor.tsの修正

追加したSource-Editingをこのファイルに追記します。
以下のような記載になりました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  */

// The editor creator to use.
import { ClassicEditor as ClassicEditorBase } from '@ckeditor/ckeditor5-editor-classic';

import { Essentials } from '@ckeditor/ckeditor5-essentials';
import { UploadAdapter } from '@ckeditor/ckeditor5-adapter-ckfinder';
import { Autoformat } from '@ckeditor/ckeditor5-autoformat';
import { Bold, Italic } from '@ckeditor/ckeditor5-basic-styles';
import { BlockQuote } from '@ckeditor/ckeditor5-block-quote';
import { CKBox } from '@ckeditor/ckeditor5-ckbox';
import { CKFinder } from '@ckeditor/ckeditor5-ckfinder';
import { EasyImage } from '@ckeditor/ckeditor5-easy-image';
import { Heading } from '@ckeditor/ckeditor5-heading';
import { Image, ImageCaption, ImageStyle, ImageToolbar, ImageUpload, PictureEditing } from '@ckeditor/ckeditor5-image';
import { Indent } from '@ckeditor/ckeditor5-indent';
import { Link } from '@ckeditor/ckeditor5-link';
import { List } from '@ckeditor/ckeditor5-list';
import { MediaEmbed } from '@ckeditor/ckeditor5-media-embed';
import { Paragraph } from '@ckeditor/ckeditor5-paragraph';
import { PasteFromOffice } from '@ckeditor/ckeditor5-paste-from-office';
import { Table, TableToolbar } from '@ckeditor/ckeditor5-table';
import { TextTransformation } from '@ckeditor/ckeditor5-typing';
import { CloudServices } from '@ckeditor/ckeditor5-cloud-services';
import { SourceEditing } from '@ckeditor/ckeditor5-source-editing';

export default class ClassicEditor extends ClassicEditorBase {
public static override builtinPlugins = [
Essentials,
UploadAdapter,
Autoformat,
Bold,
Italic,
BlockQuote,
CKBox,
CKFinder,
CloudServices,
EasyImage,
Heading,
Image,
ImageCaption,
ImageStyle,
ImageToolbar,
ImageUpload,
Indent,
Link,
List,
MediaEmbed,
Paragraph,
PasteFromOffice,
PictureEditing,
Table,
TableToolbar,
TextTransformation,
SourceEditing
];

	public static override defaultConfig = {
		toolbar: {
			items: [
				'undo', 'redo',
				'|', 'heading',
				'|', 'bold', 'italic',
				'|', 'link', 'uploadImage', 'insertTable', 'blockQuote', 'mediaEmbed',
				'|', 'bulletedList', 'numberedList', 'outdent', 'indent',
				'|', 'sourceEditing'
			]
		},
		image: {
			toolbar: [
				'imageStyle:inline',
				'imageStyle:block',
				'imageStyle:side',
				'|',
				'toggleImageCaption',
				'imageTextAlternative'
			]
		},
		table: {
			contentToolbar: [
				'tableColumn',
				'tableRow',
				'mergeTableCells'
			]
		},
		// This value must be kept in sync with the language defined in webpack.config.js.
		language: 'jp'
	};
}

5, 再ビルド
1
npm run build
6, サンプルエディタを起動して検証

コピーしてきたソースコードの中にsample/index.htmlがあると思うので、それをブラウザで起動し、ちゃんとビルドされているか確認します。

以上で問題なく、必要な機能を持つCKEditorがビルドできたらbuild/ckeditor.jsをプロジェクトに設置します。
これでやっと画像処理とHTML記述機能を持ったWYSIWYGエディタを用意できました。

画像処理について

もちろん画像アップロード処理は自分で用意しなければなりません。
ドキュメントはこのへん を参照します。
CKEditor側は以下のようにし、画像をPOSTしその後の処理を行うエンドポイントとして「/api/image-upload」というルートを用意しました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<script>
    ClassicEditor
        .create( document.querySelector( '#detail' ), {
            ckfinder: {
                uploadUrl: '/api/image-upload'
            }
        } )
        .catch( error => {
            console.error( error );
        } );
</script>

エンドポイントの/api/image-uploadでは、画像を受け取りS3にアップロードしてJSONを返す処理を用意しました。
ここで返すJSONは以下の形でないといけないようです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 処理が失敗したとき
{
    "uploaded": false,
    "error": {
        "message": "Error message here"
    }
}

// 処理が成功したとき
{
    "url": "http://example.com/path/to/image",
    "uploaded": true
}
npm install @ckeditor/ckeditor5-source-editing

おわりに

以上の内容以外にも、実際にはscriptタグが自動的に削除されてしまうので色々悩みました。
XSS対策で当然の挙動だとは思いますが、X(旧Twitter)を埋め込むときなんかはscriptタグが必要なので、
一般ユーザが触るフォームにはCKEditorを、管理者のエンジニアが触るフォームにはCLEditorを利用することにしました。
CLEditorは自由度が比較的高く(というか作りが甘いため?)、scriptタグが削除される挙動を避ける抜け道がありました。

意外と大変なWYSIWYGエディタの導入でした。

以下参考にさせていただいた日本語記事になります。
ありがとうございます!
https://qiita.com/59naga/items/3f75128db11e140457c8 https://qiita.com/sawadashota/items/984fa2c73dfd2062a1a4

comments powered by Disqus

関連の投稿

2023年クリスマス・イヴの武蔵野市長選で感じたこと。波乱尽くしの年末年始。

  • February 23, 2024

2023年、外国人参政権や米屋騒動など様々な分断を産んで武蔵野市を荒らしまくった松下前市長が国政に挑むため辞任。 投票率の下がるクリスマス・イヴに市長選挙が設定されるタイミングで辞任するという姑息さを最後まで見せつけました。 松下前市長の後継・笹岡ゆうこ氏が極左天国・武蔵野市で組織票を得て優位かとみられましたが、一般市民の皆さんの熱意によって小美濃新市長が誕生しました。 この結果は吉祥寺徒歩圏内に住む杉並区民としてもとても嬉しいことでした。 SNSでの選挙応援について感じたこと 管理人は杉並区政についての情報収集を目的としてSNSのXにアカウントを作っています。

もっと読む

【考察】岸本聡子区長~黒い人脈~(随時加筆)

  • October 30, 2023

岸本区長の人脈を考える上で外せないのは西荻窪という土地でしょう。 西荻窪には彼女の住まいがあるのは勿論ですが、岸本区長の支持母体とも言える人達が集まっています。 また、岸本区長に近しいブランシャー明日香議員のカフェ「カワセミピプレット」や山名かなこ議員のNPO法人「The F-Word」も西荻に存在します。 西荻平和通り商店街会長 区政ウォッチャーなら言わずと知れた岸本聡子をかつぎだした人物、水越強 氏。

もっと読む

杉並人民共和国ってギャグじゃないかも

  • July 30, 2023

7月に掲示板を本番環境で公開してしばらく試運転中ですが 作成されたスレッドをTwitterなどのSNSで発信したり、というのを少しずつ始めています。 湧き始めた五毛党(?) 始めたばかりのアカウントで実のある発信も全然できてないので、フォロワーさんも数人しかいないのですが、 ほぼ毎日おかしな海外アカウントからフォローされています笑

もっと読む