Trixで画像アップロードを利用する

# はじめに

WYSIWYG エディタの Trix を使ってみました。画像アップロード機能も利用できるようにしたので、その手順を載せます。
Spring Boot で試しましたが、他の環境でも同様にできると思います。

[Trix: A rich text editor for everyday writing](https://trix-editor.org/)
[GitHub](https://github.com/basecamp/trix)

# 環境

* Java
* Spring Boot
* Thymeleaf
* H2 Database
* lombok

# 対象者

* 基本的な Java のコーディングができる方
* Spring で Web アプリ開発をしたことがある方

# 前提

コード量が多くなるので、記事では Trix により近い部分にフォーカスして扱います。割愛したソースは下記 GitHub で確認していただければと思います。
アプリのひな形は [Spring initializr](https://start.spring.io/) で作りました。Dependencies には以下のものを追加しました。その他はデフォルトです。

![スクリーンショット 2021](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525650/2aa580a3-129a-d491-486f-bb2d319a7e2d.png)

# 作ったもの

GitHub に作ったものを置いてあります。
https://github.com/kyamadahoge/trix-spring-boot-test

# Trix を動かす

以下のファイルを作ります。

<details><summary>編集画面のHTML</summary><div>

```html:edit.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/trix/1.3.1/trix.min.css" integrity="sha512-5m1IeUDKtuFGvfgz32VVD0Jd/ySGX7xdLxhqemTmThxHdgqlgPdupWoSN8ThtUSLpAGBvA8DY2oO7jJCrGdxoA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
  <script src="https://cdnjs.cloudflare.com/ajax/libs/trix/1.3.1/trix.min.js" integrity="sha512-2RLMQRNr+D47nbLnsbEqtEmgKy67OSCpWJjJM394czt99xj3jJJJBQ43K7lJpfYAYtvekeyzqfZTx2mqoDh7vg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
  <form data-th-action="@{/save}" method="post" data-th-object="${form}">
    <input type="hidden" data-th-field="*{content}">
    <trix-editor input="content" class="trix-content"></trix-editor>
    <button>保存</button>
  </form>
</body>
</html>
```

* `<input>` には Trix に入力した内容の HTML が出力されるようにします
    * この値を DB に保存します
* `<trix-editor>` が Trix がレンダリングされる部分です
    * この要素の `input` 属性と、HTML 出力先要素の `id` 属性を同じ値（ここでは `content`）にしておきます
    * これで Trix に入力した内容の HTML 出力先がひも付けられます

</div></details>

* その他必要なソース（上記 GitHub 参照）
    * 編集画面の Controller, Form, Service, Repository, Entity クラス
    * 表示画面の html
    * DB 初期化用の DDL
    * application.yml

ここまで出来たら :arrow_down: でアプリを起動します。

```shell
./mvnw spring-boot:run
```

http://localhost:8080/edit を開くと Trix エディタを触ることができます。エディタで編集したり保存したり、保存した内容を見たりできるようになっています。
画像のアップロードはこの先の手順を踏むとできるようになります。

![スクリーンショット 2021-](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525650/bbf73f74-47e4-cbf0-566e-aa906880a464.png)

## 画像をアップロードできるようにする

Trix はエディタ内に画像をドラッグ＆ドロップするとアップロードできる仕組みを用意しています。これを利用するにはもう少し手順が必要です。

### 画像アップロードするコード

<details><summary>編集画面の HTML</summary><div>

上記 `edit.html` に `<script>` を追加します。
ドラッグ＆ドロップを検出してファイルをアップロードする JavaScript を実装します。

```html:edit.html
<script data-th-inline="javascript">
(function() {
  const url = "[(@{/image/put})]";

  addEventListener('trix-attachment-add', event => {
    if (event.attachment.file) {
      uploadFileAttachment(event.attachment);
    }
  });

  const uploadFileAttachment = attachment => {
    const setProgress =
      progress => attachment.setUploadProgress(progress);
    const setAttributes =
      attributes => attachment.setAttributes(attributes);
    uploadFile(attachment.file, setProgress, setAttributes);
  };

  const uploadFile = (file, progressCallback, successCallback) => {
    const formData = createFormData(file);
    const xhr = new XMLHttpRequest();

    xhr.open('POST', url, true);

    xhr.upload.addEventListener('progress', event => {
      const progress = event.loaded / event.total * 100;
      progressCallback(progress);
    });

    xhr.addEventListener('load', event => {
      if (xhr.status === 201) {
        const data = JSON.parse(xhr.responseText);
        const attributes = {
          url: data.url
        };
        successCallback(attributes);
      }
    });

    xhr.send(formData);
  };

  const createFormData = file => {
    const data = new FormData();
    data.append('contentType', file.type);
    data.append('file', file);
    return data;
  };

})();
</script>
```

</div></details>

* その他必要なソース（上記 GitHub 参照）
    * 画像用の Controller, Service, Repository, Entity クラス

これでエディタ内に画像をドラッグ＆ドロップすると、アップロードされエディタ内に表示されるようになります。

# 所感

Trix は Ruby で扱われる記事は見かけたものの Java の例が見つけられなかったので、今回取り組んでみました。
画像アップロードの方法も併せて、この記事がどなたかの参考になれば幸いです。