CKEditorのダイアログ中のテキストをJSで置換する方法(試行錯誤の記録)

f:id:ryoutaku_jo:20190816020200p:plain

【結論】

・CKEditorのダイアログ中のテキストは、idが固定では無く、classは別のダイアログと共通化されているので、それらを使って文字の置換が困難

・ダイアログ(JavaScript)の生成にフックするdialogDefinition イベントにコールバックを設定し動的にカスタマイズする方法であれば実装可能

・ファイル一式をホストして、直接ファイルを書き換える方法でも実装できるかもしれない

【目次】

【本題】

結論(コードとbefore/after画像)

以下のコードで、画像の通りCKEditorのダイアログ中のテキストを置換できましたという話。

CKEDITOR.on('dialogDefinition', function (ev) { // eslint-disable-line no-undef
  var dialogName = ev.data.name;
  var dialogDefinition = ev.data.definition;

  if (dialogName === 'templates') {
    dialogDefinition.title = '画像配置パターン';
    var selectTplText = dialogDefinition.getContents('selectTpl').elements[0].children;
    selectTplText[0].html = '<span>画像配置パターンを選択してください。</span>';
    delete selectTplText[2];
  }
});

before

f:id:ryoutaku_jo:20190816004553p:plain

after

f:id:ryoutaku_jo:20190816004618p:plain

経緯:テンプレート機能のダイアログ中の不要なテキストを削除したい

CKEditorは、デフォルトで画像を均一幅で横並びする事が出来ません。

※以下の画像の様な配置 f:id:ryoutaku_jo:20190816010344p:plain

その為、画像を横並びに出来るにテンプレートを用意する事にしました。

テンプレート機能は完成したのですが、そのテンプレート機能を利用する際、以下の様なダイアログが表示されます。

f:id:ryoutaku_jo:20190816004553p:plain

これは、CKEditorのテンプレート機能にもともと入っている日本語ファイルから読み取られた文言です。

そもそもテンプレート機能は、全体の文章構成の雛形を出力する事を目的とした機能の様なので、現在入力中の内容と置換するオプションがデフォルトでチェックされていました。

しかし、今回は文章の中の一部分で利用する事を想定したテンプレートなので、全体と置換されてしまうと困ります。

そこで、置換オプションのチェックは外す事にしました。

※ちなみに置換オプションのデフォルトチェックを外す設定は以下の通り

templates_replaceContent: false

これでチェックを入れない限り、エディタの内容が置換されて消える事はありませんが、「現在のエディタの内容は失われます」という文言は、ユーザーに混乱を招く恐れがある為、削除する事にしました。

検証1(失敗):id/class指定でテキストを置換

まず初めに試みたのは、テキストのid(class)で該当箇所を特定して、

id/classが指定できれば、JSで置換出来ますし、:before擬似要素などを使えばCSSでも置換出来るでしょう。

しかし、これは出来ませんでした。

というのも、CKEditorのダイアログ中のテキストに適用されているidは固定では無く、classも別のダイアログと共有されているからです。

以下の様に、ページを更新したりすると、idが変わってしまい、使い物になりません・・・

f:id:ryoutaku_jo:20190816011638p:plain

f:id:ryoutaku_jo:20190816011648p:plain

検証2(失敗):公式リファレンスからダイアログのテキスト変更オプションを探す

公式リファレンスを片っ端から調査しましたが、ダイアログのテキストを変更するオプションが見当たりませんでした・・・

というかAPI関係はJS弱者の私には理解出来ない部分も多々あったので、もしかしたら上手いやり方があるかもしれません・・・

検証3(失敗):jQueryで文字列を検索して置換する

jQuery:containsを使えば、特定の文字列を持っている要素を取得出来そうだったので、試してみました。

しかし、イベント発火のタイミングが掴めず、上手いこと実装できませんでした・・・

検証4(失敗):日本語ファイルを上書きする

テンプレート機能のプラグインファイルを読み込んで、日本語ファイルを上書き出来ないか試しましたが、上手く行きませんでした・・・

ckeditor-releases/plugins/templates at master · ckeditor/ckeditor-releases · GitHub

以下は試したコードの一つ。

CKEDITOR.plugins.setLang("templates","ja",
    {
        selectPromptMsg:"エディターで使用するテンプレートを選択してください。\x3cbr\x3e(現在のエディタの内容は失われません!!!!!!!):",
    });

検証5(未実施):CDNやめてファイル一式をホストする

現在CDNで読み込んでますが、ファイル一式をホストして、直接ファイルを書き換える事で対応する手段も検討しました。

最終手段で考えていたので、もし他に打ち手が無ければ、これで対応していたかもしれません。

検証6(成功):コールバック設定して動的にカスタマイズ

ダイアログ(JavaScript)の生成にフックするdialogDefinition イベントにコールバックを設定し動的にカスタマイズする方法を試す事にしました。

CKEDITOR.on('dialogDefinition', function (ev) { // eslint-disable-line no-undef
  var dialogName = ev.data.name;
  var dialogDefinition = ev.data.definition;

  if (dialogName === 'templates') {
    console.log(dialogDefinition);
  }
});

ev.data.definitionにダイアログの定義データが入っていたので、デベロッパーツールで中身をしらみつぶしにチェックしていって、その値を置き換える事にしました。

f:id:ryoutaku_jo:20190816015739p:plain

そうして実装したコードが、初めに紹介したコードです。

CKEDITOR.on('dialogDefinition', function (ev) { // eslint-disable-line no-undef
  var dialogName = ev.data.name;
  var dialogDefinition = ev.data.definition;

  if (dialogName === 'templates') {
    dialogDefinition.title = '画像配置パターン';
    var selectTplText = dialogDefinition.getContents('selectTpl').elements[0].children;
    selectTplText[0].html = '<span>画像配置パターンを選択してください。</span>';
    delete selectTplText[2];
  }
});

これで、ダイアログのテキストの置き換えに成功しました!

f:id:ryoutaku_jo:20190816004618p:plain

参考情報

https://ckeditor.com/docs/ckeditor4/latest/index.html

ckeditor-releases/plugins/templates at master · ckeditor/ckeditor-releases · GitHub

CKEditorをカスタマイズする - Qiita

ckeditorのダイアログの項目を変えちゃおう(ckeditorカスタマイズ) | 増子良太のブログです

《今日の学習進捗(3年以内に10000時間に向けて)》

CEOから指摘頂いた箇所の修正が全て完了し、現在開発中の機能のフロント側の開発が一通り完了した。

なお、CKEditorで画像配置パターンを選択する際に表示されるダイアログの説明文を修正する作業が少してこづった。 画像配置パターンは、CKEditorのテンプレート機能を拡張して実装したのだが、ダイアログの説明文を変更するオプションが公式リファレンス上に見当たらなかった。 その為、直接cssかjsで文言を書き換える方法を試そうとしたが、該当箇所のidが固定ではなく、classも他のダイアログと共通化されていることから、id・classでの指定が出来なかった。

最終的に、ダイアログ(JavaScript )の生成をフックする dialogDefinition イベントにコールバックを設定して、ダイアログに渡される連想配列の値を直接書き換えることで、とりあえず文言の修正に成功した。 但し、jsを良く知らないまま見よう見まねで実装したので、これがベストの方法かというと正直自信は無い。 公式リファレンスもjsの知見が無いと理解が困難な箇所が多々あるので、もっと良い方法があったかもしれない。 動作には支障ないと思われるのと、これ以上私が調査しても時間が無駄になってしまうので、一先ずこの部分の作業を完了する。

画像アップロードのテストコードだけ追加して、後はCTOにレビューをお願いしようと考えている

学習開始からの期間 :251日
今日までの合計時間:2379h
一日あたりの平均学習時間:9.5h
今日までに到達すべき目標時間:2292h
目標との解離:87h
「10,000時間」まで、

残り・・・「7621時間!」