developers blog

TinyMCEに画像アップロード機能を追加する

はじめに

TinyMCEに画像のアップロード機能を追加した時の備忘録。

環境

  • tinymce : 6.0.3

TinyMCEをダウンロードする

自分で契約したサーバなどに設置する場合、https://www.tiny.cloud/get-tiny/ を開き、ページ中ほどにあるDownload TinyMCE Communityのボタンをクリックしてファイルをダウンロードします。

TinyMCEページのダウンロードボタンの場所。

2022/06/20時点で、tinymce_6.0.3.zipがダウンロードされます。
ダウンロードしたzipファイルを解凍し、中のtinymceというフォルダを任意の場所にコピーします。 ここでは説明のため、プロジェクトの直下にコピーしています。

1root
2  ┗  tinymce

TinyMCEを設置して確認する

TinyMCEの動作を確認するため、index.htmlを作成し確認します。

1  root
2    ┣ tinymce
3+   ┗ index.html

index.htmlの中身は以下のようになります。

  • tinymce/tinymce.min.jsファイルを読み込む
  • tinymce.init()を実行(オプションのselectorにはtextaraのセレクタを指定する。ここでは#tinyを指定)
index.html
1<!DOCTYPE html>
2<html lang="ja">
3<head>
4<meta charset="UTF-8">
5<title>TinyMCE</title>
6<script src="./tinymce/tinymce.min.js"></script>
7<script>
8tinymce.init({
9  selector: '#tiny',
10});
11</script>
12</head>
13<body>
14<textarea id="tiny" name="conetnt"></textarea>
15</body>
16</html>

ブラウザを開いて、以下のようにエディタが表示されていれば成功です。

TinyMCEが表示されている

その他のオプションなどは、ドキュメントを参照してください。

TinyMCEを日本語化する

メニューなどを日本語化するために、日本語化ファイルをダウンロードします。

https://www.tiny.cloud/get-tiny/language-packages/ ページを開き、ページをスクロールしてJapaneseと書かれた部分を探し、ダウンロードボタンをクリックしてファイルをダウンロードします。

ja.zipというファイルがダウンロードされるため、解凍し、中にあるja.jsというファイルを/tinymce/langs/フォルダにコピーします。

1  root
2    ┣ tinymce
3    ┃  ┗ langs
4+   ┃     ┗ ja.js
5    ┗ index.html

次にTinyMCEのオプションにlanguage: "ja",を追加します。

1  tinymce.init({
2    language: "ja",
3    selector: '#tiny',
4  });

ブラウザを再読み込みして、メニューが日本語化されていれば成功です。

日本語された画面

画像のアップロード機能を追加する

TinyMCEで画像を扱うために、オプションにplugins: "image",を追加します。

1  tinymce.init({
2    language: "ja",
3    plugins: "image",
4    selector: '#tiny',
5  });

以下のようにメニューの挿入に「画像」が追加されます。

「画像」メニューをクリックすると「画像の挿入/編集」ダイアログが表示されます。

ツールバーに画像ボタンを表示するには、オプションにimageを追加します。

1tinymce.init({
2    language: "ja",
3    plugins: "image",
4    selector: '#tiny',
5    toolbar: ['undo redo | styles | bold italic | alignleft aligncenter alignright alignjustify | outdent indent | image']
6  });

すると、以下のようにツールバーにボタンが追加されます。

次に、画像のアップロードは何通りかの方法があるため、お好みの方法で設定してください。

ファイル送信を手動で行う(images_upload_handler)

images_upload_handler: function () {...}を指定して、アップロード処理を手動で行います。例として、example_upload_handlerという関数を作成してファイルを送信する場合は以下のようになります。

1  tinymce.init({
2    language: "ja",
3    plugins: "image",
4    selector: '#tiny',
5    images_upload_handler: example_upload_handler,
6  });

「画像の挿入/編集」ダイアログに「アップロード」のメニューが追加されます。この場合、画像をドラッグ&ドロップでアップロードすることができます。

example_upload_handlerの中身の例は以下のようになります。

  • サーバのアップロードURLに対して画像ファイルを送信する(ここではpostAcceptor.php
  • JSONデータ受け取った画像のURLをresolveで返す
1const example_upload_handler = (blobInfo, progress) => new Promise((resolve, reject) => {
2  const xhr = new XMLHttpRequest();
3  xhr.withCredentials = false;
4  xhr.open('POST', 'postAcceptor.php');
5
6  xhr.onload = () => {
7    if (xhr.status === 403) {
8      reject({ message: 'HTTP Error: ' + xhr.status, remove: true });
9      return;
10    }
11
12    if (xhr.status < 200 || xhr.status >= 300) {
13      reject('HTTP Error: ' + xhr.status);
14      return;
15    }
16
17    const json = JSON.parse(xhr.responseText);
18
19    if (!json || typeof json.location != 'string') {
20      reject('Invalid JSON: ' + xhr.responseText);
21      return;
22    }
23
24    resolve(json.location);
25  };
26
27  xhr.onerror = () => {
28    reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
29  };
30
31  const formData = new FormData();
32  formData.append('file', blobInfo.blob(), blobInfo.filename());
33
34  xhr.send(formData);
35});

アップロードできる画像の形式を指定するには、images_file_types: '{画像形式}',を指定します。jpgとpngだけアップロードさせたい場合は以下のようにカンマで区切って指定します。

1tinymce.init({
2  language: "ja",
3  plugins: "image",
4  selector: '#tiny',
5  images_upload_handler: example_upload_handler,
6  images_file_types: 'jpg,png',
7});

ファイル送信を手動で行う(file_picker_callback)

file_picker_callback: function () {...}を指定して、アップロード処理を手動で行います。次の例では、example_picker_callbackという関数を使用してファイルを送信します。
images_upload_handlerとの違いは、あちらは画像のみを扱うのに対して、file_picker_callbackは画像以外のファイルも扱うことができます。

1  tinymce.init({
2    language: "ja",
3    plugins: "image",
4    selector: '#tiny',
5    file_picker_callback: example_picker_callback,
6  });

ソースの横に、ファイル選択のボタンが表示されます。

example_picker_callbackの中身の例は以下のようになります。

  • inputを生成し、変更が発生した時にファイルを送信する
  • サーバのアップロードURLに対して画像ファイルを送信する(ここではpostAcceptor.php)
  • JSONデータ受け取った画像のURLをcallbackで返す
1
2const example_picker_callback = (callback, value, meta) => {
3  const input = document.createElement("input");
4  input.setAttribute("type", "file");
5
6  if (meta.filetype === "image") {
7    input.setAttribute("accept", ".png, .jpeg, .jpg, .webp");
8  }
9
10  input.onchange = function () {
11    var file = this.files[0];
12
13    const xhr = new XMLHttpRequest();
14    xhr.withCredentials = false;
15    xhr.open("POST", "postAcceptor.php");
16
17    xhr.onload = () => {
18      if (xhr.status === 403) {
19        reject({ message: 'HTTP Error: ' + xhr.status, remove: true });
20        return;
21      }
22
23      if (xhr.status < 200 || xhr.status >= 300) {
24        callback("HTTP Error: " + xhr.status);
25        return;
26      }
27
28      const json = JSON.parse(xhr.responseText);
29
30      if (!json || typeof json.location != 'string') {
31        callback('Invalid JSON: ' + xhr.responseText);
32        return;
33      }
34
35      callback(json.location);
36    };
37
38    xhr.onerror = () => {
39      reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
40    };
41
42    const formData = new FormData();
43    formData.append("file", file, file.name);
44
45    xhr.send(formData);
46  };
47
48  input.click();
49}

ファイル送信を自動で行い、アップロード先のURLを指定する場合

オプションにimages_upload_url: "{アップロードURL}"を指定することで、アップロードURLに対してファイルを送信します。
./postAcceptor.phpというURLに対してファイルを送信する場合は以下のように指定します。

1  tinymce.init({
2    language: "ja",
3    plugins: "image",
4    selector: '#tiny',
5    images_upload_url: "./postAcceptor.php",
6  });