TopMovable TypeJavaScript > Movable Type 4.1/MTOS のネイティブタグで dTree を実装する
2007年12月20日

Movable Type 4.1/MTOS のネイティブタグで dTree を実装する

Posted at December 20,2007 1:55 AM
Category:[JavaScript, カテゴリー]
Tag:[, , ]

Movable Type 4.1/MTOS で変数の算術演算子と配列およびハッシュが実装されたことで、PHPあるいはJavaScriptとの組み合わせが必要だった処理が、ネイティブなタグのみで実装可能になりました。

全てのコードについて移植が可能であるかどうかは不明ですが、どの程度の威力があるか検証してみたかったので、サンプルとして、以前紹介した dTree のカスタマイズについてテンプレートタグで実装してみました。

1.dTree について

機能や設定方法は下記の記事を参照願います(実際にご利用になる場合、この記事の4項までの設定が必要です)。

dTree によるサブカテゴリーリスト for Movable Type

で、元記事で紹介したPHP版のスクリプトは下記の通りです(若干直しました)。

<script type="text/javascript">
d = new dTree('d');
d.config.useCookies=false;
d.add(0, -1,'Categories','javascript: void(0);');
<?php $cat_number = 0; $level = 0; $tree = array(); ?>
<MTTopLevelCategories>
<?php $tree[$level] = ++$cat_number; if(!$level) { ?>
    d.add(<?php echo $cat_number ?>, 0,'<$MTCategoryLabel encode_php="1"$>','<MTIfNonZero tag="MTCategoryCount"><$MTCategoryArchiveLink$><MTElse>javascript: void(0);</MTElse></MTIfNonZero>');
<?php } else { ?>
    d.add(<?php echo $cat_number ?>, <?php echo $tree[$level - 1] ?>,'<$MTCategoryLabel encode_php="1"$>','<MTIfNonZero tag="MTCategoryCount"><$MTCategoryArchiveLink$><MTElse>javascript: void(0);</MTElse></MTIfNonZero>');
<?php } $level++; ?>
<MTSubCatsRecurse max_depth="3">
<?php $level--; ?>
</MTTopLevelCategories>
document.write(d);
</script>
<p style="text-align:center"><a href="javascript: d.openAll();">open all</a> | <a href="javascript: d.closeAll();">close all</a></p>

再掲になりますが、dTree によるサブカテゴリーリストの完成イメージは次の通りです。

dTree によるサブカテゴリーリスト

この表示を行うための JavaScript は次の内容になっています(上記のPHPスクリプトから生成されたものです)。

<script type="text/javascript">
d = new dTree('d');
d.config.useCookies=false;
d.add(0, -1,'Categories','javascript: void(0);');
d.add(1, 0,'test1','http://.../test/');
d.add(2, 1,'test1-1','http://.../test/test11/');
d.add(3, 2,'test1-1-1','http://.../test/test11/test111/');
d.add(4, 2,'test1-1-2','http://.../test/test11/test112/');
d.add(5, 1,'test1-2','http://.../test/test12/');
d.add(6, 5,'test1-2-1','http://.../test/test12/test121/');
d.add(7, 5,'test1-2-2','http://.../test/test12/test122/');
d.add(8, 0,'test2','http://.../test2/');
d.add(9, 8,'test2-1','http://.../test2/test21/');
document.write(d);
</script>
<p style="text-align:center"><a href="javascript: d.openAll();">open all</a> | <a href="javascript: d.closeAll();">close all</a></p>

スクリーンショットと JavaScript(のカテゴリー)の対応はなんとなくお分かりになると思いますが、

d.add(...) 

の行で、カテゴリー部分を表示させています。

本エントリーでは、Movable Type のネイティブタグのみで、このカテゴリーを表示する部分の JavaScript を生成します。

2.dTree のカテゴリー表示部分のフォーマット

先程も簡単に紹介しましたが、JavaScript でカテゴリーを表示する部分は add 関数がキモとなっており、関数のパラメータは、

d.add([*1],[*2],[カテゴリー名],[カテゴリーのURL *3]);
*1:カテゴリーに一意に割り当てられたdTree用のカテゴリー番号
*2:そのカテゴリーが属する親カテゴリーの番号
"0"はdTreeのルートに属する場合(=最上位のカテゴリー)
*3:dTreeの生成するa要素のhref属性になります。

となっています。

上記の add 関数部分を、サブカテゴリーリストを出力するサブテンプレートを応用して作成します。以下、add 関数の各パラメータをどのようなロジックで作成するかという解説を交えながら、ネイティブなテンプレートを組み立てていきます。

3.各パラメータ用のデータ生成方法

3.1 第1パラメータ用のデータ生成

第1パラメータはカテゴリーに番号を順に付与していけば良いだけので、リスト1のように、

リスト1

<$mt:setvar name="cat_number" value="1"$>
<MTTopLevelCategories>
  <$mt:setvar name="cat_number" op="++"$>
  d.add(<$mt:getvar name="cat_number"$>,~略~);
  <$MTSubCatsRecurse$>
</MTTopLevelCategories>

とすれば良いことが分かります。

1行目でカテゴリー番号保持用の変数(cat_number)を1で初期化し、MTTopLevelCategories タグのループ内でインクリメントしていきます。
そしてインクリメント後に add 関数の第1パラメータに表示させればOKです。

3.2 第2パラメータ用のデータ生成

第2パラメータの、自カテゴリーの属する親カテゴリー番号を算出する方法は色々なアプローチがあると思いますが、ここでの方法は、まず算出に必要なデータとして、現在処理されているカテゴリーの階層をインデックスとした自カテゴリー番号を、配列の変数として保持します。

「カテゴリーの階層」は、親カテゴリーの階層は0、子カテゴリーの階層は1、孫カテゴリーの階層は2…、という具合に、数値で表すこととします。

「カテゴリーの階層をインデックスとした自カテゴリー番号を、配列の変数として保持」とは、例えば一番最初の「カテゴリー1」を処理している時、このカテゴリーはルート階層(数値で表すと0)に属するので、

tree[0]=1

という変数を作成することを指しています。左辺の変数 tree のインデックス0が階層の番号を示し、右辺の1がカテゴリー番号を示します。

「カテゴリー2」を処理している時、このカテゴリーは親カテゴリー(数値で表すと1)に属するカテゴリーなので、

tree[1]=2

という変数を作成します。

この規則によって、各カテゴリーを処理する時には、刻々と内容が書き換わる、次のような配列が作成されます。

カテゴリー1の処理中:tree[0]=1
カテゴリー2の処理中:tree[1]=2
カテゴリー3の処理中:tree[2]=3
カテゴリー4の処理中:tree[2]=4
カテゴリー5の処理中:tree[1]=5
カテゴリー6の処理中:tree[2]=6
カテゴリー7の処理中:tree[2]=7
カテゴリー8の処理中:tree[0]=8
カテゴリー9の処理中:tree[1]=9

少し話が難しくなりますが、このデータは次回の繰り返し処理で利用するためのものです。つまり、カテゴリー1の処理中に作成された、一番最初の、

tree[0]=1

は(MTTopLevelCategories の)繰り返し処理の中でそのまま保持されており、次のカテゴリー2の処理の時に利用される、ということだけをとりあえず覚えていてください。

前置きが長くなりましたが、上記のデータを作成するサブテンプレートは、リスト2のようになります(青色はリスト1からの追加部分)。

リスト2

<$mt:setvar name="cat_number" value="1"$>
<$mt:setvar name="level" value="1"$>
<MTTopLevelCategories>
  <$mt:setvar name="cat_number" op="++"$>
  <$mt:setvar name="tree[$level]" value="$cat_number"$>
  d.add(<$mt:getvar name="cat_number"$>,~略~);
  <$MTSubCatsRecurse$>
  <$mt:setvar name="level" op="++"$>
  <$MTSubCatsRecurse$>
  <$mt:setvar name="level" op="--"$>
</MTTopLevelCategories>

2行目で配列インデックス用の変数levelを初期化し、5行目で、処理中のカテゴリー番号を、現在の階層をインデックスとした配列データに保持します。

階層の数値の増減は、MTSubCatsRecurse の直前と直後で操作しています。

プログラミングに不慣れな方には分かりにくいのですが、MTSubCatsRecurseはいわゆる再帰処理を行うためのタグで、現在処理しているカテゴリーに子カテゴリーが存在する場合、MTSubCatsRecurse の内容を取り出し、 MTTopLevelCategories の中で処理します。

つまり MTSubCatsRecurse は次の階層を処理するための再帰データとなるので、その直前で変数 level をインクリメントすることで、階層用のデータがインクリメントされます。

また、MTSubCatsRecurse の直後でデクリメントすれば、階層の数値を親カテゴリーの階層に戻せます。
さらに MTSubCatsRecurse の中に孫カテゴリーデータが存在すれば、変数 level はさらにインクリメントされることになります。

これでdTreeに必要なデータが揃いましたので、あとは子カテゴリーが属する親カテゴリーのカテゴリー番号を求めるだけです。
これは、現在処理されているデータの階層からデクリメントした配列の値、つまり自カテゴリーの上位の階層のカテゴリー番号を取得すればいい訳です。

言い換えると、例えば2行目の、

tree[1]=2

の親カテゴリー番号を求める場合、上位の階層は

tree[0]

であり、その中に親のカテゴリー番号が設定されているので、配列のインデックスをデクリメント(-1)、つまり、

tree[1-1]

とすれば、tree[0] が求まります。あとはそこに設定されているカテゴリー番号1を取得すれば良い訳です。

また、4行目の

tree[2]=4

の親カテゴリーを求める場合、上位の階層は

tree[1]

となり、その中にカテゴリー番号が設定されているので、インデックスをデクリメント(-1)、つまり

tree[2-1]

とすれば、tree[1] が求まるので、あとはそこに設定されているカテゴリー番号2を取得すれば良い訳です。

話をまとめると、リスト3のようになります(青色はリスト2からの追加部分)。

リスト3

<$mt:setvar name="cat_number" value="1"$>
<$mt:setvar name="level" value="1"$>
<MTTopLevelCategories>
  <$mt:setvar name="cat_number" op="++"$>
  <$mt:setvar name="tree[$level]" value="$cat_number"$>
  <mt:if name="level" eq="1">
    d.add(<$mt:getvar name="cat_number"$>, 0,'<$MTCategoryLabel escape="js"$>','<MTIfNonZero tag="MTCategoryCount"><$MTCategoryArchiveLink$><MTElse>javascript: void(0);</MTElse></MTIfNonZero>');
  <mt:else>
    d.add(<$mt:getvar name="cat_number"$>, <$mt:setvar name="tmp" value="$level"$><$mt:setvar name="tmp" op="--"$><$mt:getvar name="tree[$tmp]"$>,'<$MTCategoryLabel escape="js"$>','<MTIfNonZero tag="MTCategoryCount"><$MTCategoryArchiveLink$><MTElse>javascript: void(0);</MTElse></MTIfNonZero>');
  </mt:if>
  <$mt:setvar name="level" op="++"$>
  <$MTSubCatsRecurse$>
  <$mt:setvar name="level" op="--"$>
</MTTopLevelCategories>

追加した6~10行目のうち、9行目が該当します。
第2パラメータの値に配列変数treeのデータを表示しています。

6行目の MTIf で処理を振り分けている理由ですが、親カテゴリーを処理している場合、さらに上位の階層(つまり dTree のルート階層)データを取得しようとしますが、これまでの処理では設定されていないデータなので、エラーを避けるため、その場合のみ、7行目で第2パラメータに固定で0を設定するようにしています。

3.3 第3パラメータ用のデータ生成

第3パラメータのカテゴリー名には、<$MTCategoryLabel escape="js"$> を記述するだけです。なお、JavaScript として正常に動作するよう、escape モディファイアに "js" を指定します。

3.4 第4パラメータ用のデータ生成

第4パラメータには、リスト4のようにカテゴリーのリンク、

リスト4

<MTIfNonZero tag="MTCategoryCount">
<$MTCategoryArchiveLink$>
<MTElse>
javascript: void(0);
</MTElse>
</MTIfNonZero>

を設定します。

カテゴリーにブログ記事が1件以上投稿されている場合は、カテゴリーアーカイブへのリンクを設定し、投稿されていなければリンクの代わりに "javascript: void(0);" を設定し、リンクをクリックしてもページ遷移が発生しないようにしています。

最後に、第1パラメータと第2パラメータに表示される値をデクリメントします(青色はリスト3からの追加部分)。

リスト5

<$mt:setvar name="cat_number" value="1"$>
<$mt:setvar name="level" value="1"$>
<MTTopLevelCategories>
  <$mt:setvar name="cat_number" op="++"$>
  <$mt:setvar name="tree[$level]" value="$cat_number"$>
  <mt:if name="level" eq="1">
    d.add(<$mt:getvar name="cat_number" op="--"$>, 0,'<$MTCategoryLabel escape="html"$>','<MTIfNonZero tag="MTCategoryCount"><$MTCategoryArchiveLink$><MTElse>javascript: void(0);</MTElse></MTIfNonZero>');
  <mt:else>
    d.add(<$mt:getvar name="cat_number" op="--"$>, <$mt:setvar name="tmp" value="$level"$><$mt:setvar name="tmp" op="--"$><$mt:getvar name="tree[$tmp]" op="--"$>,'<$MTCategoryLabel escape="html"$>','<MTIfNonZero tag="MTCategoryCount"><$MTCategoryArchiveLink$><MTElse>javascript: void(0);</MTElse></MTIfNonZero>');
  </mt:if>
  <$mt:setvar name="level" op="++"$>
  <$MTSubCatsRecurse$>
  <$mt:setvar name="level" op="--"$>
</MTTopLevelCategories>

これは変数cat_numberと変数levelの初期値を1にしているため、デクリメントしないと下のように、カテゴリー番号が2から開始されるためです。

d.add(2, 0,'test1','http://.../test/');
d.add(3, 2,'test1-1','http://.../test/test11/');
d.add(4, 3,'test1-1-1','http://.../test/test11/test111/');
d.add(5, 3,'test1-1-2','http://.../test/test11/test112/');
d.add(6, 2,'test1-2','http://.../test/test12/');
d.add(7, 6,'test1-2-1','http://.../test/test12/test121/');
d.add(8, 6,'test1-2-2','http://.../test/test12/test122/');
d.add(9, 0,'test2','http://.../test2/');
d.add(10, 9,'test2-1','http://.../test2/test21/');

変数cat_numberと変数levelの初期値を1にしているのは、初期値0の場合にリスト系のテンプレートタグで正常にインクリメントされない不具合を避けるためです。

これにdTree用の前後のスクリプトを加えれば完成です(青色はリスト5からの追加部分)。

リスト6

<script type="text/javascript">
d = new dTree('d');
d.config.useCookies=false;
d.add(0, -1,'Categories','javascript: void(0);');
<$mt:setvar name="cat_number" value="1"$>
<$mt:setvar name="level" value="1"$>
<MTTopLevelCategories>
<$mt:setvar name="cat_number" op="++"$>
<$mt:setvar name="tree[$level]" value="$cat_number"$>
<mt:if name="level" eq="1">
  d.add(<$mt:getvar name="cat_number" op="--"$>, 0,'<$MTCategoryLabel escape="html"$>','<MTIfNonZero tag="MTCategoryCount"><$MTCategoryArchiveLink$><MTElse>javascript: void(0);</MTElse></MTIfNonZero>');
<mt:else>
  d.add(<$mt:getvar name="cat_number" op="--"$>, <$mt:setvar name="tmp" value="$level"$><$mt:setvar name="tmp" op="--"$><$mt:getvar name="tree[$tmp]" op="--"$>,'<$MTCategoryLabel escape="html"$>','<MTIfNonZero tag="MTCategoryCount"><$MTCategoryArchiveLink$><MTElse>javascript: void(0);</MTElse></MTIfNonZero>');
</mt:if>
<$mt:setvar name="level" op="++"$>
<$MTSubCatsRecurse$>
<$mt:setvar name="level" op="--"$>
</MTTopLevelCategories>
document.write(d);
</script>
<p style="text-align:center"><a href="javascript: d.openAll();">open all</a> | <a href="javascript: d.closeAll();">close all</a></p>

よりエレガントな実装があると思いますが、その点はご容赦ください。

関連記事:dtree のサブカテゴリーリストにブログ記事タイトルを表示する for Movable Type

Posted by yujiro
関連記事
人気エントリー
トラックバックURL


コメント

MTを始めたばかりで、こちらのサイトや書籍を参考にさせていただいております。
ブログの作成で大変助かっております。

1つご質問があるのですが、
今回紹介していただいているdTree によるサブカテゴリーリストに
各カテゴリ毎の記事数を表示したいのですが可能でしょうか。
この場合、<$MTCategoryCount$>は使えないのかなと思い悩んでおります。

できれば対応方法をご教授いただければ幸いです。

よろしくお願いします。

[1] Posted by backpacker Author Profile Page : March 24, 2008 12:12 AM

>backpackerさん
こんばんは。
ご返事遅くなりすいません。
ご質問の件ですが、下記で表示されます。

<script type="text/javascript">
d = new dTree('d');
d.config.useCookies=false;
d.add(0, -1,'Categories','javascript: void(0);');
<$mt:setvar name="cat_number" value="1"$>
<$mt:setvar name="level" value="1"$>
<MTTopLevelCategories>
<$mt:setvar name="cat_number" op="++"$>
<$mt:setvar name="tree[$level]" value="$cat_number"$>
<mt:if name="level" eq="1">
  d.add(<$mt:getvar name="cat_number" op="--"$>, 0,'<$MTCategoryLabel escape="html"$> [<$MTCategoryCount$>]','<MTIfNonZero tag="MTCategoryCount"><$MTCategoryArchiveLink$><MTElse>javascript: void(0);</MTElse></MTIfNonZero>');
<mt:else>
  d.add(<$mt:getvar name="cat_number" op="--"$>, <$mt:setvar name="tmp" value="$level"$><$mt:setvar name="tmp" op="--"$><$mt:getvar name="tree[$tmp]" op="--"$>,'<$MTCategoryLabel escape="html"$>  [<$MTCategoryCount$>]','<MTIfNonZero tag="MTCategoryCount"><$MTCategoryArchiveLink$><MTElse>javascript: void(0);</MTElse></MTIfNonZero>');
</mt:if>
<$mt:setvar name="level" op="++"$>
<$MTSubCatsRecurse$>
<$mt:setvar name="level" op="--"$>
</MTTopLevelCategories>
document.write(d);
</script>
<p style="text-align:center"><a href="javascript: d.openAll();">open all</a> | <a href="javascript: d.closeAll();">close all</a></p>

それではよろしくお願い致します。

[2] Posted by yujiro Author Profile Page : March 31, 2008 1:19 AM

お忙しいところコードまで教えていただきありがとうございます!
カテゴリ毎の記事数を表示することができました!

本当にありがとうございました。

[3] Posted by backpacker Author Profile Page : March 31, 2008 10:53 AM

>backpackerさん
こんにちは。
ご連絡ありがとうございました。
うまくできたようで良かったです。
ではでは!

[4] Posted by yujiro Author Profile Page : April 4, 2008 3:02 PM
コメントする

*必須



お知らせ:2008年5月現在、多忙のため、7月頃までコメントを速やかに回答できない状態が続きます。ご質問の内容によっては回答が7月以降になる可能性がありますので、予めご了承ください。

太字 イタリック アンダーライン ハイパーリンク 引用

コメント投稿後にScript Errorや500エラーが表示された場合は、すぐに再送信せず、ブラウザの「戻る」ボタンで一旦エントリーのページに戻り(プレビュー画面で投稿した場合は、投稿内容をマウスコピーしてからエントリーのページに戻り)、ブラウザをリロードして投稿コメントが反映されていることを確認してください。

コメント欄に(X)HTMLタグやMTタグを記述される場合、「<」は「&lt;」、「>」は「&gt;」と入力してください。例えば「<$MTBlogURL$>」は「&lt;$MTBlogURL$&gt;」となります(全て半角文字)

Now loading...
Entries of this Category
QRcode

現在停止中です
携帯電話からこのQRcodeを撮影することで携帯用URLを取得することができます

URI for cellular phones
ギターに入った猫
Styles
Font Size
Default
For defective color vision
Gray Scale
RGB Color
Search this site

このブログをメールで購読する by:FeedBurner

loading ...
BlogPeople
Now loading...
Syndicate this site
FeedBurner(RSS1.0/RSS2.0/Atom)
Counter
これまでのアクセス
クリエイティブ・コモンズ・ライセンス
Powered by
Movable Type 4.1
 
List Me!