TinyMCE7.2+CKFinder3.7.0

tinymce-ckfinder

TinyMCE7.2を使いたくて、ファイルマネージャーを探していたらCKFinderを見つけたので組み合わせて実装してみた。特にアカウント登録とかも不要だった。

 

TinyMCE7.2の実装

公式からJSファイルをダウンロード
https://www.tiny.cloud/get-tiny/

 

JSを読み込んでinitするだけで、基本的には旧バージョンと同じ。

最小構成サンプル

<script src="./js/tinymce/tinymce.min.js"></script>
tinymce.init({
  selector: '#mytextarea',
  language: 'ja',
  theme :"silver",
  body_class: "tiny_mce_class",
  content_css : "./css/editor.css",
  height: 500,
  toolbar_sticky: true,
  menubar: false,
  branding: false,
  license_key: 'gpl',
  plugins: 'code preview link image table fullscreen lists',
  toolbar: ['code preview undo redo cut copy paste styles bold italic underline strikethrough forecolor backcolor removeformat link unlink hr alignleft aligncenter alignright bullist numlist image table fullscreen'],
});
<textarea id="mytextarea">Hello, World!</textarea>

 

CKFinderを組み込む

CKFinderをダウンロード

https://ckeditor.com/ckfinder/download/

 

jsフォルダの中にtinymce、ckfinderを置くように配置。

tiny-ck
  

ckfinder/config.phpを編集

66行目あたり baseUrl /files/ に変更

 

$config['backends'][] = array(
    'name'         => 'default',
    'adapter'      => 'local',
    'baseUrl'      => '/files/',
//  'root'         => '', // Can be used to explicitly set the CKFinder user files directory.
    'chmodFiles'   => 0777,
    'chmodFolders' => 0755,
    'filesystemEncoding' => 'UTF-8',
);

 

CKfinderの動作環境にPHP8.2以上が必要だったためテスト環境のMAMPを最新にアップデートして8.3を使用。

MAMP/conf/php8.3.1/php.ini に以下を追加。

extension=fileinfo

 

MAMP環境では権限がなかったので、

ckfinder/conf.phpの28行目あたり、

return falsereturn true に変更。

実稼働時にはセキュリティ処理が必要。

 

$config['authentication'] = function () {
    return true;
};

 

ckfinderを読み込む

<script src="./js/ckfinder/ckfinder.js"></script>

 

TinyMCE init({})に追加

tinymce.init({
  selector: 'textarea',
  plugins: 'image',
  toolbar: 'image ckfinder',
  setup: function(editor) {
    editor.ui.registry.addButton('ckfinder', {
      text: 'Insert Image',
      onAction: function() {
        openCKFinder(editor);
      }
    });
  },
  file_picker_callback: function(callback, value, meta) {
    if (meta.filetype == 'image') {
      openCKFinder(tinymce.activeEditor, callback);
    }
  }
});

function openCKFinder(editor, callback) {
  CKFinder.modal({
    chooseFiles: true,
    width: 800,
    height: 600,
    onInit: function(finder) {
      finder.on('files:choose', function(evt) {
        var file = evt.data.files.first();
        var url = file.getUrl();
        if (callback) {
          callback(url, {text: file.get('name')});
        } else {
          editor.insertContent('<img src="' + url + '">');
        }
      });
      finder.on('file:choose:resizedImage', function(evt) {
        var url = evt.data.resizedUrl;
        if (callback) {
          callback(url, {text: evt.data.name});
        } else {
          editor.insertContent('<img src="' + url + '">');
        }
      });
    }
  });
}

 

toolbar: に追加する

toolbar: 'ckfinder',

 

アイコンを変更

このままだと、ツールバーに「画像の挿入」と表示されているので、アイコンに変更する。

 

マテリアルデザインスタイルのアイコンセットを使用時

icons: 'material', 

 

TinyMCEにあるアイコンを使用

text:の部分を以下に変更

icon: 'upload',
tooltip: 'ファイルのアップロード',

 

ソース全体

<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, maximum-scale=1.0">
    <title>TinyMCE7</title>
		<script src="./js/tinymce/tinymce.min.js"></script>
		<script src="./js/ckfinder/ckfinder.js"></script>

<script>
  tinymce.init({
	selector: '#mytextarea',
	language: 'ja',
	theme :"silver",
	body_class: "tiny_mce_class",
	content_css : "./css/editor.css",
	height: 500,
	toolbar_sticky: true,
	menubar: false,
	branding: false,
	license_key: 'gpl',
	icons: 'material',
	plugins: 'code preview link image table fullscreen lists',
	toolbar: ['code preview undo redo cut copy paste styles bold italic underline strikethrough forecolor backcolor removeformat link unlink hr alignleft aligncenter alignright bullist numlist image ckfinder table fullscreen'],

  setup: function(editor) {
    editor.ui.registry.addButton('ckfinder', {
      icon: 'upload',
      tooltip: 'ファイルのアップロード',
      onAction: function() {
        openCKFinder(editor);
      }
    });
  },
  file_picker_callback: function(callback, value, meta) {
    if (meta.filetype == 'image') {
      openCKFinder(tinymce.activeEditor, callback);
    }
  }
});

	function openCKFinder(editor, callback) {
		CKFinder.modal({
			chooseFiles: true,
			width: 800,
			height: 600,
			onInit: function(finder) {
				finder.on('files:choose', function(evt) {
					var file = evt.data.files.first();
					var url = file.getUrl();
					if (callback) {
						callback(url, {text: file.get('name')});
					} else {
						editor.insertContent('<img src="' + url + '">');
					}
				});
				finder.on('file:choose:resizedImage', function(evt) {
					var url = evt.data.resizedUrl;
					if (callback) {
						callback(url, {text: evt.data.name});
					} else {
						editor.insertContent('<img src="' + url + '">');
					}
				});
			}
		});
	}
</script>
  </head>
  <body style="padding:10px;">
		<textarea id="mytextarea">Hello, World!</textarea>
	<p>&nbsp;</p>
	<p>&nbsp;</p>
  </body>
</html>

 

tinymce-7

 

※設置時には画像保存ディレクトリは存在せず、画像を保存した時に、今回の設定の場合は、ルートディレクトリにfilesディレクトリが作成され、その中のimagesディレクトリの中に保存される。

 

カスタムアイコンを使う

アイコンを既存の物ではなく、独自の物を使用する場合、SVGなども使える。

tinymce.init({
  // ... 他の設定 ...
  setup: function(editor) {
    editor.ui.registry.addIcon('custom-image', '<svg width="24" height="24" focusable="false">  <path d="M10.7 20H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2v4.1M17 17a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 0 3 3" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>');
    
    editor.ui.registry.addButton('ckfinder', {
      icon: 'custom-image',
      tooltip: '画像の挿入',
      onAction: function() {
        openCKFinder(editor);
      }
    });
  },
  // ... 他の設定 ...
});

 

全体

<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, maximum-scale=1.0">
    <title>TinyMCE7</title>
		<script src="./js/tinymce/tinymce.min.js"></script>
		<script src="./js/ckfinder/ckfinder.js"></script>

<script>
  tinymce.init({
	selector: '#mytextarea',
	language: 'ja',
	theme :"silver",
	body_class: "tiny_mce_class",
	content_css : "./css/editor.css",
	height: 500,
	toolbar_sticky: true,
	menubar: false,
	branding: false,
	license_key: 'gpl',
	plugins: 'code preview link image table fullscreen lists',
	toolbar: ['code preview undo redo cut copy paste styles bold italic underline strikethrough forecolor backcolor removeformat link unlink hr alignleft aligncenter alignright bullist numlist image ckfinder table fullscreen'],

  setup: function(editor) {
    editor.ui.registry.addIcon('custom-image', '<svg width="24" height="24" focusable="false">  <path d="M10.7 20H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2v4.1M17 17a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 0 3 3" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>');

    editor.ui.registry.addButton('ckfinder', {
      icon: 'custom-image',
      tooltip: 'ファイルのアップロード',
      onAction: function() {
        openCKFinder(editor);
      }
    });
  },
  file_picker_callback: function(callback, value, meta) {
    if (meta.filetype == 'image') {
      openCKFinder(tinymce.activeEditor, callback);
    }
  }
});

	function openCKFinder(editor, callback) {
		CKFinder.modal({
			chooseFiles: true,
			width: 800,
			height: 600,
			onInit: function(finder) {
				finder.on('files:choose', function(evt) {
					var file = evt.data.files.first();
					var url = file.getUrl();
					if (callback) {
						callback(url, {text: file.get('name')});
					} else {
						editor.insertContent('<img src="' + url + '">');
					}
				});
				finder.on('file:choose:resizedImage', function(evt) {
					var url = evt.data.resizedUrl;
					if (callback) {
						callback(url, {text: evt.data.name});
					} else {
						editor.insertContent('<img src="' + url + '">');
					}
				});
			}
		});
	}
</script>
  </head>
  <body style="padding:10px;">
		<textarea id="mytextarea">Hello, World!</textarea>
	<p>&nbsp;</p>
	<p>&nbsp;</p>
  </body>
</html>

 

エディタの中身だけ指定ピクセル以上に広がらないようにするCSS

editor.css

body.tiny_mce_class{
	width:800px;
	max-width:100%;
}

.tiny_mce_class img{
	max-width:100%;
	height:auto;
}