2009-03-10

Blogger の機能を増設中

Blogger のテンプレートを玩んでいた。

---

まず、フィード関連。

気分屋なので「チェックしてないと気が済まない」という物事はこの世に存在しない。ニュースだってテレビだって全然見ないときは見ない。というわけで、フィード関連は、これからも自分では使わない。と思う。

しかし、もちろん自分の好みは関係がない。

他人が便利に見てこその blog なので、フィード関連を充実させてみた。ラベル毎の投稿フィードを自動的に作成する JavaScript がクリボウさんのところにあった。おお、これはすばらしい!ありがとうございます、使わせていただきます。

でも、せっかく JavaScript の関数 encodeURIComponent() を使うのだから、 Unicode で表せる言語は全てサポートしたい。つまり、左→右と左←右のように書字方向が異なる言語が混在していても大丈夫にしないと。そして、例えばアラビア語で blog をやってる人にも使えるようにしないと。

そのためには以下のように、 data:blog.languageDirection に関連する2ヶ所(本質的には1ヶ所)を変更するだけで良い。

<ul>
<b:loop values='data:labels' var='label'>
<li>
<b:if cond='data:blog.url == data:label.url'>
<span expr:dir='data:blog.languageDirection'>
<data:label.name/>
</span>
<b:else/>
<a expr:dir='data:blog.languageDirection' expr:href='data:label.url'>
<data:label.name/>
</a>
</b:if>
(<data:label.count/>)
<script type='text/javascript'>
var icon = &#39;src=&quot;http://sites.google.com/site/onecotravel/icons/icon_feed12.png&quot;&#39;;
document.write(&#39;&lt;a title=&quot;Posts feed on this category&quot; &#39;);
document.write(&#39;href=&quot;/feeds/posts/full/-/&#39; + encodeURIComponent(&#39;<data:label.name/>&#39;) + &#39;&quot;&#39;);
document.write(&#39; target=&quot;_blank&quot;&gt;&#39;);
document.write(&#39;&lt;img width=&quot;12&quot; height=&quot;12&quot; &#39; + icon + &#39;/&gt;&#39;);
document.write(&#39;&lt;/a&gt;&#39;);
</script>
</li>
</b:loop>
</ul>


この変更をしないとき、何が起こるかは次を見ればわかる。先に、blog のデフォルトの書字方向が ltr の場合の例をあげ、次に rtl の場合の例を掲げる。none は何も対処しないとき、 data:blog.languageDirection は対処したときの表示だ:
    none
  1. 日本語اللغة العربية (123)
  2. اللغة العربية日本語 (123)
    data:blog.languageDirection
  1. 日本語اللغة العربية (123)
  2. اللغة العربية日本語 (123)
    none
  1. 日本語اللغة العربية (123)
  2. اللغة العربية日本語 (123)
    data:blog.languageDirection
  1. 日本語اللغة العربية (123)
  2. اللغة العربية日本語 (123)
[ヒント: マウスで文字列をいろんな始点からいろんな方向へドラッグしてなぞってみると、どういう順に字が繋がっているかがわかるよ。それから、アラビア語でも数字は左→右に書く。]

実は、私の使っているテンプレートにはこの多国語対応は実装されていた。しかし、余計なところで書字方向を指定するというバグ入りだったからそれは除去してある。このバグは、「書字方向によって括弧のグリフは自動的に反対向きになる」という知識のない人の仕業だった。「なぜ同じ向きの括弧が2つ現れるのか」を、かわいそうに、悩んだに違いない。ほらほら、日本語だって、横書きと縦書きで、テキストデータそのものは同じなのに、括弧(や、句読点などの約物)のグリフだけは自動的に置き換わるようになってるでしょ?

(日本語ブログに於ける需要、少なからむ…。)

意味があるんだかないんだか。(笑)

---

次に。

テンプレートを読んでいたら、それぞれの投稿 post 毎に data:post.timestampISO8601 という属性が参照できることが分かった。

上と同じクリボウさんのところに、投稿とか更新の時期で絞ってフィードを受けるパラメータが書いてあった。なるほど、 Blogger は ISO8601 での時刻表記を検索キーにしていたんだね。(書いたあとでわかった:実は、世の中のフィードと言われるもの全般がそうみたい。なにせ RFC3339 がある。汗)

さて、Blogger にはコンテンツの表示方法が3通りある。簡単に説明しておこう。

(1) index 表示: 「ホーム」、あるいは、「ホーム」から「前の投稿」「後の投稿」だけを踏んで辿り着く表示。コメントとバックリンクの内容は表示されない。この状態で「前の投稿」「後の投稿」を踏むとオーナーの設定した記事数で機械的に index 表示される。 (注: Blogger 関連の古い文献では index ではなく main 表示という名で同じものを呼んでいる。)

(2) item 表示: 1つの投稿への permalink (別のサイト上に書かれたリンクなど)、または、記事の最後にある「Links to this Post」とかいうやつ、「アーカイブ」の特定の1つの投稿へのリンク(オーナーが HIERARCHY モードに設定している場合に限って存在)のいずれかを踏んだ直後の表示。1つの投稿だけが表示され、コメントとバックリンクの内容が表示される。この状態で「前の投稿」「後の投稿」を踏むと1つの投稿だけが item 表示される。

(3) archive 表示: 「アーカイブ」「ラベル」の中から投稿の集合(実際には要素が1つかもしれない)を表すリンクを踏んだ直後、あるいはそこから「前の投稿」「後の投稿」だけを踏んで辿り着く表示。コメントとバックリンクの内容は表示されない。この状態で「前の投稿」「後の投稿」を踏むと元の分類になるべく沿って archive 表示される。

以上により、大昔の投稿を index 表示させるには「ホーム」から延々と遡る以外に方法は存在しないことが分かる。多大な努力が必要だ(笑)。他の表示にはどの表示からも、より簡単に辿り着ける。つまり、index 表示は他の表示の上流にある

今日は、その上下関係も解消してみた。

具体的には、 item 表示のみに存在する部分(コメントとバックリンクの内容の部分)の直上にを追加した(この素敵なアイコンそのものはヒトミンさん作成の素材だ。ありがとうございます)。このボタンは、 現在の item 表示を index 表示に切り替える機能を持つ。パッと見にはコメントとバックリンクの部分が縮むだけ(この blog に限っては一番上にもちょっと変化がある)。しかし、縮んだ後で「前の投稿」「後の投稿」を踏むと、 item 表示と index 表示では挙動が違う。

試してみよう: 場合1: この記事の直後にが見えているとき。あなたは今 item 表示だ。ボタンを押してみよう。 index 表示になり、ボタンが消える。

場合2: 記事の直後にボタンが無いとき。あなたは今 index か archive 表示だ。記事の上下にある投稿時刻、あるいは、記事の下の 「Backlinkとコメントを見る」を叩いてみよう(これは Blogger にもともとある機能だ)。 item 表示になり、ボタンが出現。

場合 1, 2 のそれぞれで、「もっと古い記事へ」とか「もっと新しい記事へ」というリンクも踏んでみると、違いがもっとよく分かる。

以下、プログラミングの細かい話。

このボタンを実装する際には「±1秒で挟んで自分自身を検索する」という方法をとった。 JavaScript で ISO8601 の時刻の加減算ルーチンを書く必要があったのだが、ぶいてくさんのところが参考になりました。ありがとうございました。

Blogger では投稿時刻を「分」の単位までしか指定できない。それにもかかわらず、検索のキーは「秒」の精度をもつ。これはおそらく、複数の投稿が同一時分になることがあると考えた仕様だ。だから、この部分で手を抜いて max-results=1 とやってはいけない: index 表示に変更したときに自分自身が検索結果から抜け落ちる可能性があるからだ。というわけで、実際のコードは以下だ。

<b:if cond='data:blog.pageType == &quot;item&quot;'>
<div>
<script type='text/javascript'>
var msToISO8601 = function (m) {
var sprintf = function (s) {
return (&#39;0&#39; + s).replace(/.*(..)/, &#39;$1&#39;);
}
var d = new Date();
d.setTime(m);
return (&#39;000&#39; + d.getUTCFullYear()).replace(/.*(....)/, &#39;$1&#39;) + &#39;-&#39; + sprintf(d.getUTCMonth() + 1) + &#39;-&#39; + sprintf(d.getUTCDate()) + &#39;T&#39; + sprintf(d.getUTCHours()) + &#39;%3A&#39; + sprintf(d.getUTCMinutes()) + &#39;%3A&#39; + sprintf(d.getUTCSeconds()) + &#39;Z&#39;;
}
var newdate = Date.parse(&#39;<data:post.timestampISO8601/>&#39;.replace(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}:\d{2}):(\d{2}|\d{2}\.\d+)([+-Z])(.*)$/, &#39;$1/$2/$3 $4 UTC&#39;)) + 1000*RegExp.$5;
if (RegExp.$6 != &#39;Z&#39;)
newdate -= Date.parse(&#39;1970/01/01 &#39; + RegExp.$7 + &#39; UTC&#39;)*parseInt(RegExp.$6 + &#39;1&#39;, 2);
document.write(&#39;&lt;a href=&quot;/search?&#39;);
document.write(&#39;updated-max=&#39; + msToISO8601(newdate + 1000));
document.write(&#39;&amp;&#39;);
document.write(&#39;updated-min=&#39; + msToISO8601(newdate - 1000));
document.write(&#39;&quot;&gt;&#39;);
document.write(&#39;&lt;img src=&quot;http://sites.google.com/site/onecotravel/icons/shut_01.gif&quot;/&gt;&#39;);
document.write(&#39;&lt;/a&gt;&#39;);
</script>
<span style='font-size:x-small;color:#999999;'>この下を閉じる</span>
</div>
</b:if>


(ソースコードを HTML 化するにあたり、 Peter Palfrader さんの Code to HTML converterの出力を現代風(?)に加工して使いました。特記して謝意を示します。Special thanks to Peter!)

これをテンプレートの
<b:includable id='post' var='post'>
の閉じタグ
</b:includable>
の直前にコピペすればよいはず。

この機能も需要が少なそう。でも、どっかから大昔の記事に飛んで来た人を、それに近い日付の記事たちにも手早く誘導できるのは確かだ。

index, item, archive の表示の仕方の区分は、実は、この作業が終わるまでぼんやりとしか理解してなかった。でも、分かってしまうと、仕様がよく練られているなあと、感心。 Blog にカレンダー(と、関係ないが、トラックバック機能も)は要らない。創造性豊かな Blogger の開発者たちに大拍手!

---
2009年3月11日14:24デバッグ: IE の JavaScript では substr() の引数に負数が使用できないことが判明 (IE7でもダメ)。しょうがないので、たとえば substr(-2) と書きたいところを replace(/.*(..)/, '$1') にした。
2009年3月13日16:02デバッグ: Unicode の正しい対応に誤りがあった。記事中の解説もそれに合わせて変更した。
2009年3月15日22:22デバッグ: UTC の地域で Blogger は data:post.timestampISO8601 に +00:00 を表す Z を使っていることが判明。正規表現を手直しした。
この下を閉じる このページを印刷

Comments 5

さんのコメント...

item から index に切り替えるソースコードで、余計なことをやっていたのを発見。

除去しました。

さんのコメント...

細かいことに気がついた: Navbar の検索ボックスを使った結果も archive 表示でしたね。

さんのコメント...

参照ありがとうございます!

さんのコメント...

>takezakiさん
いいえ、どういたしまして。

さんのコメント...

本日、Blogger の正式ガジェットとしてラベルクラウドが発表されました。よって、この記事に書かれた、ラベル毎のフィードをラベルリストに付けるという機能は、この blog で廃止しました。