トップ «前の日記(2018-09-09) 最新 次の日記(2018-09-19)» 編集

日々の破片

著作一覧

2018-09-11

_ TinyMCEの使い方

SimpleMDEをしばらく使っていたが色を付けたいというような要望があって、そりゃマークダウンにはないし、かといって直接spanを書かせるわけにもいかないし、というわけでいろいろWYSIWYG系のブラウザ用エディターを調べて、結局TinyMCEに落ち着いた。

が、ドキュメントがいまいちわかりにくくて、どのプラグインが追加有償なのかといったこともなかなかわかりにくい。でも、まあ、そのあたりは解決して(一番使いたいのはTextColorでこれはデフォルトプラグインだし、次に使いたいのはTableで、これもデフォルトプラグインだった)が、一番の問題点は、入力されたデータをどう扱えるか、だった。

それ以外の使い方はなんかおかしなドキュメント(懇切丁寧だが、同じことを何度も何度も繰り返して書いてあるコピペプログラミングみたいな感じ)に書いてあるし、日本語でもうすこしまともに整理してくれてあるサイトもある(今ググってみつけた)。

知りたいのに素直にわからないのは次の2点だ。

  • データの取り出しと設定
  • 変化の検知

前者は、AJAXでサーバーへ送信したり、保存したデータをサーバーで初期設定するときに必要だし、後者はサーバーへ送信するタイミングを得るために必須だ。

TinyMCE自身はtinymce.init({selector: '#ID'(とか.parent .classとか)})と、ラップするtextareaのセレクタを与えればすぐに使えるすぐれものではあるが、ドキュメントにはtextareaをフォームに入れればsubmitされるからOKみたいにしか書いてない。でも待て。ユーザーが長い文章を入力して一息つこうとした瞬間にWordはクラッシュしブラウザーはハングしたりクラッシュする。だから、Submitを待ってはならない道理だ。最初は単純に$('#textarea').val()とすれば取り出せるのではないかと思ったが、ラップさせるTEXTAREAそのものは本当に単なるダミーとしてしか利用していないらしくて入力はまったく反映されない(逆方向はサポートしていてTEXTAREAにあらかじめ設定した内容は初期値としてロードされる)。

あと、動的に作るのは新たにDOMに追加したtextareaをtinymce.iniに与えれば良いからOKとして、削除はどうするんだ? とかも知りたいところ。で、そのあたりのJS用のAPIがいまひとつわかりにくかったので以下にまとめる。

TinyMCEのエディタオブジェクトの取得方法

  • tinymce.initで指定できるinit_instance_callbackの引数で与えられたオブジェクトを使う
      tinymce.init({selector: '#textarea', 
                    init_instance_callback: (editor) => {
                       texteditor = editor; // 後で使う
                     }
                    })
    
  • IDをtinymceに与えて取得する。
      let editor = tinymce.get('textarea'); // セレクタではなくIDなので#を付けてはだめ。はまった。
    
  • tinymce.editors配列から探す。

エディタオブジェクトの破壊方法(textareaの破壊前に行う。そうでないとおかしなことが起きる)

  • IDを指定する。
     tinymce.remove('#textarea'); // getと違ってこちらはセレクタとしてIDを指定する
      
  • tinymce.removeにエディタのインスタンスを直接与える
     let editor = tinymce.get('textarea');
     tinymce.remove(editor);  // この例は意味ない
     

入力内容の取り出し

DOMとして取得できるが、ここではサーバーへ送信したりするための方法なので文字列(つまりパーシャルHTML)の取得方法。

  let html = tinymce.get('textarea').getContent();  // これで<p>入力したよ。</p>みたいなのが取得できる。

内容設定

  • textareaにあらかじめgetContent()で取り出したパーシャルHTMLを埋め込む。
  • エディタのsetContent(パーシャルHTML)メソッドを呼ぶ。

ここまでわかると、後は、取り出しタイミングさえ得られればAJAXでサーバーへ入力内容を随時送信できる。

取り出しタイミングは、サーバーとの通信が遅ければblur一択だろうが、そうでなければ、エディターのchangeイベント(エディターがアンドゥポイント生成後に発火)、undoイベント(ユーザーがアンドゥを呼んだ後に発火)、redoイベント(ユーザーがリドゥした後に発火)の3イベントを見張るのが良いと思う。

どのイベントでも同じサーバーへの内容送信を行うのだから、tinymce.initの引数で与えれば良い。

tinymce.init({selector: 'textarea',
              init_instance_callback: (editor) => {
                editor.on('change', (e) => {  // ドキュメントではChangeのように大文字始まりで書いてあるが、小文字始まりでOK。大文字始まりでどうかは試していない。以下同様。
                  sendContent(editor.getContent()); // sendContentは自前の送信メソッド
                });
                editor.on('undo', (e) => {
                  sendContent(editor.getContent());
                });
                editor.on('redo', (e) => {
                  sendContent(editor.getContent());
                });
               }
              });

2003|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|05|06|07|08|09|10|11|12|

ジェズイットを見習え