Movable Type 7のBlockEditorに「画像+テキスト」のフィールドを追加する

先日の記事「Movable Type 7のBlockEditorに独自フィールドを追加する」で紹介したGoogleマップフィールドに続き、Web制作シーンでは必須とも言える「画像+テキスト」のフィールドを制作してみました。昨年の記事「Movable Typeプラグイン「Extend TinyMCE」の今後を考える」などで繰り返し書いてきた通り、WYSIWYGエディタ(リッチテキストエディタ)にはWebページの品質に関わる懸念を抱いていて、私がBlockEditorを拡張し「画像+テキスト」フィールドを作るのは自然な流れという印象がします。また、昨年から既に二度もブロック編集のような機能を業務で作成したことも制作の動機になりました。

実現する仕様

「画像+テキスト」のフィールドとは具体的に以下のような仕様です。

  • 画像の左、もしくは右にテキストが回り込むモジュールを提供する
  • 画像フィールド・テキストフィールドを用意し、誰でも簡単にモジュールが利用できる(操作を誤っても破綻しない)
  • 画像・画像の代替テキストが容易に設定できる

制作

Movable Type 7に標準で同梱されている「BlockEditor」プラグインに含まれる「image.js(/path/to/mt-static/plugins/BlockEditor/lib/js/fields/image.js)」に手を加えて先に記述した仕様を実現することにしました。

主な作業内容は以下の通りです。

  • アイコンの設定
  • create()にテキストエリアを追加
  • get_field_options()に画像位置の選択を追加し、不要なオプションは削除
  • get_data()をテキストエリアに対応させる
  • get_html()で出力したいHTMLのテンプレートを記述

フィールドを複数追加した場合、また同じフィールドに画像を複数配置する場合に備え、idname属性値の設定は慎重に行う必要がありました。また、標準ではオプション設定のname属性値がfield_option_から始まる必要があるようです。

テンプレートリテラルを使用

初めてBlockEditorに含まれるスクリプトを見た際、入力フィールドや出力したいHTMLを生成するコードに読みにくさを感じました。そこで今回はECMAScript 2015(ECMAScript 6)の「Template literal」を使用してみました。

例えば、出力したいHTMLは以下のように書くことができました。

const html = [
    `<div class="lytimage -image$">`,
    `<div class="lytimage__image">`,
    `<img src="${$('#' + self.id + '-url').val()}" data-asset-id="${$('#' + self.id).val()}" alt="${$('#' + self.id + '_option_alt').val()}">`,
    `</div>`,
    `<div class="lytimage__text">${$('#' + self.id + '-content').html()}</div>`,
    `</div>`,
];

return html.join('');

まだ改良の余地はありますが、jQueryでappend()を繰り返したり、+で連結を繰り返したりするよりは読みやすいのかなと感じました。ただ、Template literalはIE11が対応していません。IE11でも利用できるようにするには、同梱されているBlockEditorに含まれるコードのようになるのも致し方ないかという気もしています。

スタイルガイドを参照

先日のGoogleマップフィールドを制作する際はひとまず機能の実現を目標にコードを書いたのですが、今回は「MT7 スタイルガイド」を参照しつつ制作してみました。一貫性のあるデザインを実現することでユーザビリティの向上にも寄与すると考えられるため重要なことではないかと思います。また、良いデザインのCMSは利用していて愛着も沸いてきますね。

成果物

下記のように画像の設定ができ、テキストが入力できるフィールドが完成しました。テキストエリアはTinyMCEのインラインモードが利用できるようになっており、段落だけでなくリストやリンクが記述できるようになっています。TinyMCEのインラインモードはいくつかの編集機能しか提供しないため、品質に悪影響を及ぼす可能性は低いと判断しています。
画面キャプチャ:画像+テキストフィールドを表示した画面

<mt:ContentFieldValue>の出力結果は以下のようになりました。

<div class="lytimage -imageL">
  <div class="lytimage__image">
    <img src="http://mt7.localhost/images/lazor_garden_alivila.jpg" data-asset-id="3" alt="写真:ラソール ガーデン・アリビラ クリスティア教会">
  </div>
  <div class="lytimage__text">
    <ul>
      <li>リスト項目1</li>
      <li>リスト項目2</li>
    </ul>
    <p>写真はホテル日航アリビラ ヨミタンリゾート沖縄にある「ラソール ガーデン・アリビラ クリスティア教会」です。</p>
  </div>
</div>

制作しての気付き

エディタの起動

create()にテキストエリアとエディタの起動コードを記述しているのですが、エディタの起動処理は入力フィールドをreturnで返した後に実行する必要があります。フィールド追加時にイベントは発生していないようなので(monitorEvents(document.getElementById('content_data'));で確認)ひとまずsetTimeout()を使いましたが、良い方法を模索したいと考えています。(MutationObserver?)

2018年3月16日追記

Beta2よりフィールド追加時にfield_createdイベントが発生するようになりました。

画像のリサイズ

画像を設定する際、現在の所「画像の挿入オプション」が表示されません。リサイズした画像を設定してもらえるとは限らないので、記事の編集画面で画像を挿入する場合と同じように「画像の挿入オプション」が表示されてほしいと感じました。(編集してリサイズすることもできますが、元の画像が残らないので...。)フィードバックを送信してみます。

出力するHTMLにはdata-asset-idを入れているので、モディファイアで何とかすることも視野に入れています。

サンプルコード

GitHubにて提供しています。