PowerCMS™

【東京セミナー】6月6日(木) 企業Webリニューアル。最初に押えたい要件定義の進め方と、最新CMSで出来ること

PowerCMS ブログ

ホーム > PowerCMS ブログ > スニペット・カスタムフィールドでアイテム選択ダイアログを使用する

2013年11月21日

スニペット・カスタムフィールドでアイテム選択ダイアログを使用する

PowerCMS のカスタムフィールドProで追加されるスニペット・カスタムフィールド (通称スニペットフィールド) では、テンプレートタグにより HTML や JavaScript、CSS を組み合わせて自由度の高い入力欄を設計することができますが、その中ではローカルのファイル選択欄 (<input type=file>) を使用してファイルをアップロードし、テンプレートでアイテムとして扱うこともできます。ここで、ファイル選択欄ではなく Movable Type 標準の「アイテム」フィールドのように、モーダルダイアログから新規アイテムを作成して使用したり、既存のアイテムから選択したりするための実装方法を紹介します。

アイテム選択欄のサンプル画像です。

ここでは例として、システムオブジェクト「ブログ記事」に種類が「スニペット」のカスタムフィールドを作成し、その中で2つのアイテム選択ダイアログを使用します。まず必須項目を次に示す値で入力してカスタムフィールドを作成します。

システムオブジェクト
ブログ記事
種類
スニペット
オプション
customfield_e_snippet_1_o1,customfield_e_snippet_1_o2
既定値
(後述)
ベースネーム
e_snippet_1
テンプレートタグ
EntrySnippet1

カスタムフィールド編集画面のスクリーンショット

注意点として、Movable Type のアイテム選択ダイアログを流用するため、技術的な制約としてオプション欄にカンマ区切りで指定するキーは必ず「customfield_」で始まる必要があります。アイテム選択ダイアログを使用しない他の入力欄のキーは、通常のスニペット・カスタムフィールドと同様、自由にキーを付けることができます。

スニペット・カスタムフィールド編集画面で既定値欄に入力するテンプレート

2~3行目の配列変数「asset_opts」にはオプション欄で指定したキーのうち、アイテム選択ダイアログを使用するキーを追加していきます。ここでは2つのキーを追加していますが、5つでも、1つだけでも構いません。

なお、下記サンプルはアイテム選択ダイアログの内、「ファイル」選択ダイアログを作成する場合のサンプルです。例えば「画像」選択ダイアログを作成したい場合は、6-7行目でセットしている asset_type 変数および、asset_type_label 変数の値に、それぞれ、「image」「画像」といった値を指定してください。asset_type 変数に指定できる値は、6行目末尾の MTTemplateNote タグのコメントを参照ください。
<$MTSetVar name="undef(asset_opts)"$>
<$MTSetVar name="push(asset_opts)" value="customfield_e_snippet_1_o1"$>
<$MTSetVar name="push(asset_opts)" value="customfield_e_snippet_1_o2"$>
<MTLoop name="asset_opts">
  <MTIf name="__first__">
    <$MTVar name="asset_type" _default="file" setvar="__at"$><$MTTemplateNote value="file, audio, video, image"$>
    <$MTVar name="asset_type_label" _default="ファイル" setvar="__atl"$>
    <$MTVar name="thumbnail_width" _default="150" setvar="__w"$>
    <$MTVar name="thumbnail_height" _default="150" setvar="__h"$>
  </MTIf>

  <$MTVar name="__value__" cat="_original" setvar="_"$>
  <$MTVar name="$_" regex_replace='/\A(?:__snippet_upload_asset__(\d+)\z|.*)/','$1' setvar="asset_id"$>
<input type="hidden" name="<$MTVar name="_" escape="html"$>" value="<$MTVar name="$_" escape="html"$>">

  <$MTSetVar name="_cf_preview_html" value=""$>
  <MTIf name="asset_id" like='/\A[1-9]\d*\z/'>
    <MTAsset id="$asset_id" setvar="_cf_preview_html">
      <MTIf tag="AssetMIMEType" like="/\A(?:image\/|\z)/">
<a href="<$MTAssetURL$>" target="_blank" title="<$MTTrans phrase="View image" escape="html"$>"><img src="<$MTAssetThumbnailURL height="$__h" width="$__w"$>" alt=""></a>
      <MTElse>
<a href="<$MTAssetURL$>" target="_blank"><$MTAssetFileName escape="html"$></a>
      </MTIf>
    </MTAsset>
  <MTElse>
    <$MTVar name="$__value__"$>
  </MTIf>
  <MTUnless name="_cf_preview_html" like="/\S/">
    <$MTSetVar name="asset_id" value=""$>
  </MTUnless>

<input name="<$MTVar name="__value__"$>" id="<$MTVar name="__value__"$>" class="hidden" data-asset-chooser=true value="<$MTVar name="$__value__" escape="html"$>">

<div id="<$MTVar name="__value__"$>_preview" class="customfield_preview" data-preview-width="<$MTVar name="__w"$>" data-preview-height="<$MTVar name="__h"$>">
<$MTVar name="_cf_preview_html"$>
</div>

<div class="actions-bar" style="clear: none; text-align: center;">
  <div class="actions-bar-inner pkg actions">
    <a href="<$MTVar name="script_url"$>?__mode=list_asset&amp;_type=asset&amp;blog_id=<$MTVar name="blog_id"$>&amp;dialog_view=1&amp;filter=class&amp;filter_val=<$MTVar name="__at"$>&amp;require_type=<$MTVar name="__at"$>&amp;edit_field=<$MTVar name="__value__"$>&amp;asset_select=1"
        class="mt-open-dialog button"
    ><$MTTrans phrase="Choose [_1]" params="$__atl" escape="html"$></a>
  <MTUnless name="required">
    <a href="#" id="<$MTVar name="__value__"$>_remove_asset"
        class="<MTUnless name="asset_id">hidden </MTUnless>button"
    ><$MTTrans phrase="Remove [_1]" params="$__atl" escape="html"$></a>
  </MTUnless>
  </div>
</div>

  <MTSetVarBlock name="__selector" append="1"><MTIf name="__selector">, </MTIf>#<$MTVar name="__value__"$>_remove_asset</MTSetVarBlock>
  <MTIf name="__last__">
<script>
jQuery(function($) {
  $("<$MTVar name="__selector" escape="js"$>")
    .on("click", function() { return insertCustomFieldAsset("", $(this).attr("id").replace(/_remove_asset$/, "")) });

  window["insertCustomFieldAsset"] = function insertCustomFieldAsset(html, id, preview_html) {
    var $ = jQuery,
        $asset = $("#" + id),
        name = $asset.attr("name"),
        $original = $('input[name="' + name + '_original"]'),
        $remove, m;
    if ($asset.data("asset-chooser")) {
      $remove = $('input[name="' + name + '_remove"]');
      m = html.match(/^[<]form [m]t:asset-id="(\d+)"[^<]+<a href="([^"]*)/);
      if (m) {
        $asset.val(m[2]);
        $original.val("__snippet_upload_asset__" + m[1]);
        $remove.val("");
      } else {
        $asset.val("");
        $original.val();
        if ($remove.length > 0) {
          $remove.val("1");
        } else {
          $asset.after($('<input type="hidden" name="' + id + '_remove" value="1">'));
        }
      }
    } else { // Act as original insertCustomFieldAsset.
      $asset.val(html);
    }
    preview_html = preview_html || html || '';
    var $form     = $("<div>" + preview_html + "</div>").find("form:first"),
        $_preview = $("#" + id + "_preview"),
        preview_w, preview_h, w = 0, h = 0, img;
    if ($form.length !== 1) {
      preview_w = $_preview.data("preview-width") * 1;
      preview_h = $_preview.data("preview-height") * 1;
      // preview_html = preview_html.replace(/(<img\s(?![^>]*\swidth[\s=])(?![^>]*\sheight[\s=]))/, '$1 width="' + preview_w + '" height="' + preview_h + '"');
      m = preview_html.match(/ src="([^<">]+)/);
      if (m) {
        img = new Image();
        img.src = m[1];
        $(img).on("load", function() {
          w = img.width;
          h = img.height;
          if (w >= h) {
            h = "" + Math.round(h / w * preview_w);
            w = preview_w;
          } else {
            w = "" + Math.round(w / h * preview_h);
            h = preview_h;
          }
          $_preview.html(preview_html.replace(/(<img\s(?![^>]*\swidth[\s=])(?![^>]*\sheight[\s=]))/, '$1 width="' + w + '" height="' + h + '"'));
        });
      } else {
        $_preview.html(preview_html.replace(/(<img\s(?![^>]*\swidth[\s=])(?![^>]*\sheight[\s=]))/, '$1 width="' + preview_w + '"'));
      }
    } else {
      $form.find("a[href]").each(function() { $(this).attr("target", "_blank") });
      $_preview.html($form.html());
    }
    $("#" + id + "_remove_asset")[html ? "removeClass" : "addClass"]("hidden");
    return false;
  };
});
</script>
  </MTIf>
</MTLoop>

一つの編集画面に複数のスニペット・カスタムフィールドが必要で、そのそれぞれでアイテム選択ダイアログを使用する場合は、このテンプレートをウェブサイトやブログのテンプレートモジュールにまとめておき、スニペット・カスタムフィールドの既定値欄テンプレートから MTInclude タグでそのテンプレートモジュールを読み込むようにするなど、応用が可能です。

記事テンプレート例

基本的にはスニペット・カスタムフィールドでファイル選択欄によりアップロードしたアイテムを扱うのと同じように、カスタムフィールドの「テンプレートタグ」として設定したタグ名に「Asset」を繋げたブロックタグと key モディファイアの組み合わせでアイテムのコンテキストを得ることができます。(例: <MTEntrySnippet1Asset key="customfield_e_snippet_1_o1"> ... </MTEntrySnippet1Asset>)

<!DOCTYPE html><meta charset=<$MTPublishCharset$>><title><$MTEntryTitle escape="html"$></title>
<MTSetVarTemplate name="_tmpl_asset">
  <MTIf tag="AssetMIMEType" like="/\Aimage\//">
<img src="<$MTAssetURL escape="html"$>" alt="<$MTAssetDescription escape="html"$>" width=<$MTAssetProperty property="image_width"$> height=<$MTAssetProperty property="image_height"$>>
  <MTElse>
<a href="<$MTAssetURL escape="html"$>"><$MTAssetLabel escape="html"$> (<$MTAssetProperty property="file_size" escape="html"$>)</a>
  </MTIf>
</MTSetVarTemplate>

<MTEntrySnippet1Asset key="customfield_e_snippet_1_o1">
<p><$MTVar name="_tmpl_asset"$>
</MTEntrySnippet1Asset>

<MTEntrySnippet1Asset key="customfield_e_snippet_1_o2">
<p><$MTVar name="_tmpl_asset"$>
</MTEntrySnippet1Asset>

2014年5月30日 追記

お客様よりいただいたお問い合わせにより、PowerCMS 3.2 系列ではこの方法でアイテム選択ダイアログを使用した場合に、記事編集画面から一度プレビュー画面に遷移したあと、[このブログ記事を編集する] ボタンを押して再び記事編集画面に戻ると、選択したアイテムの情報が不正な値に変更されてしまう問題が判明しました。(PowerCMS 3.23 現在。PowerCMS 4 以降では問題なく使用できます。) この問題の修正は次の PowerCMS 3.24 でリリースされる予定です。リリースまでの間、もし PowerCMS 3.2 系列でアイテム選択ダイアログを使用されたい場合は、弊社サポート窓口までお問い合わせください。プログラムの部分的な修正をご提供することも可能です。

また、何例かの運用を経て得られたフィードバックを反映し、上記既定値欄用のテンプレートを更新しました。主な変更点は次の通りです。

  • MT 6 の編集画面デザインに馴染むよう、アイテムの選択・削除のリンクをボタン表示に変更しました。
  • 画像アイテムを選択した直後に、編集画面上でプレビュー表示される画像を中央寄せで表示するようにしました。
  • アイテム選択ダイアログをひとつのスニペット・カスタムフィールド内で複数繰り返して使用する場合、編集画面上で選択済みの画像アイテムがプレビュー表示されますが、このサムネイル画像の幅や高さを個別に変更できるようにしました。

なお、この記事では便宜上、スニペット・カスタムフィールド編集画面の既定値欄にテンプレートを貼り付ける使い方を説明していますが、実際には2~3行目の配列変数「asset_opts」の初期化と追加をしている部分を削除して、テンプレート全体をウェブサイトのテンプレートモジュールなどに分離することをお薦めします。モジュール化することで、既定値欄には必要に応じて例えば:

...

<$MTSetVar name="undef(asset_opts)"$>
<$MTSetVar name="push(asset_opts)" value="customfield_e_snippet_1_o1"$>
<$MTInclude module="アイテム選択ダイアログのテンプレートモジュール名"$>

...

<$MTSetVar name="undef(asset_opts)"$>
<$MTSetVar name="push(asset_opts)" value="customfield_e_snippet_1_o2"$>
<$MTSetVar name="push(asset_opts)" value="customfield_e_snippet_1_o3"$>
<$MTInclude module="アイテム選択ダイアログのテンプレートモジュール名"$>

...

......のように、繰り返して複数の選択ダイアログを使用できます。

複数のアイテム選択欄を使用したサンプルです。


カテゴリー
テンプレート作成Tips

Recent Entries