2004年12月29日
●コメント投稿者の情報表示をカスタマイズする
コメント投稿者の情報表示のカスタマイズについてご説明致します。
表示に使用される変数タグは MTCommentAuthorLink / MTCommentPreviewAuthorLink の2種類で、表示方法の詳細設定にタグアトリビュート(属性)を用います。これによりコメントに入力されたコメント投稿者の情報(URL・メールアドレス等)の表示・非表示やを表示方法等をコントロールすることができます。
カスタマイズ方法です。まず MTCommentAuthorLink / MTCommentPreviewAuthorLink は、下記の各テンプレートの赤色部分に存在します(デフォルトテンプレートで示しています)。カスタマイズされる場合はこれらが一律対象となります。
個別エントリーアーカイブ
<MTComments>
<div id="c<$MTCommentID$>">
<$MTCommentBody$>
</div>
<p class="posted">投稿者 <$MTCommentAuthorLink default_name="Anonymous" spam_protect="1"$> <MTCommentAuthorIdentity> : <$MTCommentDate$></p>
</MTComments>
コメント・プレビュー
<$MTCommentPreviewBody$>
<p class="posted">投稿者 <$MTCommentPreviewAuthorLink spam_protect="1"$> : <$MTCommentPreviewDate$></p>
:
<MTComments>
<$MTCommentBody$>
<p class="posted">投稿者 <$MTCommentAuthorLink default_name="Anonymous" spam_protect="1"$> : <$MTCommentDate$></p>
</MTComments>
コメント・リスト(本テンプレートを使用している場合)
<MTComments>
<$MTCommentBody$>
<p class="posted">投稿者 <$MTCommentAuthorLink default_name="Anonymous" spam_protect="1"$> : <$MTCommentDate$></p>
</MTComments>
次にタグアトリビュート一覧を示します。
名前の入力がない場合のデフォルト名を設定する
default_name="Anonymous"
これは管理メニュー左の「ウェブログの設定」をクリック→次ページ右上の「設定」をクリック→次ページ下の方にある「コメント」の「名前とURLを必須にする」にチェックがついていない場合に有効になります。デフォルトテンプレートではこの属性が付与されていますが、先のチェックがついていれば気にする必要はありません。この属性の設定がなく「名前とURLを必須にする」チェックがついていない状態で名前なしのコメントが投稿されると、コメント欄に投稿者名が表示されません。
なお設定した場合(および無効にした場合)は以前の名無しコメント全てに適用されます。
メールアドレスにリンクしない
show_email="0"
コメントのメールアドレス欄にメールアドレスが入力されてもリンクしません。デフォルトテンプレートではリンクする状態になっています。
URLにリンクしない
show_url="0"
コメントのURL欄にURLが入力されてもリンクしません。デフォルトテンプレートではリンクする状態になっています。
URLをリダイレクトしない
no_redirect="1"
コメントスパムの目的は、リンクがクリックされることにより検索エンジンのランクを向上させることです。この部分でURLをリダイレクトする意味は、コメント投稿者のURLを検索エンジンから直接見えないようにするためです。そうすることでコメント・スパムの検索エンジンでのランク向上を抑制する効果があります。
デフォルト状態ではこのリダイレクト機能を有効にしていますが、リダイレクトを使いたくない場合は上記の設定を追加してください。
メールアドレスをスパム・ボット対策されたアドレスに変更する
spam_protect="1"
スパマーはHTMLソースに記述されるメールアドレスのフォーマットを見つけてスパムメールを送ります。
spam_protect アトリビュートを設定すればメールアドレスのリンクは表示されますが、スパム・ボット対策されたアドレスに変更されます。つまりブラウザ上では正しいメールアドレスとして表示され、実際のHTMLソースには「@」や「.」を含みません。例えばメールアドレスが
- foo@bar.com
- foo@bar.com
デフォルトテンプレートではこの設定になっていますが、先の show_email="0" を指定した場合はメールアドレスにリンクしなくなるため冗長な設定となります。ただし設定が残っていても問題はありません。
下記に設定例を示します。最もポピュラーと思われるケースで「メールアドレスをリンクしない&メールアドレスをスパム・ボット対策されたアドレスに変更する」の設定は、
<$MTCommentAuthorLink show_email="0" spam_protect="1"$>
または
<$MTCommentPreviewAuthorLink show_email="0" spam_protect="1"$>
となります。
属性を記述する場合はその前後に半角空白を挿入します(変数タグの終了を示す"$"との間はなくても大丈夫です)。属性の記述順序に制約はありません。
2004年12月22日
●MTCommentPreviewIsStatic の振る舞いについての改善案
コメントのポップアップ化に関する事項で、投稿後の表示画面選択情報を保持する MTCommentPreviewIsStatic の振る舞いについて改善案を記します。
MTCommentFields タグで MTCommentPreviewIsStatic が指定できない
MTCommentFields はコメント・リスト/コメント・プレビュー/コメント・エラーの各テンプレートでコメント入力フォームを指定するコンテナタグです。MTCommentPreviewIsStatic は、ユーザー・マニュアルでは
特別な秘匿タグで、Comment Preview and Comment Error テンプレートで使います。システムは、コメントを投稿後、どのページを表示したらよいか知るために、このタグを利用します。このタグを使うときは Comment Preview と Comment Error テンプレートの中の HTML フォーム の INPUT HIDDEN の中に埋め込みます。
という説明になっています。これは変数タグで、値と意味は次の通りと考えられます。
- 0:ポップアップ・ウィンドウ
1:非ポップアップ・ウィンドウ
<input type="hidden" name="static" value="1">
またはコメント・リストの
<MTCommentFields static="0">
より取得します。
この値の取得方法は Movable Type ユーザー・マニュアルによると、コメント・プレビュー/コメント・エラーテンプレートのコメントフォーム内に
<input type="hidden" name="static" value="<$MTCommentPreviewIsStatic$>">
を指定するようになっています。
input タグを用いるということは、デフォルトテンプレートで使われている MTCommentFields が適用できないということを暗黙的に指しており、コメント用テンプレートに 個別エントリーアーカイブと同じ(膨大な)テンプレートを貼り付ける必要があります。
これは大きな問題ではありませんが面倒です。また直感的およびポップアップ化によるテンプレート変更の容易性から、コメント・プレビュー/コメント・エラーテンプレートで
<MTCommentFields preview="1" static="<$MTCommentPreviewIsStatic$>">
という指定ができても良いのではないでしょうか(実験しましたが×)。
という訳で上記は改善案として記させて頂きました。またこの指定が可能となるパッチが Orgawa::memoranda さんより公開されることを密かに期待しております。
なお MTCommentPreviewIsStatic 値の取得は、MTCommentFields を残した状態で下記のスクリプト(青色部分)を追加することで実現できます。
<MTCommentFields preview="1">
<script language="javascript" type="text/javascript">
<!--
if (document.comments_form.static)
document.comments_form.static.value = '<$MTCommentPreviewIsStatic$>';
//-->
</script>
この方が、個別エントリーアーカイブよりコメント用フォームをコピー&ペーストし、その中の input タグの指定を変更するという作業を行うよりはるかに簡単です。
コメント・プレビュー/コメント・エラー画面でフォーム情報が引き継がれない
真面目に input タグから MTCommentPreviewIsStatic 値を取得した場合の問題です。
現状の仕様により、MTCommentPreviewIsStatic を使用するためにコメント・プレビュー/コメント・エラーテンプレートの
<MTIfCommentsAllowed>
:
</MTIfCommentsAllowed>
を個別エントリーアーカイブのもの
これについては入れ替えた部分の下記の input タグにvalue 属性等(青色部分)を追加することで解決します。
<input tabindex="1" id="author" name="author" value="<$MTCommentPreviewAuthor encode_html="1"$>"/>
:
<input tabindex="2" id="email" name="email" value="<$MTCommentPreviewEmail encode_html="1"$>"/>
:
<input tabindex="3" type="text" name="url" id="url" value="<$MTCommentPreviewURL encode_html="1"$>"/>
:
<textarea tabindex="4" id="text" name="text" rows="10" cols="50"><$MTCommentPreviewBody convert_breaks="0" encode_html="1"$></textarea>
また入れ替えたタグの直後に下記のスクリプト(Ogawa::memoranda:Movable Type 3.0のMTCommentFields tagより引用)を追加する方法もあります。
<script language="javascript" type="text/javascript">
<!--
if (document.comments_form.author)
document.comments_form.author.value =
'<$MTCommentPreviewAuthor encode_js="1"$>';
if (document.comments_form.email)
document.comments_form.email.value =
'<$MTCommentPreviewEmail encode_js="1"$>';
if (document.comments_form.url)
document.comments_form.url.value =
'<$MTCommentPreviewURL encode_js="1"$>';
if (document.comments_form.text)
document.comments_form.text.value =
'<$MTCommentPreviewBody convert_breaks="0" encode_js="1"$>';
//-->
</script>
仮にこれが不具合であったとしてもシステムとして修正されることは考えにくいので、やはりコメント・プレビュー/コメント・エラーテンプレートでは MTCommentFields の利用が前提ではないかと推測しています。
動作および振る舞いについて認識誤り等ございましたらご指摘ください。
2004.12.23 追記
フォーム情報が引き継がれない問題について、(o)さんよりアドバイス頂いた方法(inputタグに挿入)に修正しました。先に書いたのもとりあえず残してます。
またスクリプトの引用がもれていたので追記しました。
さらにcookie取得用のJavaScriptは不要ですので削除しました(ポップアップでこれが必要なのはコメント・リストテンプレートのみ)。
2004年11月24日
●カテゴリーアーカイブで全カテゴリーリストを表示
Movable Type 3.11-ja ではサブカテゴリー機能が追加されました。それに伴いサイドバーメニューのカテゴリーリストにはこれまで通りの表示に加え、サブカテゴリー表示もできるタグ
- <MTSubCategories>~</MTSubCategories>
ところが、例えばメインページからカテゴリーアーカイブページにジャンプすると、サイドバーのカテゴリーリストにはそのカテゴリー配下のカテゴリーしか表示されなくなります。配下のカテゴリーが存在しない場合は何も表示されません。
カテゴリーリストの表示サンプルを下図に示します。
・メインページで表示されているカテゴリーリスト。ここでは全カテゴリーが表示されています。視覚的にお分かりになると思いますが、トップカテゴリーに「ウェブログ」「趣味」、「ウェブログ」カテゴリーのサブカテゴリーに「こうさぎ」「カスタマイズ」、「カスタマイズ」カテゴリーのサブカテゴリーに「テンプレート」「折りたたみ」、「趣味」カテゴリーのサブカテゴリーに「映画」「読書」があります。 |
・上のカテゴリーリストより「ウェブログ」をクリックしてジャンプしたページで表示されるカテゴリーリストです。「ウェブログ」カテゴリーに関係するサブカテゴリーだけが表示されます。 |
・上のカテゴリーリストより「カスタマイズ」をクリックしてジャンプしたページで表示されるカテゴリーリストです。「カスタマイズ」カテゴリーに関係するサブカテゴリーだけが表示されます。 |
・上のカテゴリーリストより「折りたたみ」をクリックしてジャンプしたページで表示されるカテゴリーリストです。下位のカテゴリーが存在しないため何も表示されません。 |
このエントリーではどのカテゴリーアーカイブページにジャンプしても、サンプルの一番上の画像のようなメニューが表示される方法を紹介します。なお日付アーカイブや個別アーカイブではページ自体に「カテゴリー」という概念がない(つまり先のタグがカテゴリーアーカイブ内のような振る舞いをしない)ので全カテゴリーが表示されます。
全カテゴリーを表示するには MTTopLevelCategories を用いることで実現できます。テンプレートの下記の赤色部分を青色に変更してください。
変更前
<div class="sidetitle">
Categories
</div><div class="side">
<div id="categories">
<MTSubCategories>
<MTSubCatIsFirst><ul></MTSubCatIsFirst>
<MTIfNonZero tag="MTCategoryCount">
<li><a href="<$MTCategoryArchiveLink$>" title="<$MTCategoryDescription$>"><MTCategoryLabel></a> [<$MTCategoryCount$>]
<MTElse>
<li><MTCategoryLabel>
</MTElse>
</MTIfNonZero>
<MTSubCatsRecurse max_depth="3">
</li>
<MTSubCatIsLast></ul></MTSubCatIsLast>
</MTSubCategories>
</div>
</div>
変更後
<div class="sidetitle">
Categories
</div><div class="side">
<div id="categories">
<MTTopLevelCategories>
<MTSubCatIsFirst><ul></MTSubCatIsFirst>
<MTIfNonZero tag="MTCategoryCount">
<li><a href="<$MTCategoryArchiveLink$>" title="<$MTCategoryDescription$>"><MTCategoryLabel></a> [<$MTCategoryCount$>]
<MTElse>
<li><MTCategoryLabel>
</MTElse>
</MTIfNonZero>
<MTSubCatsRecurse max_depth="3">
</li>
<MTSubCatIsLast></ul></MTSubCatIsLast>
</MTTopLevelCategories>
</div>
</div>
MTTopLevelCategories についてはMovable Type ユーザマニュアル: テンプレートタグで下記の説明があります。
MTTopLevelCategories
MTSubCategoriesのクローン。ただし、カテゴリー階層の最上位で常に開始します。
上記で全カテゴリーが表示されるようになりますが、カテゴリーリストを独立したインデックステンプレートとして割り充てる方法を併せてご紹介しておきます。これは巷で流行っている(?)「モジュール(部品)化」というものです。
インデックステンプレートはいわゆるメインページや他のアーカイブテンプレートと同じ位置付けで、保存・再構築することで独立したファイルを出力します。モジュール化のメリットはエントリーの再構築時間を短縮と、適用したアーカイブページで常に同じ内容が反映されることです。
以下、カスタマイズ方法です。
管理メニューの「テンプレート」をクリックし、次ページの「インデックス・テンプレート」の右端にある「新しいインデックス・テンプレートを作る」をクリック。次ページの各項目に以下の内容を設定してください。
- テンプレートの名前:カテゴリーリスト
- 出力ファイル名:categorylist.html
- このテンプレートにリンクするファイル:(無記入)
- 再構築オプション:チェックをする
- テンプレートの中身:下記をコピー&ペースト(緑色部分は2004.12.01修正箇所)
<div class="sidetitle">
Categories
</div><div class="side">
<div id="categories">
<MTTopLevelCategories>
<MTSubCatIsFirst><ul></MTSubCatIsFirst>
<MTIfNonZero tag="MTCategoryCount">
<li><a href="<$MTCategoryArchiveLink$>" title="<$MTCategoryDescription$>"><MTCategoryLabel></a> [<$MTCategoryCount$>]
<MTElse>
<li><MTCategoryLabel>
</MTElse>
</MTIfNonZero>
<MTSubCatsRecurse max_depth="3">
</li>
<MTSubCatIsLast></ul></MTSubCatIsLast>
</MTTopLevelCategories>
</div>
</div>
ペーストする内容は公開テンプレート(スタイルシート)を前提にしたものです。異なるテンプレートを使用されている場合は div タグのクラス属性等を適宜修正してください。
修正が終わったら、保存・再構築してください。管理メニューの「ウェブログの設定」→「基本設定」で指定したローカル・サイト・パスに categorylist.html が配置されます。
先の categorylist.html をインクルードするためにカテゴリー・アーカイブテンプレートの下記の赤色部分を青色部分に修正します(リストは公開テンプレートを例にしています)。
修正前
<div class="sidetitle">
Categories
</div><!-- 全カテゴリー用 -->
<div class="side">
<MTCategories>
<a href="<$MTCategoryArchiveLink$>">
<$MTCategoryLabel$></a> [<$MTCategoryCount$>]<br />
</MTCategories>
</div>
<!-- 全カテゴリー用 -->
修正後
<$MTInclude file="categorylist.html"$>
categorylist.html が正常に読み込めない場合は上記のfile属性指定の部分をルートディレクトリからのフルパス指定に変更してください。
修正が終わったら保存・再構築してください。ここまでの作業が済めばカテゴリーアーカイブページのカテゴリーリストは全カテゴリーが表示されるようになっています。
カテゴリー・アーカイブテンプレートを除いた各テンプレートのカテゴリーリストを、MTCategories から MTSubCategories を用いたものに置き換えます。各テンプレートのカテゴリーリストを前記と同様の作業(MTIncludeタグへの変更)を行ってください。公開テンプレートをご利用の方は、下記のようにカテゴリーリストをコメントアウト(赤色部分を削除)し、コメントアウトされたサブカテゴリー部分を有効(青色部分を追加)にされてもOKです。
修正前
<!-- 全カテゴリー用 -->
<div class="side">
:
</div>
<!-- 全カテゴリー用 --><!-- サブカテゴリー用
<div class="side">
<div id="categories">
:
</div>
</div>
サブカテゴリー用 -->
修正後
<!-- 全カテゴリー用
<div class="side">
:
</div>
全カテゴリー用 --><!-- サブカテゴリー用 -->
<div class="side">
<div id="categories">
:
</div>
</div>
<!-- サブカテゴリー用 -->
修正が終了したらそれぞれ保存・再構築してください。
作業は以上です。なお3.11-ja用公開テンプレートご利用の方はスタイルシートの設定に冗長な部分がございましたので、下記の赤色部分をばっさり削除してやってください。少なくとも一番下の margin-bottom~ を削除しないとメニュー下の空白が相当とられてしまいます。
.side #categories {
font-family: Verdana, Arial, sans-serif;
color: #666666;
background: none;
font-size: 9px;
font-weight:normal;
line-height:150%;
text-align: left;
padding:2px;
margin-bottom:25px;
}
2004.12.01 お詫び
全カテゴリー表示に MTTopLevelCategories タグを用いた方法がありましたので記述を一部修正致します。Note book :: Hibi no Note さんよりご指摘頂きました。ありがとうございました。
2004年11月17日
●MTIfNonZeroタグでコメント表示方法を制御する
個別エントリーアーカイブの中で、「トラックバック数が0件でなければトラックバックを表示する」ために利用する
- MTIfNonZero
参照サイトは下記です。ありがとうございました。このエントリーでは MTIfNonZero タグを利用して、コメント投稿数が0件の時に
- 個別エントリーアーカイブの「コメント」タイトルを表示しない
- 個別エントリーアーカイブの「コメント」タイトル下に「コメントがありません」という表示をする
【「コメント」タイトルを表示しない】
個別エントリーアーカイブテンプレートの下記の部分に青色のタグを挿入すれば、コメントが0件の場合にコメントのタイトルを非表示にすることができます。</MTIfNonZero> の挿入位置は「コメント」と書かれた次の行でも問題ないと思いますが、コメント表示タグ全体を括らないのはスッキリしないので個人的には下記を推奨します。
:
<MTEntryIfAllowComments>
<MTIfNonZero tag="MTEntryCommentCount">
<div id="comments" class="comments-head"><a name="comments"></a>コメント</div><MTComments>
<a name="<$MTCommentID$>"></a>
<div id="c<$MTCommentID$>" class="comments-body">
<$MTCommentBody$>
<div class="comments-post">Posted by <$MTCommentAuthorLink default_name="Anonymous" spam_protect="1"$> <MTCommentAuthorIdentity> at <$MTCommentDate$></div>
</div>
</MTComments>
</MTIfNonZero>
<MTEntryIfCommentsOpen>
:
意味的には、MTIfNonZero の tag属性 MTEntryCommentCount(=エントリーのコメント数)が0でなければ <MTIfNonZero>~</MTIfNonZero> で囲まれた部分を表示(厳密には有効に)する、というものです。
【「コメント」タイトル下に「コメントがありません」という表示をする】
上記同様、青色のタグを該当位置に挿入すれば、コメントが0件の場合にコメントのタイトル下に「コメントがありません。」というメッセージを表示することができます。タイトルはいずれの場合も表示するので MTIfNonZero タグの中に入れないようにします。divタグは公開テンプレート用に併せて書いてありますので適宜変更してください。
:
<MTEntryIfAllowComments>
<div id="comments" class="comments-head"><a name="comments"></a>コメント</div>
<MTIfNonZero tag="MTEntryCommentCount">
<MTComments>
<a name="<$MTCommentID$>"></a>
<div id="c<$MTCommentID$>" class="comments-body">
<$MTCommentBody$>
<div class="comments-post">Posted by <$MTCommentAuthorLink default_name="Anonymous" spam_protect="1"$> <MTCommentAuthorIdentity> at <$MTCommentDate$></div>
</div>
</MTComments>
<MTElse>
<div class="comments-body">コメントはまだありません。</div>
</MTElse>
</MTIfNonZero>
<MTEntryIfCommentsOpen>
:
この処理をおおざっぱに書くと
<MTIfNonZero tag="MTEntryCommentCount">
:
コメントが0件でない時の処理を記述
:
<MTElse>
:
コメントが0件の時の処理を記述
:
</MTElse>
</MTIfNonZero>
という感じになります。MTElse というタグは MTIfNonZero の条件にマッチしなかった場合のものを有効にするためのタグです。
2004年10月16日
●エントリーにpタグとbrタグが入る仕組み(その3:textareaにbrタグを挿入しない)
その2では特定のタグに対して常に改行タグを挿入する方法について述べましたが、今回は逆に改行タグを挿入しない方法について記します。
エントリーに <textarea>~</textarea> や <pre>~</pre> 等、内部情報に改行タグを挿入したくないタグを使用する場合があります。が現状の動作では、例えばpreタグは改行タグが挿入されないよう、
lib/MT/Util.pm
の html_text_transform の条件式に
sub html_text_transform {
my $str = shift;
$str ||= '';
my @paras = split /\r?\n\r?\n/, $str;
for my $p (@paras) {
if ($p !~ m@^</?(?:h1|h2|h3|h4|h5|h6|table|ol|dl|ul|menu|dir|p|pre|center|form|blockquote|fieldset|address|div|hr)@) {
$p =~ s!\r?\n!<br />\n!g;
$p = "<p>$p</p>";
}
}
join "\n\n", @paras;
}
としっかり設定(青色部分)されていますが、直前の行が空行でなければ期待する動作になりません。textareaタグは条件式に設定すらされていないので一律挿入されます。
こういう時のため(?)に、エントリー編集画面の下に「テキストフォーマット」が用意されているようで、この選択を「Convert Line Breaks」から「なし」に変更することでエントリーには改行タグが一律設定されなくなります。
しかし逆に他のテキスト行に改行タグを自前で付与しなければならず、結構面倒です。また「なし」にしなければならない設定を「Convert Line Breaks」のまま登録してしまい、textarea内をbrタグだらけにしてしまうという失敗もやらかしました。
できればどのエントリーも「Convert Line Breaks」のまま記述でき、なおかつ特定のタグに括られた部分は改行タグを挿入したくないところです。
ということで対処してみました。前回までのような鬱陶しい説明はございません(というか既に十分長い前置きですが(笑))。
先の html_text_transform の
$p = "<p>$p</p>";
の次の行に
$p =~ s!((?:\G|<textarea>)[^<]*?)<br />!$1!g;
を追加すれば <textarea>~</textarea> 間にある改行タグを削除します。条件式にも一応 "textarea" を追加おくと良いでしょう。
なお textarea タグに属性を付与する場合は上記の <textarea> にも属性を記述して、文字列が完全にマッチするように修正してください。例えば <textarea cols="50" rows="10" readonly> というタグを記述されのであれば、スクリプトを
$p =~ s!((?:\G|<textarea cols="50" rows="10" readonly>)[^<]*?)<br />!$1!g;
とする必要があります。
他のタグを追加する場合は、追加した行の "textarea" を "(" と ")" で括り、該当のタグ文字を "|" で区切って追加します(下記はpreを追加する例です)。
$p =~ s!((?:\G|<(textarea|pre)>)[^<]*?)<br />!$1!g;
なお該当のタグ内に別のタグ(というか"<")が存在する(例えば <textarea>~<hoge>~</hoge>~</textarea>)場合は正常に動作しませんので予めご容赦ください。
このシリーズは以上です。
2004.10.23 追記
3.11-ja での動作実績が下記エントリーにて報告されています。
textareaに属性を設定する場合の説明を追加しました。
2004年10月14日
●エントリーにpタグとbrタグが入る仕組み(その2:blockquoteにbrタグを挿入)
現状の Movable Type の振る舞いでは、エントリーのblockquote開始タグの直前の行に
- 何もない(=エントリーの先頭)
- 文字がある(=段落の途中にblockquoteが存在)
- 空行が1行ある
- 空行が2行ある
上記のケース順に記した下記のエントリーがあるとします。
<blockquote>あいうえお
あいうえお
あいうえお</blockquote>
←空行
かきくけこ
<blockquote>かきくけこ
かきくけこ
かきくけこ</blockquote>
←空行
<blockquote>さしすせそ
さしすせそ
さしすせそ</blockquote>
←空行
←空行
<blockquote>たちつてと
たちつてと
たちつてと</blockquote>
これを保存すると、pタグおよびbrタグは次のように付与されます。
<blockquote>あいうえお
あいうえお
あいうえお</blockquote>
←空行
<p>かきくけこ<br />
<blockquote>かきくけこ<br />
かきくけこ<br />
かきくけこ</blockquote></p>
←空行
<blockquote>さしすせそ
さしすせそ
さしすせそ</blockquote>
←空行
<p><br />
<blockquote>たちつてと<br />
たちつてと<br />
たちつてと</blockquote></p>
2と4の場合は期待する結果になりますが、1と3の場合は改行が付与されません。いずれもエントリーにpタグとbrタグが入る仕組み(その1)に記した通りの動作です。
空行が2行の場合について補足致しますと、段落は連続した改行("\n\n"または"\r\n\r\n")で区切られるため、3つめの改行は段落内の文字として認識されます。つまりblockquoteタグの前に(空の)文字が存在する状態になるため改行タグが付与されます。2行あった空行は、後の1行が段落内の文字として扱われるため1行になります。空行下の <p><br /> に変換されている部分が昔、空行だった行です。
余談ですがこのロジックでは空行が偶数であれば改行タグが一律付与され、奇数の空行の場合は(条件に記されたタグは)付与されないという現象が発生します。
Movable Type における改行タグの挿入方法は、HTMLを記述する際に「タグの直前に空行が存在する」というお作法が前提になっていますが、エントリーに挿入した改行と同じ位置に改行タグの挿入を期待するユーザにとっては混乱を招く原因になっているように思われます。
常に改行を挿入する方法は既出で存在していますが、個人的には "blockquote" を条件式から除外する方法を採っています。具体的にはlib/MT/Util.pmのhtml_text_transformの赤字部分
for my $p (@paras) {
if ($p !~ m@^</?(?:h1|h2|h3|h4|h5|h6|table|ol|dl|ul|menu|dir|p|pre|center|form|fieldset|blockquote|address|div|hr)@) {
$p =~ s!\r?\n!<br />\n!g;
$p = "<p>$p</p>";
}
}
を削除して
for my $p (@paras) {
if ($p !~ m@^</?(?:h1|h2|h3|h4|h5|h6|table|ol|dl|ul|menu|dir|p|pre|center|form|fieldset|address|div|hr)@) {
$p =~ s!\r?\n!<br />\n!g;
$p = "<p>$p</p>";
}
}
としています。
同様に、brタグを一律付与したいタグは条件から外すのが手っ取り早いと思います。(つづく)
2004.10.23 追記
3.11-ja での動作実績が下記エントリーにて報告されています。
2004年10月13日
●エントリーにpタグとbrタグが入る仕組み(その1:コード解析)
我楽さんのBlockquoteタグにデフォルトで改行が入るようにする。(のそれた話)がきっかけという訳ではないのですが、私もエントリーのblockquoteタグに改行が入ったり入らなかったりすることがあり、Movable Typeにおけるbrタグ挿入の振る舞いについて前々から調べてました(時間かかりすぎ?)。
ということで書けそうなレベルまでなんとか到達しましたので、シリーズもので書きます(単なるネタ増やしです(笑))。ほとんどPerl&正規表現メモになってしまいました。Perlプログラマの方には既知の部分しかありませんので予めご容赦ください。また認識誤り等ございましたらお許しください。「難しい」という方は最後のまとめだけお読み頂ければ幸いです。
エントリー入力画面で、下にある「テキストエリア」というセレクトボックスが「Convert Line Breaks」になっている場合、「保存」または「確認」をクリックすると改行部分には自動的に <p>~</p> または <br /> が挿入されます。
この処理を行っているのが
lib/MT/Util.pm
の html_text_transform という下記の関数です。
1:sub html_text_transform {
2: my $str = shift;
3: $str ||= '';
4: my @paras = split /\r?\n\r?\n/, $str;
5: for my $p (@paras) {
6: if ($p !~ m@^</?(?:h1|h2|h3|h4|h5|h6|table|ol|dl|ul|menu|dir|p|pre|center|form|fieldset|blockquote|address|div|hr)@) {
7: $p =~ s!\r?\n!<br />\n!g;
8: $p = "<p>$p</p>";
9: }
10: }
11: join "\n\n", @paras;
12:}
処理は行番号毎に下記のようになっています。
- 引数であるエントリー文字列をローカル変数 $str に保持(他の処理から"@_"という省略された変数で引き継いでいます)。
- $str が空き、つまりエントリーが空きでなければ取得(この文は $str = '' || $str; と同義でしょうか)。
- $str を改行二つ(つまり空行)が入っている箇所で分割します。例えばエントリーに空行が3ヶ所あれば4つの(いわゆる)段落に分割されます。分割されたものは @paras という配列に保存されます。改行文字は文字コード(Shift_JIS、EUC等)によって "\r\n" と "\n" の2種類があり、
\r?\n\r?\n
と書くことで両者に対応しています。"?" は直前の文字、つまり "\r" が0回または1回出現することを示しています。つまり上記の正規表現は、
\r\n\r\n または \n\n
のいずれかを示しています("\r\n" と "\n" が混在することは多分ありません)。
- 分割された単位で下記の処理を繰り返します。この行では @paras から一段落分ずつ取り出し、変数 $p に設定しています。
- 該当するタグ(ここではh1、h2、h3~hr)にマッチしないか判定。
まず "m@~@" という構文はパターンマッチを表しており、段落中に "~" にある文字列が含まれていれば処理結果は「真」、つまり以降の処理を実施します。パターンマッチはPerlでは、/正規表現/
という書き方が一般的です。ただし上記の場合、正規表現部分に "/" が含まれるとパターンマッチの文字列と区別するためにエスケープ("/" の前に "\")を付与しなければなりませんが、パターンマッチの区切り文字は変更することができます。該当の処理では、
m@正規表現@
という形式に変えているようです("/正規表現/" の場合は先頭の "m" を省略できます)。
またタグらしき文字列を区切っている "|" はいずれかに該当すれば良い、いわゆるOR条件演算子です。
"^" は文字列の先頭からマッチすることを示します。"<"はタグの開始文字そのものですので、"^" との組み合わせで段落の先頭が "<" で始まることがマッチする条件となっています。
さらに "<" と次の "/" が連続することで終了タグを示していますが、開始タグであることも条件に含めるために "/" の後に "?" を用いています。"?" の意味は3の説明の通りです。これで開始・終了タグである"<~" または "</~"
のいずれも条件に含まれることになります。
"(?:~)" は後方参照(説明は省略します)を行わないことを指しています。後方参照の解除はメモリの節約です(と書かれてました)。以上をまとめると、各段落の先頭が"<h1"、あるいは"</h1"等、条件式に書かれている開始・終了タグにマッチしないことが、この行の条件となります。マッチしなければ次の行を実行します。
- 改行文字を "\n<br />\n" に変換。雰囲気で変換しているのは分かりますが先と同様、"?" を\rの直後に用いることで "\r\n" または "\n" を対象としているのが分かります。また文字列置換は、
s/置換前の文字列/置換後の文字列/g;
が一般的ですが先と同様、"/" のエスケープを避けるために、
s!置換前の文字列!置換後の文字列!g;
としているようです。最後の "g" は処理の繰り返しを表します(条件にマッチする限り置換処理を繰り返します)。
- 段落の最初と最後に <p>~</p> を挿入
- 分割した段落を "\n\n"(空行)で結合して元に戻す
- pタグ:段落の先頭と最後に挿入(空行で区切られたものが「段落」となります)
- brタグ:段落内の改行部分に挿入。ただし条件式にかかれている文字列にマッチしない場合は挿入されない
【変換前】
あいうえお
←空行
かきくけこ
さしすせそ
【変換後】
<p>あいうえお</p>
←空行
<p>かきくけこ<br />
さしすせそ</p>
タグを用いた例については次回に記します。(つづく)
2004年09月18日
●MTEntryLinkとMTEntryPermalinkについて
最近のコメントのアンカー修正で気になったのが、リンク先を表すタグ「MTEntryLinkとMTEntryPermalinkの違いって何だ?」ってことです(おいおい…)。先のエントリーにMTEntryPermalinkは使っていないのですが、他サイトのコメントのリンクでMTEntryPermalinkを使っているケースがあるのを見つけたからです。
ということで以下調査メモです。
いずれのタグもエントリーを含むアーカイブページへの絶対URLを示します。そしてこのリンク先のアーカイブ種別によって機能が異なるようです。
リンク先が個別アーカイブ、つまりアーカイブページとエントリーが1:1の場合は機能的に同じですが、例えばカテゴリーアーカイブ等のように一つのページに他のエントリーと一緒にそのエントリーが入っていた場合、MTEntryPermalinkを用いれば特定のエントリーを指すためのアンカー (#) が自動的に付与されるようです。MTEntryLinkにはアンカーを付与する機能はありません。
なお試しにMTEntryPermalinkを用いてコメントのリンクを作ってみたところ、個別アーカイブを指している場合はアンカーは付与されませんでした。
リンクがどのアーカイブを指しているかを示すかは、管理メニューの「ウェブログの設定」→「ウェブログの設定」→ページ真ん中辺りの「アーカイブの設定」の最初にある「優先するアーカイブのタイプ 」で決定されます。デフォルトの設定は「個別」なので設定を変更しなければ個別アーカイブにリンクされるという仕組みです。
設定とは別にアーカイブファイルを変更したい場合はタグにarchive_type属性を付与します。例えばカテゴリーアーカイブにリンクしたい場合は、
<$MTEntryLink archive_type="Category"$>
と記述すればOKです。
参照ページは下記です。ありがとうございました。
・メインページで表示されているカテゴリーリスト。ここでは全カテゴリーが表示されています。視覚的にお分かりになると思いますが、トップカテゴリーに「ウェブログ」「趣味」、「ウェブログ」カテゴリーのサブカテゴリーに「こうさぎ」「カスタマイズ」、「カスタマイズ」カテゴリーのサブカテゴリーに「テンプレート」「折りたたみ」、「趣味」カテゴリーのサブカテゴリーに「映画」「読書」があります。
・上のカテゴリーリストより「ウェブログ」をクリックしてジャンプしたページで表示されるカテゴリーリストです。「ウェブログ」カテゴリーに関係するサブカテゴリーだけが表示されます。
・上のカテゴリーリストより「カスタマイズ」をクリックしてジャンプしたページで表示されるカテゴリーリストです。「カスタマイズ」カテゴリーに関係するサブカテゴリーだけが表示されます。
・上のカテゴリーリストより「折りたたみ」をクリックしてジャンプしたページで表示されるカテゴリーリストです。下位のカテゴリーが存在しないため何も表示されません。

