MTAppJSONTable

JSON を値に持つ textarea を表形式の入力 UI(テーブル)に変換する jQuery プラグイン。行・列の追加/削除・並べ替え・セル結合に対応し、保存時に内容を JSON へ書き戻す。値は HTML エスケープして表示。

JSON を値に持つ textarea を、表形式の入力 UI(テーブル)に変換する jQuery プラグインです。各行・各列をフォームのセルとして編集でき、保存時に内容を JSON へ書き戻します。行・列の追加、削除、ドラッグ並べ替え、セル結合などに対応します。

構文

$(selector).MTAppJSONTable(options);

$.fn プラグイン(JSON を保持する textarea に対して呼び出します)です。

パラメータ(主要)

options {Object} — 以下のプロパティを持ちます(headerOrder は必須)。

プロパティ既定値説明
headerOrderArray[]必須。列(プロパティ)の並び順(例 ['title', 'url']
headerObjectnull列の表示名(例 { title: 'タイトル', url: 'URL' }
headerPositionstring'top'ヘッダー位置。'top'(行方向に追加)/ 'left'(列方向に追加)
captionstringnullテーブルのキャプション
footerbooleanfalsetrue でテーブルフッターを表示(headerPosition: 'top' 時)
itemsRootKeystring'items'JSON のルートキー({ "items": [...] }
itemsArraynull初期データ(textarea が空のとき使う)
inputTypestring | Object'textarea'セルの入力欄。'textarea' / 'input'、または列ごとに指定する Object(例 { title: 'input', body: 'textarea' }
editbooleantruefalse で閲覧専用(入力欄ではなくテキスト表示)
addbooleanfalsetrue で行/列の追加ボタンを表示
clearbooleantrue削除ボタンを表示(チェックした行/列を削除)
sortablebooleanfalsetrue で行のドラッグ並べ替えを有効化(headerPosition: 'top' 時)
cellMergebooleanfalsetrue でセル結合(colspan / rowspan)を有効化
optionButtonsArraynull追加ボタン定義 [{ classname, text }]
debugbooleanfalsetrue で元の textarea(生の JSON)も表示

リスティングモード・コールバック

選択 UI(チェックボックス/ラジオ)として使う listingCheckbox / listingCheckboxType / listingTargetKey / listingTargetEscape や、各操作のフック(cbAfterBuild, cbBeforeAdd, cbAfterAdd, cbBeforeClear, cbAfterSelectRow, cbAfterSelectColumn, cbBeforeSave, cbAfterSave など)も指定できます。

戻り値

{jQuery} — 対象要素(チェーン可能)。

保存される値

テーブルの編集内容を直列化した JSON 文字列が、元のフィールドへ保存されます。headerOrder で定義した各列をキーに持つオブジェクトの配列が、itemsRootKey(既定 items)配下に入ります(具体例は次の「使用例」を参照)。

使用例

// タイトルと URL の 2 列テーブル。行の追加・削除を許可
$('#customfield_links').MTAppJSONTable({
    header: { title: 'タイトル', url: 'URL' },
    headerOrder: ['title', 'url'],
    add: true
});

保存される JSON の例:

{ "items": [ { "title": "記事A", "url": "/a" }, { "title": "記事B", "url": "/b" } ] }

user.js での記述例

user.js(「デザイン → user.js を編集」)に書く場合は、mtappVars.screen_id で画面を判定して呼び出します。

(function ($) {
    if (typeof mtappVars !== 'object') return;
    if (mtappVars.screen_id === 'edit-entry') {
        $('#customfield_links').MTAppJSONTable({
            header: { title: 'タイトル', url: 'URL' },
            headerOrder: ['title', 'url'],
            add: true
        });
    }
})(jQuery);

応用: 特定の列のセルをリッチテキスト(TinyMCE)にする

inputTypetextarea にした列のセルを、コールバックの中で MT.EditorManagerMTAppApplyTinyMCE と同じ仕組み)にかけると、セル単位のリッチテキストエディタにできます。テーブル内のセルに装飾やリンクを入れたいときに使えます。

// 「本文」列のセル(textarea)を TinyMCE 化する
let richSeq = 0;
const applyRichToBodyCells = ($container) => {
    if (!(window.MT && MT.EditorManager)) {
        return; // エディタ基盤が無ければ何もしない
    }
    $container.find('textarea.jsontable-input[data-name="body"]').each(function () {
        if (this.id && tinymce.get(this.id)) {
            return; // 適用済みはスキップ
        }
        if (!this.id) {
            this.id = `jt-rich-body-${++richSeq}`; // EditorManager は id で要素を探すので id を付与
        }
        new MT.EditorManager(this.id, { format: 'richtext' });
    });
};

$('#customfield_table').MTAppJSONTable({
    header: { title: 'タイトル', body: '本文' },
    headerOrder: ['title', 'body'],
    inputType: { title: 'input', body: 'textarea' }, // 本文だけ textarea にする
    add: true,
    cellMerge: true,
    // 初回描画時と行追加時に「本文」セルを TinyMCE 化する
    cbAfterBuild: (e, $container) => applyRichToBodyCells($container),
    cbAfterAdd:   (e, $container) => applyRichToBodyCells($container),
    // 保存の直前に TinyMCE の内容を textarea へ書き戻す(JSONTable はその後に直列化する)
    cbBeforeSave: (e, $container) => {
        $container.find('textarea.jsontable-input[data-name="body"]').each(function () {
            const editor = tinymce.get(this.id);
            if (editor) {
                editor.save();
            }
        });
    }
});

ポイント:

  • cbAfterBuild / cbAfterAdd で対象列のセル(textarea.jsontable-input[data-name="..."])に id を付け、new MT.EditorManager(id, { format: 'richtext' }) でリッチ化します(行を追加したセルにも適用するため両方で呼びます)。
  • cbBeforeSave で、保存の直前に各エディタの save() を呼んで内容を textarea へ書き戻します。これをしないと TinyMCE で編集した内容が textarea に反映されないまま直列化されます。
  • 保存される値はその列の HTML(例 <p>…</p>)になります。再描画時は encodeHTML で安全に textarea へ入り、上のコールバックで TinyMCE を再適用するとリッチ表示に戻ります。
  • cellMerge: true と併用する場合、JSONTable は headerOrder のキー補完を行わないため、初期データの各 item に全列のキー(この例では titlebody)を必ず含めてください。列を増やした場合は、過去に保存済みのデータにも新しい列のキーが必要です(無いセルは描画されず表が崩れます)。
  • セル内の TinyMCE はそのままだと縦に大きくなります。.mtapp-json-table .tox-tinymce { height: 230px; } のように高さを抑え、.mtapp-json-table td { vertical-align: top; } で上揃えにすると、隣の列の入力欄と並んで見やすくなります。

補足

  • headerOrder は必須です(指定が無いとアラートを出して中断します)。
  • 元の textarea は隠され、直後にテーブルが挿入されます。フォーム送信時(または MTAppJSONTableSave イベント発火時)に、テーブルの入力内容を JSON へ直列化して textarea に書き戻します。
  • 値は HTML エスケープして表示します(各セルの文字列値に encodeHTML を適用してから描画するため、保存値に HTML が含まれていてもそのまま実行されません)。header / caption などの設定値はそのまま使われます。
  • inputType を Object にすると列ごとに input / textarea を使い分けられます。
  • テンプレート描画には Movable Type / PowerCMS の Template エンジンを使用します。

関連

  • MTAppApplyTinyMCEtextarea をリッチテキストエディタ(TinyMCE)化する。
  • MTAppLineBreakField — 改行区切りのテキストを行ごとの入力欄にする。