こんにちは,五十嵐です.ソーシャル・ブックマークの心臓部分,ブックマークの登録部分を作っていきます.

ブックマークを登録する際には URL の他にタイトルを取得できると便利です.もちろん,タイトルが適切に付いていないページもありますので,自分で編集できることも条件になります.表示しているページをボタンひとつでブックマークできれば便利ですが,それは段階を追って,いずれ作ることにして,ここでは手で URL を入力して,そのページのタイトルを取得し,必要があればタイトルを編集した後,登録するという手順で作業できるようにします.これらが /personal のページで操作可能とします.
右図のように DHTML と非同期通信を使用した Ajax で,ページの切り替えをおこなわなくて済むようにデザインします.
詳細は省略しますが,ssbm.js にクロスブラウザ(複数のブラウザ対応)用の関数 _XMLHttpRequest を追加しました.
続いて,personal_center.tt に入力フォームと javascript を設定します.
root/template/personal/personal_center.tt フォーム部分:
<h2>ブックマーク登録</h2>
<form method="POST" action="/registbookmark"
id="registbookmarkform" name="registbookmarkform">
<input type="button"
id="bookmark_gettitle" name="bookmark_gettitle" value="タイトル取得">
<input type="reset"
id="bookmark_reset" name="bookmark_reset" value="リセット">
<input type="submit"
id="bookmark_submit" name="bookmark_submit" value="登録">
<table width="100%" border="0">
<tr><td>タイトル:</td>
<td>
<input type="text" size="40"
id="bookmark_title" name="bookmark_title" value="no title"></td>
</tr>
<tr><td>URL:</td>
<td>
<input type="text" size="40"
id="bookmark_url" name="bookmark_url" value=""></td>
</tr>
<tr><td>タグ:</td>
<td>
<input type="text" size="40"
id="bookmark_tags" name="bookmark_tags" value=""></td>
</tr>
<tr><td>コメント:</td>
<td>
<input type="text" size="40"
id="bookmark_comment" name="bookmark_comment" value=""></td>
</tr>
</table>
</form>
javascript の部分:
var httpObject;
var timer_id;
var timeout_sec = 10;
function checkTimeout(){
if( --timeout_sec <= 0 ){
clearInterval( timer_id );
httpObject.abort();
alert( 'Timeout' );
return false;
}
}
function requestTitle( url, func ){
httpObject = _XMLHttpRequest();
if( ! httpObject ){
alert('お使いのブラウザには対応していません.');
return false;
}
timer_id = setInterval( 'checkTimeout()', 1000 );
httpObject.open( 'GET', '/gettitle?bookmark_title=' + url, true );
httpObject.onreadystatechange = function () {
if( httpObject.readyState == 4 ){
clearInterval( timer_id );
if( httpObject.status == 200 ){
func( httpObject.responseText );
}else{
alert( httpObject.readyState + ':'
+ httpObject.status + ':'
+ httpObject.statusText );
return false;
}
}
}
httpObject.send('');
}
function getTitle( url ){
if( url == "" ){
return;
}
var funcRef = function ( title ) {
var newtitle = title;
if( newtitle == '__no_title__' ){
newtitle = 'no title';
}
_getElementById('bookmark_title').value = newtitle;
}
requestTitle( url, funcRef );
}
document.registbookmarkform.bookmark_gettitle.onclick = function(){
var url = document.registbookmarkform.bookmark_url.value;
if( url == "" ){
alert( 'URL を入力してください.' );
return false;
}
getTitle( url );
}
httpObject.onreadystatechange へ設定した匿名関数の中で,"this" を使いたかったのですが,firefox では動かなかったので,httpObject をそのまま使用しました.W3C のサンプルには,"this" で記述されているのですが... ( 「
The XMLHttpRequest Object」 (W3C) 参照)
サーバ側の '/gettitle' のコードを追加します.LWP::Simple::get() を使用して,指定された URL にアクセスし,タイトルを取得します.
lib/SecureSBM/Controller/Personal.pm
sub _gettitle : Private {
my $url = shift;
my $title = '';
if( my $content = LWP::Simple::get( $url ) ){
my ( $tmpt ) = $content =~ m{<title>([^<]*)</title>}i;
$title = Jcode::jcode($tmpt)->utf8;
}
return $title;
}
sub gettitle : Path('/gettitle') {
my ( $self, $c ) = @_;
my $url = $c->req->param('bookmark_title');
my $title = '';
if( $title = _getBookmarkTitle( $c, $url ) ){
$c->log->debug('*** already url exists ');
$c->res->body( $title );
return 1;
}
$title = _gettitle( $url );
if( $title eq '' ){
$title = '__no_title__';
}
$c->res->body( $title );
}
_getBookmarkTitle() でブックマークが既に登録されているかどうかを確認しています.body に空文字が設定されると,end アクションでテンプレートが呼ばれてしまうので,'__no_title__' という文字を入れて回避しています.javascript 側でも '__no_title__' という文字を受け取った場合の処理を行っています.
次回は "/registbookmark" のアクションを lib/SecureSBM/Controller/Personal.pm に追加します.今回もだいぶ長くなってしまったので,コードは次回以降にしますが,ブックマークは他の人とも共有しますので,既に存在している場合に注意しなければなりません.
2007/03/27 記
参考:
Keyword: Perl Catalyst Secure-SBM SSBM セキュア・ソーシャル・ブックマーク