Movable Type 4.1/MTOS のネイティブタグで dTree を実装する
Movable Type 4.1/MTOS で変数の算術演算子と配列およびハッシュが実装されたことで、PHPあるいはJavaScriptとの組み合わせが必要だった処理が、ネイティブなタグのみで実装可能になりました。
全てのコードについて移植が可能であるかどうかは不明ですが、どの程度の威力があるか検証してみたかったので、サンプルとして、以前紹介した dTree のカスタマイズについてテンプレートタグで実装してみました。
1.dTree について
機能や設定方法は下記の記事を参照願います(実際にご利用になる場合、この記事の4項までの設定が必要です)。
で、元記事で紹介した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 によるサブカテゴリーリストの完成イメージは次の通りです。

この表示を行うための 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>
よりエレガントな実装があると思いますが、その点はご容赦ください。
コメント投稿フォームの「情報を保存する」のチェックを外した時の振る舞いを変更する
Movable Type 4 のコメント投稿画面にある、「ログイン情報を記憶」というチェックボックス(下のスクリーンショット一番下のチェックボックス)は、投稿者情報(名前・電子メール・URL)をクッキーを利用して保存し、次回の投稿時に投稿者情報の入力を不要にするためのものです。
チェックボックスにチェックをしておけば、コメント投稿時に投稿者情報がクッキーに保存されます。

逆に、このチェックを外すと、チェックを外した瞬間にクッキーから投稿者情報を消去する動作が実行されるのですが、同時に、入力フィールドに記入された投稿者情報まで消去されてしまいます(下)。

チェックを外す操作によるフォーム情報のクリアは、ユーザが意図しない動作のように思われます。
ということで、このエントリーでは、チェックを外しても投稿者情報を消去せず、クッキー情報のみ削除するカスタマイズを紹介します。
1.設定方法
ブログ管理画面より、「デザイン」→「テンプレート」を開き、一覧に表示された「JavaScript」のリンクをクリック。これは mt.js というコメントフォーム制御用の JavaScript です。

「テンプレートの内容」にある赤色の部分
:
function forgetMe (f) {
deleteCookie('mtcmtmail', '/', '');
deleteCookie('mtcmthome', '/', '');
deleteCookie('mtcmtauth', '/', '');
f.email.value = '';
f.author.value = '';
f.url.value = '';
}
:
を削除するか、赤色行の先頭に "//" をつけてコメントアウトします。
:
function forgetMe (f) {
deleteCookie('mtcmtmail', '/', '');
deleteCookie('mtcmthome', '/', '');
deleteCookie('mtcmtauth', '/', '');
// f.email.value = '';
// f.author.value = '';
// f.url.value = '';
}
:
編集後、「保存と再構築」をクリックしてください。
Lightbox JS/Litebox で BlogPet を背景画像の下に隠す
Lightbox JS / Litebox でブログパーツ BlogPet の Flash を PNG 背景画像の下に隠す方法です。
以前、「Lightbox JS でブログパーツ等の Flash を PNG 背景画像の下に隠す」という記事を書いたのですが、BlogPetのソースコードが変更されており、ご質問を頂きましたので再掲します。
1.BlogPet のスクリプトを取得する
BlogPet 表示用の script 要素の src 属性に記述されたURLをブラウザ(Firefox 推奨)に入力すると、下のようなスクリプトが表示されます。
(function() {
try {
request = encodeURIComponent(document.URL);
referrer = encodeURIComponent(document.referrer);
} catch (e) {
request = escape(document.URL);
referrer = escape(document.referrer);
}
document.write(
"<object id='usa.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' " +
"classid='clsid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' " +
"codebase='http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0' " +
"width='130' " +
"height='220'>" +
"<param name='allowScriptAccess' value='sameDomain' />" +
"<param name='movie' value='http://media.blogpet.net/5/8/243658.swf' />" +
"<param name='play' value='true' />" +
"<param name='loop' value='false' />" +
"<param name='menu' value='false' />" +
"<param name='quality' value='high' />" +
"<param name='bgcolor' value='#ffffff' />" +
"<param name='FlashVars' value='public_key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&domain=api.blogpet.net¤t_url=" + request + "' />" +
"<embed name='usa.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' " +
"type='application/x-shockwave-flash' " +
"pluginspage='http://www.macromedia.com/go/getflashplayer' " +
"width='130' " +
"height='220' " +
"allowScriptAccess='sameDomain' " +
"src='http://media.blogpet.net/5/8/243658.swf' " +
"play='true' " +
"loop='false' " +
"menu='false' " +
"quality='high' " +
"bgcolor='#ffffff' " +
"current_url='" + request + "'" +
"FlashVars='public_key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&domain=api.blogpet.net¤t_url=" + request + "' />" +
"</object><br />"
);
})();
document.write('<object id="site" classid="clsid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" width="130" height="100" align="middle"><param name="allowScriptAccess" value="always" /><param name="movie" value="http://kk.blogtoy.net/swf/48.swf" /><param name="play" value="true" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="high" /><param name="FlashVars" value="domain=kk.blogtoy.net&source=/swf/13.swf&onclick=/click/2/classic/8" /><embed src="http://kk.blogtoy.net/swf/48.swf" loop="false" menu="false" quality="high" bgcolor="#ffffff" width="130" height="100" name="site" align="middle" allowScriptAccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" FlashVars="domain=kk.blogtoy.net&source=/swf/13.swf&onclick=/click/2/classic/8" /></object>');
これを「ファイル」→「名前をつけてページを保存」を選択し、任意のファイル名(blogpet.txt 等)で保存します。
2.スクリプトの修正
保存したスクリプトを任意のエディタで開き、下記の青色部分を追加してください。注:計4ヶ所あります。
(function() {
try {
request = encodeURIComponent(document.URL);
referrer = encodeURIComponent(document.referrer);
} catch (e) {
request = escape(document.URL);
referrer = escape(document.referrer);
}
document.write(
"<object id='usa.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' " +
"classid='clsid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' " +
"codebase='http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0' " +
"width='130' " +
"height='220'>" +
"<param name='allowScriptAccess' value='sameDomain' />" +
"<param name='movie' value='http://media.blogpet.net/5/8/243658.swf' />" +
"<param name='play' value='true' />" +
"<param name='loop' value='false' />" +
"<param name='menu' value='false' />" +
"<param name='quality' value='high' />" +
"<param name='bgcolor' value='#ffffff' />" +
"<param name='wmode' value='transparent' />" +
"<param name='FlashVars' value='public_key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&domain=api.blogpet.net¤t_url=" + request + "' />" +
"<embed name='usa.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' " +
"type='application/x-shockwave-flash' " +
"pluginspage='http://www.macromedia.com/go/getflashplayer' " +
"width='130' " +
"height='220' " +
"allowScriptAccess='sameDomain' " +
"src='http://media.blogpet.net/5/8/243658.swf' " +
"play='true' " +
"loop='false' " +
"menu='false' " +
"quality='high' " +
"bgcolor='#ffffff' " +
"current_url='" + request + "'" +
"wmode='transparent' " +
"FlashVars='public_key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&domain=api.blogpet.net¤t_url=" + request + "' />" +
"</object><br />"
);
})();
document.write('<object id="site" classid="clsid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" width="130" height="100" align="middle"><param name="allowScriptAccess" value="always" /><param name="movie" value="http://kk.blogtoy.net/swf/48.swf" /><param name="play" value="true" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="high" /><param name="wmode" value="transparent" /><param name="FlashVars" value="domain=kk.blogtoy.net&source=/swf/13.swf&onclick=/click/2/classic/8" /><embed src="http://kk.blogtoy.net/swf/48.swf" loop="false" menu="false" quality="high" bgcolor="#ffffff" width="130" height="100" name="site" align="middle" allowScriptAccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" wmode="transparent" FlashVars="domain=kk.blogtoy.net&source=/swf/13.swf&onclick=/click/2/classic/8" /></object>');
3.スクリプトをブログに設定
BlogPet 表示用の script 要素の src 属性 charset 属性を削除し、代わりに2項の内容を追加します。なお、language 属性も非推奨なので削除しても良いでしょう。
変更前
<script language="JavaScript" type="text/javascript" src="http://www.blogpet.net/js/xxxxxxxxxxxxxxxxx.js" charset="UTF-8"></script>
変更後
<script type="text/javascript">
[2項の内容をここに入れる]
</script>
以上です。
これで、ページ上の LightBox JS/LItebox 画像を表示した時、BlogPet が背景画像の下に隠れればOKです。
CSS+JavaScript によるカラムレイアウト切り替え(cookieによる状態保持)
CSS+JavaScript によるカラムレイアウト切り替えでは基本的な切り替え方法を紹介しましたが、このエントリーでは cookie を用いてスタイルを保持する方法を紹介します。
前述の通り、前回までのカスタマイズではブラウザ上でページ遷移やリロードをするとスタイルが元に戻ってしまうという欠点があります。例えば配色や文字サイズを切り替えたらそのままのデザインで他のページも閲覧したいケースは少なくないと思いますので、このカスタマイズを併用されるとユーザビリティが向上するでしょう。
サンプルを用意しましたのでリロードを実施してみてください。
注:IEのリキッドレイアウト表示に不具合があるようですので、サンプルは固定レイアウトのみに限定させて頂いてます。
CSS+JavaScript によるカラムレイアウト切り替えのカスタマイズが終わっていることを前提にカスタマイズを説明します。
1.cookie 保持スクリプトの追加
状態を保持したいテンプレートの <head>~</head> へ下記を追加します。外部ファイルにしても構いません。
<script type="text/javascript">
<!--
function createCookie(name,value,days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
//-->
</script>
このスクリプトは QuirksMode:Cookies からの抜粋です。
2.スタイル切り替えスクリプトに cookie 保持起動の追加
CSS+JavaScript によるカラムレイアウト切り替えの1項のスクリプトに下記の青色部分 *1 を追加します。
<script type="text/javascript">
<!--
function changeColumn(id) {
var elements = document.getElementsByTagName('body');
document.getElementById('links-right-box').style.display = 'block';
document.getElementById('links-left-box').style.display = 'block';
if(id == '3'){
:
(中略)
:
}
createCookie('style', id, 365);
}
//-->
</script>
createCookie の引数には、cookie名・値(ここではカラムレイアウト)・有効期限(ここでは日単位)の順に設定します。有効期限が「365」であれば1年有効であることを示します。
3.ページ読み出し時の cookie 取得処理追加
状態保持をしたいテンプレートの最後の方(</html> の前)に下記を追加します。
<script type="text/javascript">
<!--
var id = readCookie('style');
if(id){
changeColumn(id);
}
//-->
</script>
*1:色覚障害等で色が識別できない場合は、サイト右上の「Styles」メニューにある Gray Scale をクリックしてください。IEではグレースケール表示され、青色部分が下線表示、赤色部分が二重下線で表示されます。Firefox/Opera ではカラー表示のままですが下線表示に切り替わります。なお設定の都合上、リンクとテキスト表示が判断できなくなりますので予めご容赦ください。
CSS+JavaScript によるカラムレイアウト切り替え
公開テンプレート(Movable Type/Serene Bach/sb/ FC2ブログ/Seesaaブログ)でカラムレイアウトをリアルタイムに切り替えるカスタマイズです。ここでは公開テンプレートをサンプルに説明していますが、同様の構造であればどのようなテンプレートでも実現可能です。
とりあえず、どのような動作になるかをサンプルでお試しください(中央上部のプルダウンメニューで操作できます)。
以前、類似の記事でスタイルシート切替や3カラム可変と3カラム固定を切り替えるをエントリーしていますが、これらはいずれもスタイルシートを新たに追加する必要がありました。つまり「スタイルシートを切り替える」というカスタマイズでした。
今回のカスタマイズでは、スタイルシートの追加や切り替えなしにレイアウトを切り替えることができます。
その理由は、現在公開しているテンプレートでは1つのスタイルシートに
- 3カラムリキッドレイアウト
- 3カラム固定レイアウト
- 2カラムリキッドレイアウト(右サイドバー)
- 2カラム固定レイアウト(右サイドバー)
- 2カラムリキッドレイアウト(左サイドバー)
- 2カラム固定レイアウト(左サイドバー)
- 1カラムリキッドレイアウト
- 1カラム固定レイアウト
の8種類のレイアウトをまとめて記述しています。各レイアウトは body 要素の class 属性に割り当てているので、この class 属性値(青色 *1)を書き換えることでレイアウトが切り替わります。
<body class="layout-three-column">
CSSには class 属性に対応するクラスセレクタが記述されています。例えば .layout-three-column では下記のような設定になっています(抜粋)。
body.layout-three-column {
margin-bottom: 20px;
}
.layout-three-column #box {
width: 850px;
}
.layout-three-column #content {
float: left;
width: 478px;
}
.layout-three-column #links-left-box,
.layout-three-column #links-right-box {
float: left;
width: 185px;
}
.layout-three-column #links-left,
.layout-three-column #links-right {
padding: 15px 15px 0 15px;
}
公開テンプレートでは、同様の設定を8種類全てのレイアウトについて記述しています。目新しいテクニックではありませんが、ページデザインを切り替えるには非常に有効な手法です。
つまり JavaScript で class 属性値を書き換えれば簡単にレイアウトを切り替えることが可能、という訳です。具体的には、HTML(テンプレート)に切替用のスクリプトとプルダウンメニューまたはリンクを書き加えるだけで済みます。
以下、このエントリーでは全レイアウトを表示するカスタマイズ方法を説明します。組み合わせによってはサイドバーを非表示にするような効果を出すこともできますので、それらについては追ってご紹介したいと思います。
1.スクリプトの追加
切り替えを実施したいテンプレートの <head>~</head> へ下記を追加します。外部ファイルにしても構いません。
<script type="text/javascript">
<!--
function changeColumn(id) {
var elements = document.getElementsByTagName('body');
document.getElementById('links-right-box').style.display = 'block';
document.getElementById('links-left-box').style.display = 'block';
if(id == '3'){
elements[0].setAttribute('class','layout-three-column');
elements[0].setAttribute('className','layout-three-column');
} else if(id == '3l') {
elements[0].setAttribute('class','layout-three-column-liquid');
elements[0].setAttribute('className','layout-three-column-liquid');
} else if(id == '2l') {
elements[0].setAttribute('class','layout-two-column-left');
elements[0].setAttribute('className','layout-two-column-left');
document.getElementById('links-right-box').style.display = 'none';
} else if(id == '2ll') {
elements[0].setAttribute('class','layout-two-column-liquid-left');
elements[0].setAttribute('className','layout-two-column-liquid-left');
document.getElementById('links-right-box').style.display = 'none';
} else if(id == '2r') {
elements[0].setAttribute('class','layout-two-column-right');
elements[0].setAttribute('className','layout-two-column-right');
document.getElementById('links-left-box').style.display = 'none';
} else if(id == '2rl') {
elements[0].setAttribute('class','layout-two-column-liquid-right');
elements[0].setAttribute('className','layout-two-column-liquid-right');
document.getElementById('links-left-box').style.display = 'none';
} else if(id == '1') {
elements[0].setAttribute('class','layout-one-column');
elements[0].setAttribute('className','layout-one-column');
document.getElementById('links-left-box').style.display = 'none';
document.getElementById('links-right-box').style.display = 'none';
} else if(id == '1l') {
elements[0].setAttribute('class','layout-one-column-liquid');
elements[0].setAttribute('className','layout-one-column-liquid');
document.getElementById('links-left-box').style.display = 'none';
document.getElementById('links-right-box').style.display = 'none';
}
}
//-->
</script>
2.切り替え用プルダウンメニューの追加
1項と同様、切り替えを実施したいテンプレートに下記のプルダウンメニュー(青色)を追加します。ここではカラム切り替えで非表示にならないよう、中央カラム上部に設定しています。
:
<!-- 中央カラム開始 -->
<div id="content">
<form id="cc">
<select name="select" onchange="changeColumn(this.form.select.value);">
<option value="3">3カラム</option>
<option value="3l">3カラムリキッド</option>
<option value="2l">2カラム(左)</option>
<option value="2ll">2カラム(左)リキッド</option>
<option value="2r">2カラム(右)</option>
<option value="2rl">2カラム(右)リキッド</option>
<option value="1">1カラム</option>
<option value="1l">1カラムリキッド</option>
</select>
</form>
<div class="blog">
:
リンクにする場合は下記のようになります(どこに配置するかは自己解決してください)
<ul>
<li><a href="javascript:void(0);" onclick="changeColumn('3')">3カラム</a></li>
<li><a href="javascript:void(0);" onclick="changeColumn('3l')">3カラムリキッド</a></li>
<li><a href="javascript:void(0);" onclick="changeColumn('2l')">2カラム(左)</a></li>
<li><a href="javascript:void(0);" onclick="changeColumn('2ll')">2カラム(左)リキッド</a></li>
<li><a href="javascript:void(0);" onclick="changeColumn('2r')">2カラム(右)</a></li>
<li><a href="javascript:void(0);" onclick="changeColumn('2rl')">2カラム(右)リキッド</a></li>
<li><a href="javascript:void(0);" onclick="changeColumn('1')">1カラム</a></li>
<li><a href="javascript:void(0);" onclick="changeColumn('1l')">1カラムリキッド</a></li>
</ul>
3.スタイルの追加
2項で一応完成ですが、プルダウンメニューの位置を整えるために下記のCSSを追加します。
#cc {
text-align:center;
padding-top: 15px;
}
*1:色覚障害等で色が識別できない場合は、サイト右上の「Styles」メニューにある Gray Scale をクリックしてください。IEではグレースケール表示され、青色部分が下線表示、赤色部分が二重下線で表示されます。Firefox/Opera ではカラー表示のままですが下線表示に切り替わります。なお設定の都合上、リンクとテキスト表示が判断できなくなりますので予めご容赦ください。
mt-site.js について(その3:cookie登録の改善)
mt-site.js について(その2:注意事項)の最後で述べた、
コメント投稿フォームの「情報を登録しますか?」チェックボックスのチェックを外すと、mt-site.js の forgetMe が実行され、それまで入力していたコメント情報が消去されてしまいます。お世辞にも使い勝手が良いとは言えないので、別途修正案を提示したいと思います。
の修正案です。これを行う理由は、cookie非登録というチェックを外す操作によるフォーム情報のクリアはユーザが意図しない動作である、というところに基づいています。英語圏では等しいのかもしれませんが少なくとも私はそう感じましたので。
解決策はたいした内容ではありません。管理画面よりテンプレートの mt-site.js を選択し、「テンプレートの内容」にある、
function forgetMe (f) {
deleteCookie('mtcmtmail', '/', '');
deleteCookie('mtcmthome', '/', '');
deleteCookie('mtcmtauth', '/', '');
f.email.value = '';
f.author.value = '';
f.url.value = '';
}
の赤色部分を削除します。
2005.11.18 追記
mt-site.js について認識誤りがあったため本文を修正しました。
mt-site.js について(その2:注意事項)
Movable Type 3.2-ja 以降でデフォルト・テンプレートをご利用になるか、新たにテンプレートを作成される場合、mt-site.js の振る舞いの制約上、いくつか注意する点があります。またコメント・トラックバック関連の表示でいくつかの不具合が確認されていますので、下記の修正あるいは設定を推奨します。
1.cookie登録のチェックボックスを追加
修正の対象はコメント・プレビューテンプレートです。
エントリー・アーカイブには、コメント投稿フォームに cookie 登録用のチェックボックス
この情報を登録しますか?
が存在しますが、コメント・プレビューテンプレートにはこのチェックボックスが存在しません。このチェックボックスが存在しないと、ページを開いた時に
document.comments_form.bakecookie has no properties
という JavaScript エラーが発生します。これは mt-site.js の individualArchivesOnLoad に含まれるコード
if (mtcmtauth || mtcmthome) {
document.comments_form.bakecookie.checked = true;
} else {
document.comments_form.bakecookie.checked = false;
}
が実行される時に document.comments_form.bakecookie がみつからないためです。
ということで、本チェックボックス(青色部分)を下記の位置に追加しましょう。
<p>
<label for="comment-url">URL: </label>
<input id="comment-url" name="url" size="30" value="<$MTCommentPreviewURL$>" />
</p>
<p>
<label for="comment-bake-cookie"><input type="checkbox"
id="comment-bake-cookie" name="bakecookie" onclick="if (!this.checked) forgetMe(document.comments_form)" value="1" />
この情報を登録しますか?</label>
</p>
</div>
2.コメント関連タグのID属性について
mt-site.js はコメント投稿フォームにある下記のID属性を利用して表示・非表示を制御しています。
- comments-open
- comments-open-data
- name-email
- comments-open-text
- comments-open-footer
mt-site.js ではこれらのID属性有無チェックは行っていないため、テンプレートを自作される場合(特に他へ公開される等)はこれらのタグを含むようにしましょう。
3.トラックバック関連タグのID属性について
mt-site.js はトラックバック欄にある下記のID属性を参照して、表示・非表示を制御しています。
- trackbacks-info
3項と同様、テンプレートを自作される場合等はこれらのタグを含むようにしましょう。
4.その他1(commenter_name.js の削除)
コメント・プレビューテンプレートのヘッダ部分に記述されている
<script type="text/javascript" src="<MTStaticWebPath>js/commenter_name.js"></script>
は不要です。この行が残っているとコメント・プレビュー画面で JavaScript エラーが発生する可能性があるため削除しましょう。
commenter_name.js というファイルは、英語版の初期β版には含まれていましたが、それ以降は含まれていません。また commenter_name.js の内容は mt-site.js に包含されていますので削除しても問題はありません。
公開テンプレートでは現在コメントアウトしていますが、初期のテンプレートでは有効になっている場合があるため、JavaScript エラーになる場合はこの行を削除してください。
5.その他2(cookie登録用チェックボックスの振る舞い)
コメント投稿フォームの「情報を登録しますか?」チェックボックスのチェックを外すと、mt-site.js の forgetMe が実行され、それまで入力していたコメント情報が消去されてしまいます。お世辞にも使い勝手が良いとは言えないので、別途修正案を提示したいと思います。
とりあえず無闇にチェックを外はずないよう気をつけましょう。
mt-site.js について(その1:仕組みと動作)
エントリー・アーカイブやコメント・プレビュー画面のヘッダ部分には、
<script type="text/javascript" src="<$MTBlogURL$>mt-site.js"></script>
という設定があります。
この mt-site.js は、エントリー・アーカイブやコメント・プレビュー画面でのコメント・トラックバック欄の表示・非表示および、TypeKey認証時のコメンター情報や投稿フォームの表示を制御するためのものです。
以下、mt-site.js の仕組みおよび動作について説明します。
1.インタフェース
mt-site.js では下記のインタフェース(関数)が定義されています(内部で利用されるインタフェースは省略しています)。
- rememberMe:cookie に投稿者情報(名前・メールアドレス・URL)を保存
- forgetMe:cookie から投稿者情報(名前・メールアドレス・URL)を削除し、フォームデータをクリア
- individualArchivesOnLoad:設定状態によってコメント・トラックバック欄の表示・非表示を制御+cookieからコメント投稿者情報取得
- writeTypeKeyGreeting:TypeKeyサイン・イン/サイン・アウト情報表示を制御
また、mt-site.js が取得された、つまりHTMLのヘッダに記述された冒頭の script 要素が読み込まれた時点で、
- commenter_name
が生成(プログラム的には「変数定義」を指します)されます。commenter_name は TypeKey による投稿者のニックネームで、ニックネームを cookie あるいは Movable Type から取得するコードも同時に生成されます(生成契機は2項参照)。このコードも script 要素が読み込まれる契機に実行されます。
2.生成契機
mt-site.js は、テンプレートの再構築を契機に生成されるダイナミックなスクリプトです。ダイナミックな生成を行う理由は、ブログのコメント・トラックバックの設定内容によってスクリプトの振る舞いを変える必要があるためです。
例えば、コメントを「一切受け付けない」という設定にした場合、エントリー・アーカイブのコメント欄は表示されなくなり、コメント・プレビュー画面は当然それ自体にジャンプできなくなります。
これは設定に応じた mt-site.js が再構築によって自動生成され、エントリー・アーカイブを表示する時にコメント投稿フォーム表示させないように mt-site.js が制御しているためです。
mt-site.js は「インデックステンプレート」として登録されており、「インデックス・テンプレートの再構築」を契機に生成されます(メインページではなく「インデックス・テンプレート」であることに注意してください)。設定の変更を行って「インデックス・テンプレートの再構築」が促された場合は、再構築が必要であることを指します(再構築が不要な場合は表示されません)。
それ以外の契機でインデックス・テンプレートの再構築を行う場合は、再構築画面の「すべてを再構築」または「インデックス・テンプレートを再構築」を選択してください。
また設定画面の TypeKey 登録を行い、インデックス・テンプレートを再構築すると、mt-site.js の最後の辺りに TypeKey 投稿者のニックネームを取得する
if ('user-domain' != 'user-domain') {
document.write('<script src="http://user-domain/mt/mt-comments.cgi?__mode=cmtr_name_js"></script>');
} else {
commenter_name = getCookie('commenter_name');
}
が生成されます。
user-domain 同士を比較している部分は、実際には MTCGIHost と MTBlogHost が展開された値が設定されます。独自ドメインを取得している場合等には cookie からの取得ができない(ホスト名が異なるため)ので、
http://user-domain/mt/mt-comments.cgi?__mode=cmtr_name_js
が実行されます。ちなみにこのURLを実行すると、
var commenter_name = 'hogehoge';
というレスポンスになります。hogehoge の部分がコメンター情報で、つまりコメンター情報が JavaScript として直接HTMLに表示されるという仕組みです。
3.動作
エントリーアーカイブにおける、TypeKey サイン・インした後の TypeKey 関連情報の表示の流れを説明します(設定画面で TypeKey 登録が完了していることを前提としています)。
3.1 ニックネーム取得
ページが表示されると(厳密にはヘッダの script 要素が実行されると)、mt-site.js に記述された、
if ('user-domain' != 'user-domain') {
document.write('<script src="http://user-domain/mt/mt-comments.cgi?__mode=cmtr_name_js"></script>');
} else {
commenter_name = getCookie('commenter_name');
}
が実行されて、cookie あるいは Movable Type より投稿者のニックネームを取得。
3.2 名前・メールアドレスの表示制御
次に、body 要素の individualArchivesOnLoad が実行され、commenter_name が存在する場合は、コメント投稿フォームの名前・メールアドレス欄を非表示に、存在しない場合は表示します。
3.3 サイン・インの表示制御
最後に、投稿フォームの中にある writeTypeKeyGreeting が実行されて、commenter_name が存在する場合は、コメント投稿フォームに
サインインを受け付けました。hogehoge さん。コメントしてください。(サイン・アウト)
と表示し、存在しない場合は、
TypeKey IDを使ってサイン・インしてください。
と表示します。
2005.11.18 追記
本文を修正しました。

