2014年06月13日
スニペット・カスタムフィールドでカスタムフィールドをタブグループにまとめる
PowerCMS に同梱されているスニペットフィールドを使うと、任意の UI でカスタムフィールドを作ることが可能です。
PowerCMS ユーザーガイドに掲載されているシンプルな管理画面 UI の作成から、MT タグや JavaScript を活用した高機能な管理画面 UI 作成まで、カスタマイズ次第であらゆる管理画面 UI を作ることができます。
今回はスニペットカスタムフィールドを利用して、任意のカスタムフィールドをタブでグループ化するカスタマイズ Tips を紹介します。
本記事で紹介するサンプルは、PowerCMS 4.03 にて動作確認をしています。
完成図
上記の完成図にするためのスニペット・カスタムフィールドのサンプルが下記になります。
スニペット・カスタムフィールドの設定
タブグループ化するための、記事のカスタムフィールドが複数あることを前提としています。
上記の完成図では、テキスト、チェックボックス、テキスト(複数行)、ラジオボタン、画像のカスタムフィールドが事前にあり、それをグループ化しました。
仮に、今回作成するカスタムフィールドは、ウェブサイトの記事のカスタムフィールドで、それぞれのカスタムフィールドのベースネームが下記であるとします。
- テキスト ( websiteentrytext )
- チェックボックス ( websiteentrycheckbox )
- テキスト複数行 ( websiteentrytextarea )
- ラジオボタン ( websiteentryradio )
- 画像 ( websiteentryimage )
以下は、スニペット・カスタムフィールドで作成するカスタムフィールドの具体的な設定項目とその値です。
名前
カスタムフィールドグループ
任意の名前を指定してください。
説明
なし
任意の説明文を指定してください。
種類
スニペット
保存後に表示される既定値の設定は後述します。
オプション
websiteentrytext,websiteentrycheckbox___websiteentrytextarea,websiteentryradio___websiteentryimage
スニペット・カスタムフィールドでは、オプションに指定した値をパラメータとしてリクエストに含めることで、任意の値を保存できる仕組みです。
今回のサンプルは、オプションの項目を、本来の用途ではなく、タブグループをどのようにグループ化するかを記述するために使っています。
指定する値は、タブグループに利用するカスタムフィールドのベースネームで、「___
」(アンダースコアが三つ)がタブの区切りで、「,
」(カンマ)がベースネームの区切りになります。
また、PowerRevision プラグインでは、このオプション値をバックアップファイルとして生成する XML ファイル中のタグ名として利用する制約があるため、「___
」(アンダースコアが三つ)の前後に空白などの XML の要素名として利用できない文字を含めることはできません。
上記の設定は、1つ目のタブに、websiteentrytext
と websiteentrycheckbox
を表示し、2つ目のタブに、websiteentrytextarea
と websiteentryradio
を表示し、最後のタブに、ベースネームが 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 との組み合わせで問題があることが確認されたため、記事中の「|
」は、「___
」(アンダースコアが三つ)に変更いたしました。
- カテゴリー
- 設定・管理画面カスタマイズ
コメントを投稿する