PowerCMS™

PowerCMS ブログ

ホーム > PowerCMS ブログ > スニペット・カスタムフィールドでカスタムフィールドをタブグループにまとめる

2014年06月13日

スニペット・カスタムフィールドでカスタムフィールドをタブグループにまとめる

PowerCMS に同梱されているスニペットフィールドを使うと、任意の UI でカスタムフィールドを作ることが可能です。

PowerCMS ユーザーガイドに掲載されているシンプルな管理画面 UI の作成から、MT タグや JavaScript を活用した高機能な管理画面 UI 作成まで、カスタマイズ次第であらゆる管理画面 UI を作ることができます。

今回はスニペットカスタムフィールドを利用して、任意のカスタムフィールドをタブでグループ化するカスタマイズ Tips を紹介します。

本記事で紹介するサンプルは、PowerCMS 4.03 にて動作確認をしています。

完成図

  • タブ1を表示した時のカスタムフィールドの状態
  • タブ2を表示した時のカスタムフィールドの状態
  • タブ3を表示した時のカスタムフィールドの状態

上記の完成図にするためのスニペット・カスタムフィールドのサンプルが下記になります。

スニペット・カスタムフィールドの設定

タブグループ化するための、記事のカスタムフィールドが複数あることを前提としています。

上記の完成図では、テキスト、チェックボックス、テキスト(複数行)、ラジオボタン、画像のカスタムフィールドが事前にあり、それをグループ化しました。

仮に、今回作成するカスタムフィールドは、ウェブサイトの記事のカスタムフィールドで、それぞれのカスタムフィールドのベースネームが下記であるとします。

  1. テキスト ( websiteentrytext )
  2. チェックボックス ( websiteentrycheckbox )
  3. テキスト複数行 ( websiteentrytextarea )
  4. ラジオボタン ( websiteentryradio )
  5. 画像 ( websiteentryimage )

以下は、スニペット・カスタムフィールドで作成するカスタムフィールドの具体的な設定項目とその値です。

名前

カスタムフィールドグループ

任意の名前を指定してください。

説明

なし

任意の説明文を指定してください。

種類

スニペット

保存後に表示される既定値の設定は後述します。

オプション

websiteentrytext,websiteentrycheckbox___websiteentrytextarea,websiteentryradio___websiteentryimage

スニペット・カスタムフィールドでは、オプションに指定した値をパラメータとしてリクエストに含めることで、任意の値を保存できる仕組みです。

今回のサンプルは、オプションの項目を、本来の用途ではなく、タブグループをどのようにグループ化するかを記述するために使っています。

指定する値は、タブグループに利用するカスタムフィールドのベースネームで、「___」(アンダースコアが三つ)がタブの区切りで、「,」(カンマ)がベースネームの区切りになります。

また、PowerRevision プラグインでは、このオプション値をバックアップファイルとして生成する XML ファイル中のタグ名として利用する制約があるため、「___」(アンダースコアが三つ)の前後に空白などの XML の要素名として利用できない文字を含めることはできません。

上記の設定は、1つ目のタブに、websiteentrytextwebsiteentrycheckbox を表示し、2つ目のタブに、websiteentrytextareawebsiteentryradio を表示し、最後のタブに、ベースネームが websiteentryimage であるカスタムフィールドを表示するという設定になります。

ベースネーム

websiteentrycfgroups

任意のベースネームを指定してください。

テンプレートタグ

websiteentrycfgroups

任意のテンプレートタグを指定してください。

今回のサンプルでは、スニペット・カスタムフィールド自体には値を保存しないため、このタグを利用する機会はありません。

既定値

<div id="cfgroups"></div>

<script type="application/x-mt-js-template" id="cfgroups-tabs-tmpl">
    <div id="cfgroups-tabs">
    <ul>
    [# jQuery.each(tabs, function (i) { #]
        <li><a href="#cfgroups-tabs-[#= i + 1 #]">タブ[#= i + 1 #]</a></li>
    [# }) #]
    </ul>
    [# jQuery.each(tabs, function (i) { #]
    <div id="cfgroups-tabs-[#= i + 1 #]"></div>
    [# }) #]
    </div>
</script>

<script>
    jQuery(function ($) {
    'use strict';

    // 変数を宣言する
    var $me, $me_display_option, $cfgroups, options, tabs, html;

    // スニペット・カスタムフィールド自身の jQuery オブジェクトをキャッシュする
    $me = $('#customfield_<$mt:var name="basename" encode_js="1"$>-field');
    // スニペット・カスタムフィールド自身の表示オプションチェックボックスの jQuery オブジェクトをキャッシュする
    $me_display_option = $('#custom-prefs-customfield_<$mt:var name="basename" encode_js="1"$>');

    // div#cfgroups の jQuery オブジェクトをキャッシュする
    $cfgroups = $('#cfgroups');

    // オプションの値を変数に代入する
    options = '<$mt:var name="options" encode_js="1"$>';

    // オプションの値を配列に変換する
    tabs = $.map(options.split('___'), function (option) {
        return [option.split(/\s*,\s*/)];
    });

    // script#cfgroups-tabs-tmpl の innerHTML をテンプレートとして、テンプレートをビルドする
    // テンプレート内で利用する tabs という変数に、上記の tabs 変数をアサインしている
    html = Template.process('tabs', { tabs: tabs }, { tabs: $('#cfgroups-tabs-tmpl').html() });

    // スニペット・カスタムフィールド自身が表示されているかどうかを判定するための関数
    function isHidden ($me) {
        return $me.is(':hidden');
    }

    // flatten で利用するためのユーティリティ関数
    function identity (a) {
        return a;
    }

    // ネストされた配列(2階層まで)をフラットにする関数
    function flatten (arr) {
        return $.map(arr, identity);
    }

    // タブグループをレンダリングするための関数
    function render () {
        // div#cfgroups の innerHTML にテンプレートのビルド結果を反映する
        $cfgroups.html(html);

        // カスタムフィールドをタブグループの該当タブに移動する
        $.each(tabs, function (i) {
        var basenames = this;
        $.each(basenames, function () {
            var basename, $customfield;
            basename = this.valueOf();
            $customfield = $('#customfield_' + basename + '-field');
            // カスタムフィールドの見出し部分はソート不可にするため、
            // ソート対象になるクラス名を除去し、最低限のスタイル調整をする
            $customfield
            .find('.field-header')
                .removeClass('field-header')
                .css('padding', '5px 10px');
            // カスタムフィールドを該当のタブグループに移動する
            $customfield.appendTo('#cfgroups-tabs-' + (i + 1));
        });
        });

        // div#cfgroups-tabs をタブ化する
        $cfgroups.find('#cfgroups-tabs').tabs();
    }

    // カスタムフィールドを通常の位置に戻すための関数
    function restore () {
        $.each(flatten(tabs), function () {
        // タブグループ内のカスタムフィールドの jQuery オブジェクトを取得する
        var $field = $('#customfield_' + this + '-field');
        // カスタムフィードの見出し部分に、クラス名 .field-header を再設定し、ソート可能にする
        $field.children().first().addClass('field-header');
        // フィールドの並びの最後に移動する
        $field.appendTo('#sortable');
        });
    }

    // 自身の表示オプションが変更された時、HTML を組み立て直すためのイベントハンドラ
    $me_display_option.on('change', function () {
        if ($(this).is(':checked')) {
        // 表示オプションが ON になったら、タブグループを表示する
        render();
        }
        else {
        // 表示オプションが OFF になったら、タブグループから、本来の場所にカスタムフィールドを移動する
        restore();
        }
        return true;
    });

    // 自身が非表示であれば何もしない
    if (isHidden($me)) return;

    // 自身が非表示でなければタブグループを組み立てて表示する
    render();
    });
</script>

上記が、タブグループを実現するための、スニペット・カスタムフィールドの具体的なロジックになります。

冒頭の <div id="cfgroups"></div> は、JavaScript で生成した DOM を挿入するためのラッパー要素です。

次の、<script type="application/x-mt-js-template" id="cfgroups-tabs-tmpl"> ... </script> で囲まれた部分は、タブグループを描画する HTML の JavaScript テンプレートになります。

JavaScript テンプレートは、Movable Type の管理画面でも利用されている、Movable Type 標準の Template.js という JavaScript テンプレートエンジンを利用しています。

script 要素の type 属性にブラウザが理解できない Media タイプが指定された時、その内容を無視するという特徴を利用して、テンプレートの記述のために利用しています。
※ 本来は script 要素の type 属性に指定する Media タイプは、RFC にて定義された妥当な Media タイプを指定するべきですが、すでに広く使われている手法のため、今回はこの方法を採用しました。

その後の script 要素にて、具体的な処理内容を記述しています。

処理内容を大きく捉えると、共通で使う変数の初期化、ユーティリティ関数の定義、イベントハンドラの登録、メインの処理といった内容が記述されています。コメントをヒントにご確認ください。

jQuery の ready イベントが発火するまでは、通常のカスタムフィールドとして表示され、その要素自体をタブグループ内に移動するため、並び順や表示オプションの状態などはそのまま引き継がれます。(タブグルーブ内の並びはオプションの指定順によって変更します)また、非表示の時は何もしないようにしています。

本サンプルの利点は、スニペット・カスタムフィールド自身で UI を作り込むわけではないため、通常のカスタムフィールドの編集や追加(スニペット・カスタムフィールドのオプションの値を追加する必要はあります)の操作にて UI を変更できる点にあります。

以上、スニペット・カスタムフィールドのカスタマイズの一例をご紹介しました。

スニペット・カスタムフィールドは、管理画面 UI の柔軟なカスタマイズが可能ですので、ぜひご活用ください。

追記

投稿当初、オプション値タブでグループ化する範囲の区切り文字を「|」(バーティカルバー)にしておりましたが、PowerRevision との組み合わせで問題があることが確認されたため、記事中の「|」は、「___」(アンダースコアが三つ)に変更いたしました。


カテゴリー
設定・管理画面カスタマイズ

Recent Entries