2008-06-30

Jaxer のエラーハンドリング runat="server" 編

サーバサイドでエラーが起きたとき、Aptana Jaxer がどのように振る舞うか調べてみましたので、その結果をお伝えします。Jaxer でサーバサイドのコードを実行するタイミングには runat="server" と runat="server-proxy" がありますが、今回は runat="server" を対象とします。

サーバサイドでエラーが発生するとは、つまり JavaScript の例外が発生すると同じです。そこで、次のとおり、サーバサイドで例外をスローするコードを用意しました。

<script type="text/javascript" src="jquery.js" runat="both"></script>
<script type="text/javascript" runat="server">
//<![CDATA[
jQuery(function($) {
throw 'ERROR!';
});
//]]>
</script>

そして、このサーバサイドのコードを実行すると、次のようなエラーページを表示し、そのエラーの原因がメッセージで示されます。このメッセージは、デバッグに役立ちます。このとき、ページのレンダリングは継続するので、その流れでクライアントサイドのコードも実行されることになります。



このサーバサイドのエラーメッセージを表示しないという選択もできます。そのときは、Config.UNCAUGHT_ERRORS_ARE_RESPONSE_ERRORS = false; とします。

次のような外部ファイルのインクルードに失敗したときも、エラーメッセージを表示しますが、Config.INCLUDE_ERRORS_ARE_RESPONSE_ERRORS = false; とすることで、インクルードのときのエラーメッセージのみ表示しないという選択もできます。

<jaxer:include src="jaxer-include/foo.html"></jaxer:include>
公開して運用するときには、上記のエラーメッセージを表示したり、継続して実行したりすると不都合があります。そのときは、Config.DISPLAY_ERRORS = false; とすることで、固定のエラーページを表示し、クライアントサイドのコードを実行しないようにできます。

固定のエラーページとして、Config.RESPONSE_ERROR_PAGE か Config.FATAL_ERROR_PAGE で指定したファイル(または文字列)の内容が表示されるはずなのですが、なぜか、次のような Jaxer のエラーページが表示されてしまいます。



Jaxer の不具合か環境か原因は把握できていません。ここで試した Jaxer のバージョンは 0.9.7.2472 Windows XP です。

2008-06-29

Jaxer.setEvent を使ってサーバサイドでイベントを指定する

Aptana Jaxer でイベントをサーバサイドで指定したとき、クライアントサイドでそのイベントが有効になるのか、有効なときどう振る舞うのか、いろいろなパターンを試してみました。

サーバサイドで onclick プロパティに Function を指定してみましたが、クライアントサイドでは動作しませんでした。

<script type="text/javascript" src="jquery.js" runat="both"></script>
<script type="text/javascript" runat="server">
//<![CDATA[
jQuery(function($) {
var element = $('#r')[0];
element.onclick = function() {
alert('bar1');
});
});
//]]>
</script>
<div id="r">foo</div>

サーバサイドで setAttribute を使って onclick に JavaScript コードを指定してみたところ、クライアントサイドで期待どおり動作しました。

jQuery(function($) {
var element = $('#r')[0];
element.setAttribute('onclick', 'alert(\'bar2\');');
});

サーバサイドで addEventListener を使って onclick に Function を指定してみましたが、クライアントサイドでは動作しませんでした。

jQuery(function($) {
var element = $('#r')[0];
element.addEventListener('click',
function() { alert('bar3'); },
false);
});

つまり、属性値として指定したイベントのみが対象ということです。サーバサイドの DOM をシリアライズして、クライアントサイドの HTML をレンダリングするという過程から捉えると、あたり前の結果といえます。

Jaxer.setEvent メソッドを使うと、もう少し直感的にイベントを指定できます。ただし、上記の仕組みを変えるものではなく、あくまでもヘルパメソッドですよ。

サーバサイドで Jaxer.setEvent を使って onclick に Function を指定してみたところ、クライアントサイドで期待どおり動作しました。

jQuery(function($) {
var element = $('#r')[0];
Jaxer.setEvent(element, 'onclick', function() {
alert('foo1');
});
});

サーバサイドで Jaxer.setEvent を使って onclick に JavaScript コードを指定してみたところ、クライアントサイドで期待どおり動作しました。

jQuery(function($) {
Jaxer.setEvent(element, 'onclick', 'alert(\'foo2\');');
});

サーバサイドで Jaxer.setEvent を使って、イベントから変数を参照してみましたが、undefined になりました。このときの foo は、サーバサイドではなく、クライアントサイドの foo を参照することになります。
jQuery(function($) {
var foo = 'foo4';
Jaxer.setEvent(element, 'onclick', function() {
alert(foo);
});
});

ですので、クライアントサイドに foo という Function を定義し、サーバサイドで foo を呼び出すようにイベントを指定することができます。

<script type="text/javascript" src="jquery.js" runat="both"></script>
<script type="text/javascript" runat="server">
//<![CDATA[
jQuery(function($) {
Jaxer.setEvent(element, 'onclick', 'foo();');
});
//]]>
</script>
<script type="text/javascript">
//<![CDATA[
function foo() {
alert('foo5');
}
//]]>
</script>
<div id="r">foo</div>

これまでの結果から、サーバサイドで jQuery.fn.click (jQuery.fn.bind) を指定しても、期待どおり動作しないことは自明です。jQuery はイベントの状態を jQuery オブジェクトが保持するため、その状態クライアントサイドで失われます。

jQuery(function($) {
$('#r').click(function() {
alert('foo3');
});
});

最後に参考として、Jaxer.setEvent のソースコードを抜粋します。ハンドラが文字列のときはそのまま、Function のときは文字列に変換してから setAttribute を使って指定しているだけでした。

var attribute;
if (typeof handler == "function")
{
if (handler.name == "")
{
attribute = "(" + handler.toSource() + ")()";
}
else
{
attribute = handler.name + "()";
}
}
else // handler should be a string (the handler function's body)
{
attribute = handler;
}
domElement.setAttribute(eventName, attribute);

Function.toSource メソッドを積極的に使ったコードをはじめてみた気がしますが、この使い方は妥当なんだろうか?という小さな疑問が残りました。

2008-06-28

Jaxer.clientData を使ってサーバサイドの状態をクライアントサイドに引き渡す

非 Ajax の一般的な WEB アプリケーションは、リンクのパスや QUERY_STRING、フォームの値を使って、サーバサイドの状態をクライアントサイドに引き渡しています。

リンクやフォームを使って状態を引き渡すという仕組みは、あたり前になり過ぎていて、その意味や必要性をよく考えなくなってしまう傾向があるのですが、Ajax アプリケーションを開発すると、その意味や必要性と対面せざるを得ません。

みなさんの Ajax アプリケーションは、どのような仕組みを使って、サーバサイドの状態をクライアントサイドに引き渡していますか。いろいろな方法がありますよね。

そのひとつとして Aptana Jaxer は、Jaxer.clientData を介して、サーバサイドのオブジェクトをクライアントサイドに引き渡すという固有の仕組みを提供しています。

次のコードがその実例です。サーバサイドで Jaxer.clientData.foo の値を指定すると、クライアントサイドでは、その値を同じ Jaxer.clientData.foo から取得できます。
<script type="text/javascript" src="jquery.js" runat="both"></script>
<script type="text/javascript" runat="server">
//<![CDATA[
jQuery(function($) {
Jaxer.clientData.foo = 'bar';
});
//]]>
</script>
<script type="text/javascript">
//<![CDATA[
jQuery(function($) {
$('#r').text(Jaxer.clientData.foo);
});
//]]>
</script>
<div id="r">foo</div>

この仕掛けは、そても単純なものでした。Jaxer がクライアントサイドのページをレンダリングするとき、次のように script 要素を使って Jaxer.clientData を生成するだけです。Jaxer.clientData の値は、サーバサイドの Jaxer.clientData を JSON stringify したものです。

<script>
Jaxer.clientData = Jaxer.Serialization
.fromJSONString('{\"foo\":\"bar\"}');
</script>

私も Ajax アプリケーションを書くとき、同じようなことをよくやってました。そのときは、サーバサイドは JavaScript じゃないので、JSON stringify する(している)という変換の意識がどっかにあるのですが、

サーバーサイドもクライアントサイドも Jaxer.clientData で操作できると知ったとき、えっ!? どんな特別な仕掛けを使っているんだろうと勘ぐってしまいました。結果としては、同じことをしているだけだったのです。Jaxer の直感的なインタフェースに惑わされました。

jQuery Chili のレシピを静的ロードする方法

jQuery Chili 2.0 は、シンタックスハイライトのレシピを php.js や js.js のように外部ファイル化しています。そして、そのファイルが必要になる時点で、次のように jQuery.getJSON メソッド (XHR) を使って動的ロードし、code 要素に適用しています。

$.getJSON( path, function( recipeLoaded ) {
book.recipes[ path ] = recipeLoaded;

自らのサイトに WEB ページと jQuery Chili をホストするときは不都合ないのですが、この blogspot.com のようなブログの WEB ページに対して、他でホストした jQuery Chili を使おうとすると、XHR のクロスドメイン制約のために、前述のレシピを動的ロードできずエラーになります。

こういう状況のときは、jQuery Chili の動的ロードを無効にして、あらかじめレシピを指定しておくという対策ができます。この対策を説明したサイトが見つからなかったので、ここでお伝えします。

次のように jquery.chili-2.0.js の後に recipes.js を指定してロードします。

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javaScript" src="chili/jquery.chili-2.0.js"></script>
<script type="text/javaScript" src="chili/recipes.js"></script>

recipes.js は、次のようになっています。recipeLoading プロパティを false にして、レシピの動的ロードを無効にしています。そして、php.js、html.js、js.js、css.js のように、レシピのファイル名をキーに、レシピの記述をそのまま指定しています。

ChiliBook.recipeLoading = false;
ChiliBook.recipes[ "php.js" ] = { ... };
ChiliBook.recipes[ "html.js" ] = { ... };
ChiliBook.recipes[ "js.js" ] = { ... };
ChiliBook.recipes[ "css.js" ] = { ... };

recipes.js には PHP、HTML、JavaScript、CSS のレシピが指定してあります。 不要なレシピがあれば削除してしまえばよく、別なレシピが必要であれば、レシピのファイル名をキーに、そのレシピのファイルの内容を指定すればよいです。レシピのファイルは JSON 形式になっているので、上記の { ... } の部分を置き換えるだけです。

2008-06-26

Dreamweaver Extensionの開発にチャレンジしてみる (その2)

Dreamweaver CS3の体験期間が過ぎてしまい記事の確認ができなくなってしまうという何とも情けない状態に陥っていたのですが、何とか確認環境を整えたので続きを投稿しますw

前回はmicroformats拡張機能を参考にmxiファイルを作るところまででした。ではまず作成したmxiファイルの中身を簡単に説明します(※)。

※ファイルフォーマットの詳細が知りたい方は「The Extension Instration File Format」を参照してください。
<macromedia-extension name="Aiueo" version="0.1.0" type="Suite">
<author name="aquilegia" />
<products>
<product name="Dreamweaver" version="9" primary="true" />
</products>
<description><![CDATA[
あいうえお機能拡張。
]]></description>
<ui-access><![CDATA[
「ヘルプ」メニューから「Aiueo.htmlを開く」を選択して実行する。
]]></ui-access>
<license-agreement><![CDATA[
]]></license-agreement>
<files>
<file source="Aiueo.html" destination="$dreamweaver\Configuration\Menus\Aiueo\" />
</files>
<configuration-changes>
<menu-insert insertAfter="DWMenu_Help_About">
<separator />
<menuitem id="DWMenu_Help_Aiueo" name="Aiueo.htmlを開く"
enabled="true" file="Menus/Aiueo/Aiueo.html" />
</menu-insert>
</configuration-changes>
</macromedia-extension>

このファイルはXML形式でmacromedia-extensionタグをルート要素に拡張機能の情報を記述しています。中には日本語を含めることができ、今回はWindows-31Jで保存したところencoding属性を指定しなくても文字化けすることなく表示されました。

ルート要素のname属性、version属性と子要素として追加したauthor要素、description要素、ui-access要素、license-agreement要素はAdobe Extension Managerで拡張機能をインストールした際に表示される情報のようで、今回は適当な内容です。

重要なのはproducts要素、files要素、configuration-changes要素です。
products要素にはどのAdobe製品の拡張機能をサポートしているかを書きます。今回はDreamweaver CS3(バージョン9)なので「<product name="Dreamweaver" version="9" primary="true" />」と書きました。primary属性はオプションで、今回指定したプロダクトは一つなので付けなくても問題ないです。version属性は間違えると拡張機能をインストールする際にAdobe Extension Managerに怒られます。試しにversion属性に10を指定してインストールすると次のダイアログが表示されました。


次のfiles要素は「この拡張機能はこれらのファイルを使ってますから、拡張機能ファイル(xmp)を作る際は取り込んでくださいね。」というもので、files要素の配下にfile要素で使用ファイルを書いておくと、拡張機能ファイルを作成する際に取り込んでくれます。今回はAiueo.htmlファイルを作ったのでそれを書きました。
最後にconfiguration-changes要素ですが、これが一番厄介でした。microformats拡張機能はバーに項目を追加してますが、メニューには追加していないのでそのまま真似ることができず、しょうがないので説明書(The Extension Instration File Format)を眺めたところ、configuration-changes要素の下にはmenu-insert要素を書けることがわかり、そこから順々に調べていってメニュー項目を追加する設定を書くことができました。ポイントはmenu-insert要素のinsertAfter属性で、この属性には追加したい場所の直前の項目IDを設定する必要があるのですが、どうやって調べてよいのかわかりませんでした。その為、一度この属性に適当な値を指定して拡張機能をインストールし、以下のパスにMenus.xmlというDreamweaverのメニュー構成ファイルが出力されるので、その中身からIDを取得しました。
C:\Documents and Settings\(ログインユーザ)\Application Data\Adobe\Dreamweaver 9\Configuration\Menus\Menus.xml

今回は「ヘルプ(H)」メニューの一番下に追加するので、直前の項目IDは"DWMenu_Help_About"(「Dreamweaver について(_A)」)を設定。

これで拡張機能情報ファイルの作成は終わりです。次は実行するHTMLファイルを作成します。
<html>
<head>
<title>Aiueo</title>
<script language="javascript">
function canAcceptCommand(){
return true;
}
function receiveArguments(){
alert("Aiueo");
}
</script>
</head>
<body>
</body>
</html>

HTMLファイルにはscript要素を追加し、二つの関数を定義しています。canAcceptCommand関数はメニューを選択した際にreceiveArguments関数を呼び出すかどうかを判定する関数です。今回は必ず呼び出すので常に true を返しています。receiveArguments関数にはメニューを選択したときに実行させたい処理を記述します。今回は"Aiueo"と表示する処理を書きました。このファイルを「Aiueo.html」の名前で保存すればHTMLファイルの作成は終了です。

次は作成した二つのファイル(拡張機能情報ファイルとHTMLファイル)を同じディレクトリに置き、Adobe Extension Managerを使って次の手順で拡張機能ファイルを作成します。
  • Adobe Extension Managerを起動。
  • メニューから「ファイル(F)」->「拡張機能の作成(C)」を選択。
  • 表示されたファイルダイアログで作成したmxiファイルを開く。
  • 拡張機能ファイルの保存先を聞かれるので適当な場所へ保存する。

最後に「拡張機能ファイルが正常に作成されました」と表示されれば成功です。下の画像はAdobe Extension Managerを起動したところです。


次は作成した拡張機能を次の手順でDreamweaverへインストールします。
  • Adobe Extension Managerを起動。
  • メニューから「ファイル(F)」->「拡張機能をインストール(I)」を選択。
  • 拡張機能ファイルの選択ダイアログが表示されるので作成したmxpファイルを指定する。
  • 免責事項が表示されるので「承諾する(A)」ボタンを押下。

最後に「拡張機能'Aiueo'のインストールが正常に終了しました」と表示されれば成功です。下の画像はインストールを終えた後のAdobe Extension Managerです。


いよいよDreamweaverの起動です。Dreamweaverを起動して、メニューから「ヘルプ(H)」->「Aiueo.htmlを開く」を選ぶと「Aiueo」とダイアログ表示されます。



一度インストールしてしまえば、インストール先のAieuo.htmlファイルを編集することで手軽に色々と試すこともできます(※変更後二度呼び出さないと反映されませんが・・・)。
C:\Documents and Settings\(ログインユーザ)\Application Data\Adobe\Dreamweaver 9\Configuration\Menus\Aiueo\Aiueo.html

以上でDreamweaver Extensionの開発は終了です。色々と躓くことが多かったですが、拡張機能情報ファイルから拡張機能を作成する方法はWeb上であまり見かけなかったので参考になれば幸いです。

Jaxer サーバサイド window.onload のハンドリングいろいろ

Aptana Jaxer で、サーバーサイドでの window.onload イベント相当をハンドリングする方法はいろいろあります。Jaxer 固有の方法と、クライアントサイドの一般的な方法を試してみましたので、その結果をお伝えします。ここで試した Jaxer のバージョンは 0.9.7.2472 です。

body 要素の onserverload 属性を使う Jaxser 固有の方法です。もちろん期待どおり動作します。
<body onserverload="load();">
<script type="text/javascript" runat="server">
//<![CDATA[
function load() {
document.getElementById('r').innerHTML = 'bar';
}
//]]>
</script>
<div id="r">foo</div>
window オブジェクトの onserverload イベントを使っても、期待どおり動作しました。
<script type="text/javascript" runat="server">
//<![CDATA[
window.onserverload = function() {
document.getElementById('r').innerHTML = 'bar';
}
//]]>
</script>
<div id="r">foo</div>
window オブジェクトの onload イベントを使ってみましたが、期待どおり動作しませんでした。Jaxer のドキュメントを読んだ感じだと、onserverload と同じ振る舞いをすると読み取れるのですが、実際は違うようです。
<script type="text/javascript" runat="server">
//<![CDATA[
window.onload = function() {
document.getElementById('r').innerHTML = 'bar';
}
//]]>
</script>
<div id="r">foo</div>
addEventListener を使って DOM ContentLoaded イベントを捕捉してみたところ、期待どおり動作しました。
<script type="text/javascript" runat="server">
//<![CDATA[
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('r').innerHTML = 'bar';
}, false);
//]]>
</script>
<div id="r">foo</div>
DOM ContentLoaded イベントが使えるならと思い、jQuery.ready を試してみたところ、期待どおり動作しました。このとき、jQuery.browser.mozilla はちゃんと ture を示していました。
<script type="text/javascript" src="jquery.js" runat="both"></script>
<script type="text/javascript" runat="server">
//<![CDATA[
jQuery(function($) {
$('#r').text('bar');
});
//]]>
</script>
<div id="r">foo</div>
Mozilla を意識しない window.onload に依存した JavaScript ライブラリなどは、Jaxer のサーバーサイドでの window.onload イベント相当を扱えないかもしれませんね。

2008-06-24

jQuery のチートシート jTouch を iPod touch と iClooly で

jQuery 1.2.3 のリファレンスをチートシートとしてまとめて、いつでもどこでも iPhone や iPod touch から見てしまおうという WEB サイトがあることを知りました。

jTouch - Color Charge
A touchable jQuery Cheat Sheet in your pocket, accessible anywhere. Built for iPhone and iPod Touch, it also works great on any W3C Standards compliant browser or mobile devices with built-in Internet access.
振り返って思い起こしてみると、ふと電車の中でアイディアが浮かんだとき、これ jQuery で簡単にできたっけ?と確認したくなることがあります。同じように、寝ころんで技術書などを読んでるときも、あれ jQuery だとどうしてたっけ?と気になったりします。

ただ iPod touch だと、電車で移動するなど、無線 LAN が使えないと使えなかったりするのが欠点だったりしますね。チートシートというので、1ページにすべて収まっているかと思ったのですが、項目を選択するとアクセスが発生しているようなので、ネットワークに繋がらない環境では使えないようです。

↓jTouch を iPod touch の Safari で表示した様子です。Dreamweaver CS3 でコーディングしながら参照したら便利かなと試してみましたが、PC の WEB ブラウザで見るほうがはるかに手軽でした。失敗です。



写真の iPod touch は iPod touch アルミスタンド iClooly という iPod touch 専用のスタンドで立てかけたものです。超小型のマルチモニタみたいに見えるのが、ちょっとかわいいところです。

ROCKRIGESOUND iPod touch用アルミスタンド iClooly[あいくるぅりー] RSJ-ICRT01

が、実際のところ、持ち運ぶときの取り外しが手間ですし、モニタの横においても、WEB サイトの動作チェックくらいにしか使わないので、値段の割りにはあんまり役立っていません。質感がいいなぁや面白そうだなぁというのは、購入するときまでの尺度だと、あらためて実感して、無駄使いを反省するのでした。

2008-06-23

今までに生成された The geo microformat を CARWINGS-CASTING するようにしてみた

The geo microformat 生成ツール を改良して、今までに生成された The geo microformat を RSS 2.0 形式でフィードするようにしました。さらに、そのフィードに CARWINGS 情報端末向けの CARWINGS-CASTING のタグセットを付与するようにもしました。

CARWINGS-CASTING は、自動車(カーナビ)をインターネットに繋げて、自動車にインターネットの情報を配信するための仕組みを提供するものです。いわゆるテレマティクスサービスの一種です。

CARWINGS-Lab
CARWINGS-CASTINGは、RSS2.0をコンテナとして、CARWINGS情報配信向けに拡張されたタグセットを用いることでCARWINGS対応端末に位置などの付加情報を配信する方法です。
CARWINGSセンターから送信するパラメータ(車の現在位置など)に連動して動的にCARWINGS-CASTINGを生成することにより車の状況に応じた情報配信が可能です。
さらに、CARWINGS-CASTINGに含まれる緯度経度情報は、CARWINGS対応ナビゲーションの目的地に設定できたり、同じく電話番号はハンズフリーで発呼できるなど、ドライブ中のユーザに適した情報配信が可能です。
とのことです。

なんだか面白そうで、何かに役立ちそうな予感がしたので、手始めに The geo microformat 生成ツールを改良して、次のようなフィードを配信するようにしてみました。

http://developmentor.lrlab.to/postal/microformats/geo?alt=rss
<item>
<title>東京タワー</title>
<link>http://.../microformats/geo/35.658587,139.745428,15</link>
<description>35.658587, 139.745428</description>
<georss:point>35.658587 139.745428</georss:point>
<!--carwings-->
<carwings:readtitle>東京タワー</carwings:readtitle>
<carwings:readtext>35.658587, 139.745428</carwings:readtext>
<carwings:lat>35.658587</carwings:lat>
<carwings:lon>139.745428</carwings:lon>
<carwings:data><![CDATA[
東京タワー<br />
]]></carwings:data>
<carwings:tel>00-0000-0000</carwings:tel>
<!--<carwings:address></carwings:address>-->
<!--<carwings:mail></carwings:mail>-->
<carwings:link>
http://.../microformats/geo/35.658587,139.745428,15
</carwings:link>
<!--/carwings-->
</item>
CARWINGS-CASTING の配信を受けるには、CARWINGS 対応のカーナビが必要です。また、CARWINGS 対応のカーナビは、原則、日産自動車のディーラーオプションとしてしか購入できないようです。

ですが、そんなひとのためにか、CARWINGS エミュレータ という WEB アプリケーションが用意されているので、そのエミュレータを使って、前述したフィードの動作確認をしてみました。

↓がエミュレータのトップページです。このページの地図を使って、自動車の現在地を指定します。現在地は、住所を指定して移動できるようになっています。そして、フィードの URL を指定して、送信ボタンをクリックすると、カーナビの画面が表示されます。

カーナビでは、現在地のほか、目的地、経由地(最大5箇所)、進行方向、進行速度をリクエストパラメータとして、フィードを生成する CGI プログラムに引き渡されるとのことです。ですが、エミュレータは、現在地のみしか扱えないようです。



↓カーナビの画面に item 要素の内容が表示されます。送るやキーボードの上下を使って、item を移動できます。

吹き出しの中身は、音声による読み上げを表しています。carwings:readtitle 要素と carwings:readtext 要素が読み上げの対象です。省略したときは title 要素と description 要素が対象になりますが、読み上げ精度を保つなら、前者の要素に、機械が読み上げしやすいテキストを指定することになります。

carwings:lat 要素と carwings:lon 要素が含まれると、旗のアイコンが表示されます。変わりに georss:point 要素を指定してみましたが、なぜか認識されませんでした。エミュレータと仕様にギャップがあるようです。また、carwings:tel 要素が含まれると、電話のアイコンが表示されます。



↓カーナビの画面には carwings:data 要素の内容が表示されます。限られた HTML タグしか使えませんが、テキストのほかに画像も表示できます。また、carwings:link 要素が含まれると、その URL を表す QR コードが画面に重なる形で表示されます。カーナビと携帯電話などの接点に使えそうです。



読み上げ停止をクリックすると、次のようにメニューが切り替わります。そして、ここに行くをクリックすると、carwings:lat 要素と carwings:lon 要素を目的地に設定するようです。ただ、このエミュレータは、カーナビの機能はエミュレートしないので、あくまでもイメージです。



電話するをクリックすると、carwings:tel 要素の値がメッセージボックスに表示されます。



詳細を見るをクリックすると、title 要素と description 要素の値が表示されます。



現在地表示をクリックすると、現在地を中心とした地図が表示されます。ただ、原因は把握していませんが、フィードが含む位置情報が、あまりにも広域(日本以外など)だと正しく地図が表示できないようです。



今回は、現在地に関わらずフィードを生成していますが、これをエミュレータが送信した現在地位の周辺にしぼってフィードを生成するようにすれば、単なる情報配信を超えた何かが実現できそうです。

でも、このエミュレータだけでは、とても物足りない気がします。音声による読み上げとか、地図をクルージングしながら定期的にフィードを取得できたりするとよいですね。さすがに日産車を購入するにもいかないので、日産車以外にも門戸を開くようなそんなことはできないのかなぁ。何が制約になっているのだろう。

2008-06-22

Postal Search Ajax API 1.1.0 リリース! 新 API jQuery.fn.codable など

本日(6月22日)、Postal Search Ajax API 1.1.0 をリリースしました。合わせて Postal Search Ajax API 構築キットもリリースしましたので、アーカイブをダウンロードして、必要に応じて差し替えてください。

(1) jQuery.fn.codable メソッド

jQuery.fn.codable メソッドを使って、テキストボックスを拡張して、住所の入力を支援できるようにしました。いわゆるサジェストと呼ばれるものです。

テキストボックスに住所の単語を入力すると、その単語を含む住所を検索し、その結果を入力候補としてリスト表示します。入力候補を選択すると、その住所をテキストボックスに設定します。入力候補の選択は、マウスのほかにキーボードも使えます。

jQuery.fn.codable メソッドのデモは 住所の単語から住所の候補をサジェスト表示する #3を、詳しい仕様は Postal Search Ajax API リファレンス を見てください。

(2) jQuery dimensions プラグイン

jQuery.fn.codable メソッドの追加に伴い、Postal Search Ajax API の中に jQuery dimensions プラグイン を含めて配布するようにしました。

(3) Postal.Coder クラス (jQuery coder プラグインを含む)

今まで Postal.Coder クラスの中で、指定した住所の単語中の空白(全角を含む)を除去してから、郵便番号を検索していましたが、今回のバージョンから空白を除去せず、指定したそのまま検索するようにしました。

住所の単語中の空白を自動的に除去してしまうと、Postal.Coder クラスの利用者から見たとき、その結果が期待と異なることがあるという指摘によるものです。空白の除去を必要とするときは、Postal.Coder クラスを呼び出す前に空白を除去するようにしてください。

(4) jQuery.fn.coder(Function fn)

選択した要素の値を住所の単語とし、その住所の単語の郵便番号を検索できるようにしました。詳しい仕様は Postal Search Ajax API リファレンス を見てください。

(5) Firefox 3

Firefox3 の正式リリースに伴い、今回から Firefox3 もテストするようにし、期待どおり動作することを確認しています。

2008-06-15

autocomplete の指定で Firefox が記憶喪失になるのを防ぐ方法

大抵の WEB ブラウザは、フォームに入力した内容を記憶しておいて、次回からその内容を補完したり選択できる機能を持っています。

WEB ブラウザの利用者から見て、この機能はたいへん便利なものなのですが、サイトの運営者は様々な理由から、この機能がなるべく無効になるように、次のように input 要素の autocomplete 属性を off にすることがあります。
<input type="text" name="c" value="" autocomplete="off" />
autocomplete 属性なんですが、WEB ブラウザの既定の振る舞いが変わってしまうという副作用を持っています。IE6、Opera9、Safari3.1 (共に Windows XP)は期待どおりなのですが、Firefox2 (Windows XP) だと、フォームに値を入力して submit して、その後、戻るボタンでフォームに戻ると、入力していたハズの値が空欄になってしまいます。

これだと、戻るボタンで戻って入力しなおすという期待をしているページ遷移が機能しないことになります。もしかすると、autocomplete 属性の副作用に気が付かずにサイトを運営しているケースもあるのかもしれません。

まず、基本は autocomplete 属性は使わないのが正解じゃないかという立場です。そして、どうしても autocomplete 属性を指定したいときは、HTML に埋め込まず、次のように JavaScript を使ってコントロールすれば、副作用の不都合を回避できることがわかりました。

IE6、Firefox2、Opera9、Safari3.1 (共に Windows XP)で動作を確認しました。
<script type="text/javascript">
jQuery(function($) {
var c = $('#c')
.attr('autocomplete', 'off');

// window.unload
$(window).unload(function() {
c.removeAttr('autocomplete');
});
});
</script>

<form method="post" action="./example.cgi">
<input id="c" type="text" name="c" value="" />
<br />
<input type="submit" name="submit" value="go" />
</form>
ページをロードした直後に autocomplete 属性を off にします。また、ページをアンロードする(つまり、ページを遷移する)直前に autocomplete 属性を削除します。

2008-06-10

Postal Search Ajax API の新しい組み込み方法を追加しました

本日(6/10)、Postal Search Ajax API (本 API) の新しい組み込み方法を追加しました。

従来は、Postal Search APIs & Solutions のサーバに 本 API の script ファイルとデータをすべて預けるか、もしくは、Postal Search Ajax API 構築キット を使って、あなたの WEB サーバに 本 API の script ファイルとデータをすべて格納するかの2通りの選択しかありませんでした。

今回は、上記の2通りに加えて、あなたの WEB サーバに API の script ファイルを格納し、Postal Search APIs & Solutions のサーバにデータを預ける という選択をできるようにしました。

http://developmentor.lrlab.to/... という URL を見せたくないときは、あなたの WEB サーバに、本 API の script ファイルを格納して使うことができます。postalua.js をダウンロード して、あなたの WEB サーバに postalua.js を格納します。そして、その postalua.js を読み込むための script タグを貼り付けます。
<script type="text/javascript" src="postalua.js"></script>
ただ、あなたの WEB サーバに script ファイルを格納して使うとき、本 API がバージョンアップしても自動アップデートすることはありません。本 API がバージョンアップしたときは、最新の postalua.js をダウンロードして差し替える必要がある ... というデメリットがあります。

また、今回から同時に、住所のデータを Amazon Simple Storage Service (Amazon S3) を使って、Amazon のデータセンタで運用するようにして、信頼性を高めました。本 API の使い方やインタフェースに変更はありませんので、修正の必要はありません。今までと同じように使ってください。

2008-06-09

『jQueryで作るAjaxアプリケーション』 6月19日販売 予約開始

4774134902

jQueryで作る Ajaxアプリケーション という本が 6月19日に発売されることを知りました。Amazon で予約できるようになってます。発行元の技術評論社の紹介ページ に Amazon よりも詳細な目次が、さらに、Chapter 3 HTML要素の指定とCSSプロパティの操作 のサンプル PDF もあります。

手にとって読んではいませんが、ざっと目次を見たところ、次のように jQuery UI も扱っているので、どのように紹介しているのか、実用的な使い方の提案まで含むのか、といったことが気にかかります。

Chapter 10 jQuery UIの基本とマウスによる要素の操作
Chapter 11 要素の並べ替えとドラッグ&ドロップ
Chapter 12 jQuery UIによる画面コンポーネント[1]
Chapter 13 jQuery UIによる画面コンポーネント[2]

過去の連載などをまとめたものかなと、同サイトを探してみましたが、jquery.jsを読み解くjQueryではじめるAjax とは著者が違うようです。

上記も含めて関心がありますので、後日、手にとって確認してみます。

2008-06-08

Picasa ウェブアルバムの画像から The geo microformat を生成できるようにしました

Picasa Web Albums Data API を使って画像のジオタグを取得する
Picasa や YouTube のフィードは、Google Data API の上で成り立っているので、YouTube と同じく Picasa のフィードも、画像が位置情報を持つときは、GeoRSS を使ってその位置情報を表現します。
以前に Picasa ウェブアルバムの画像から位置情報を取得する方法を調べました。いずれどこかで使ってみようと考えていましたが、ちょうど時間ができたので、The geo microformat 生成ツール を改良し、Picasa ウェブアルバムの画像から位置情報を取得し、その位置情報から The geo microformat を生成できるようにしました。

http://picasaweb.google.co.jp/picasateam/CambridgeUK/photo#5114585391693704978 といった Picasa ウェブアルバムの URL を入力し、目的地を検索するボタンをクリックすると、次のように、その画像から位置情報を取得できるようにしました。



続けて The geo microformat を生成するボタンをクリックすると、HTML コードが生成されるのは、今までどおりです。

次のように、Picasa ウェブアルバムから生成した The geo microformat は、Picasa のアイコンから判断できるようにしてあります。



なお、今回は picasaweb.google.co.jp の URL からなる画像からのみ、位置情報を取得するようにしてあります。picasaweb.google.com など、多くの別名があるのですが、その品揃えが把握できていないというのが理由です。

また、http://lh5.ggpht.com/picasateam/RvqoUMVOLxI/AAAAAAAAQQk/rOLsH7RnldQ/s288/DSC_0027.JPG といった画像(サムネイルを含む)の URL からも位置情報が取得したいところなのですが、この URL から Picasa ウェブアルバム もしくは Picasa Web Albums Data API の URL に変換できないため、今のところ実現の見込みはありません。

Picasa ウェブアルバムと Picasa Web Albums Data API のリソース仕様(URL パターン)が明示されていないか調べたのですが、まだ見つけるに至っていません。もうしばらくアンテナをハッてみて発見できないようなら、Picasa チームのフォーラムで質問することも考えます。

このエントリで使った画像は、Picasa チームの公開アルバムの画像です。位置情報が付いた画像がいくつかありますので、参考になるでしょう。

jQuery JSONP プラグインを改善してアップデートしました

コールバックのイベントハンドリングを容易にする jQuery JSONP プラグインを改善してアップデートしました。使い方とソースコードを確認 し、必要に応じてダウンロードして差し替えてください。

変更点は、次のとおりです。コールバックのインタフェースに変更があります。

jQuery 1.2 から script 要素を jQuery.fn.append すると、キャッシュを抑止するための意図しないパラメータが付いてしまう ため、jQuery を使わず、script 要素を直接 appendChild で追加するようにしました。
  jQuery('head', document)[0]
.appendChild(script[0]);
file:// を使ったり、キャッシュが効いているとき、IE がクラッシュしないように script 要素の削除を 10ms 遅らせる ようにしました。
  setTimeout(function() {
script.remove();
}, 10);
jQuery の流儀にしたがい、コールバックのコンテキストが jQuery オブジェクトの要素になるようにしました。
  self.each(fn, [json]);
jQuery 1.2 から jQuery.getJSON メソッド を使って同じ機能が実現できる ため、このプラグインは不要になったのですが、今まで使って慣れ親しんできたのと、ちょっとした愛着があるので、使い続けていきます。

2008-06-06

FirefoxのsetIntervalに不具合?

FirefoxのsetIntervalは複数を一度に登録して実行するとまとめて処理してしまいます。次のコードは1秒間隔で3回、テキストエリアに実行回数と時間(秒.ミリ秒)を出力する関数を定義して、それを10回呼び出しています。
// 関数を定義
var textarea = document.f.ta;
var fn = function(){
var count = 0;
var id = window.setInterval(function(){
count++;
var d = new Date();
textarea.value += count + " : " + d.getSeconds()
+ "." + d.getMilliseconds() + "\n";
if(count > 2){
clearInterval(id);
}
}, 1000);
};

// 10回呼び出す
for(var i=0; i<10; i++){
fn();
}

これを実行するとFirefox以外は一秒毎に3回10行づつ出力され、合計30行が出力されるます。期待する結果どおりで正しいです。それがFirefoxは一秒後に30行出力されてしまいます。
// Firefox以外
1 : 2.843
1 : 2.859
1 : 2.859
1 : 2.859
1 : 2.859
1 : 2.859
1 : 2.859
1 : 2.859
1 : 2.859
1 : 2.859
2 : 3.859
2 : 3.859
2 : 3.859
2 : 3.859
2 : 3.859
2 : 3.859
2 : 3.859
2 : 3.859
2 : 3.859
2 : 3.859
3 : 4.859
3 : 4.859
3 : 4.859
3 : 4.875
3 : 4.875
3 : 4.875
3 : 4.875
3 : 4.875
3 : 4.875
3 : 4.875

// Firefox
1 : 51.843
1 : 51.859
1 : 51.859
1 : 51.859
1 : 51.859
1 : 51.859
1 : 51.859
1 : 51.859
1 : 51.859
1 : 51.859
2 : 51.859
2 : 51.859
2 : 51.875
2 : 51.875
2 : 51.875
2 : 51.875
2 : 51.875
2 : 51.875
2 : 51.875
2 : 51.890
3 : 51.890
3 : 51.890
3 : 51.890
3 : 51.890
3 : 51.906
3 : 51.906
3 : 51.906
3 : 51.906
3 : 51.921
3 : 51.921

自分のコードが悪いのかと思ったのですが、見直しても悪く思えません。試しにMozilla 1.0とNetscape 7.1で試したところ、Mozillaは他のブラウザと同様の結果となりましたが、NetscapeはFirefoxと近い結果になりました(1回と2回が一秒後に出力。3回目は2秒後に出力)。

setTimeoutを使って同じ処理を実行したところ、こちらは問題ありませんでした。一回毎にsetTimeoutで登録しなおしているからでしょうか。

他にも例では10個同時に実行してますが、一つだけだとFirefoxも期待通りに動きます。またディレイ時間を20msづつずらすとこちらも期待通りに動くようになります。

どうも同じタイミングで動き出すような登録はよくないようです。Firefoxではディレイ時間に気をつけないと…。

それにしてもMozilla 1.0の頃は問題なかったのが最近のはダメってデグレートでは?気になります。でもBugzilla追うのは面倒なのでそっとしておこう。

Dreamweaver Extensionの開発にチャレンジしてみる (その1)

nakajimanさんの記事を参考に私も簡単なDreamweaver Extensionを開発してみました。同じ物ではつまらないので私はメニューに項目を追加して、選択すると予め作成しておいたHTMLを表示する機能拡張を作成します。

初めての環境で開発する場合、最初のとっかかりが大切です。道をいきなり間違えないように事前のお勉強は大切だと思ったのでAdobe社が公開している「Dreamweaver CS3 - 拡張ガイド」を読んでみました。

・・・・・・・・・。10分後クローズボタンをクリック。
nakajimanさんが仰っていた「要点が掴みにくかったり、具体的な振る舞いまで言及していなかったり、なんかこう入り口の壁が高い印象があって、取り組むのを敬遠していました。」というのを理解。「はじめに」の章の内容が悪い。具体性に欠けていて何から手をつけてよいかわかりません><

どうしたものだろうと、Dreamweaverと一緒にインストールされたアプリを眺めたところ関係ありそうなアプリを発見。「Adobe Extension Manager」。すごく重要そう。起動して触ってみたところ、Fileメニューに拡張機能をインストール、作成、削除する項目を発見。ここから始めれば良さそう。

とりあえず「拡張機能の作成」をクリックしたところ、mxi拡張子のファイルを要求するファイルダイアログが表示されました。mxiファイル?何それ。調べたところ「Adobe 拡張機能情報ファイル」だそうで、拡張機能の名称やバージョン、概要、使用ファイルなどを記述したファイルなのだそうです。拡張ガイドの読んだところにはそんなファイルの事書いてなかったですよ。最初に道を間違えないようにお勉強したけど結局道に迷いはじめてる…。でも進んでみなくては何も見えてこないのでAdobe Extension Managerを信じてみることに。

mxiファイルの作成は適当な機能拡張のを雛形にしたほうが早いと思ったので、以前nakajimanさんが紹介されていたmicroformats拡張機能を参考にすることにしました。パッケージをここからDLして、Adobe Extension Managerを使ってインストール。

そしてどこかにないかなと探したところ、あったあった「microformats.mxi」ファイル。
(C:\Documents and Settings\(ログインユーザ)\Application Data\Adobe\Extesion Manager\Configuration\Extensions\microformats.mxi)

これを参考に以下のmxiファイルを作成。機能拡張名は適当に「Aiueo」と命名。
話が長くなってしまったので本日はここまで。下記の内容については次回説明します。先に結論をお伝えしておくと、次回で拡張機能の開発が無事に終わります。インストール・アンインストールもできるハッピーエンドですのでご安心ください。それでわでわ。
<macromedia-extension name="Aiueo" version="0.1.0" type="Suite">
<author name="aquilegia" />

<products>
<product name="Dreamweaver" version="9" primary="true" />
</products>

<description><![CDATA[
あいうえお機能拡張。
]]></description>

<ui-access><![CDATA[
「ヘルプ」メニューから「Aiueo.htmlを開く」を選択して実行する。
]]></ui-access>

<license-agreement><![CDATA[
]]></license-agreement>

<files>
<file source="Aiueo.htm" destination="$dreamweaver\Configuration\Menus\Aiueo\" />
</files>

<configuration-changes>
<menu-insert insertAfter="DWMenu_Help_About">
<separator />
<menuitem id="DWMenu_Help_Aiueo" name="Aiueo.htmlを開く"
enabled="true" file="Menus/Ael/Aiueo.htm" />
</menu-insert>
</configuration-changes>
</macromedia-extension>

2008-06-01

Picasa のデフォルトブラウザが IE7 に固定されてしまう

新しく ThinkPad X61s を購入したら、はじめから Picasa2 がインストールされていました。

こりゃインストールの手間が省けてよかったかと思いきや、困ったことに、Firefox2 をデフォルトブラウザにしたにも関わらず、Picasa からウェブアルバムを開くと、必ず IE7 が実行されてしまうのです。Google から Picasa のパッケージをダウンロードして再インストールしても変わりません。

lenovo と Microsoft で何か細工をしているとしか思えません。原因はよくわからないのですが、解決方法は見つかりました。

Default browser - MozillaZine Knowledge Base
Use the options or preference settings within your Mozilla browser as shown above, to set Firefox or Mozilla Suite/SeaMonkey as the default browser. If that doesn't work, try the following:
次のコマンドを "ファイル名を指定して実行..." を使って実行するだけです。
firefox.exe -silent -setDefaultBrowser
これで Picasa から Firefox2 でウェブアルバムが開くようになりました。プリインストールされた Picasa には要注意です。

Windows Vista に Apache 1.3.41 と 2.0.63 のインストールを試みてみた

今まで Windows XP だった開発環境を Windows Vista に移行しています。

Windows Vista への Apache のインストールは、普段は必要ないちょっとした対応が必要になりました。次のエントリを参考にしました。

WindowsVistaにApache2.2をインストールする
とりあえず現状でもっとも新しいバージョンである2.2をインストールすることとする。Vistaではこれまでよりもセキュアになった(らしい)ので、インストーラのアクセスが拒否されてしまう。管理者でなければ操作できないらしい。
Apache のインストーラを管理者として実行しなきゃならないってことです。でも、.msi のインストールパッケージは、右クリックしても "管理者として実行..." というメニューが表示されないので、次のように、コマンドプロンプトを管理者として実行します。



そして、そのコマンドプロンプトから、.msi のインストールパッケージを実行します。すると、Apache のインストーラが管理者として実行されます。
C:\Users\user\Downloads>apache_2.0.63-win32-x86-no_ssl.msi
この手順で Windows Vista に Apache 2.0.63 をインストールできました。

同じ手順で Apache 1.3.41 もインストールできたのですが、インストール後、Apache のサービスを開始しようとしてもエラーが発生しまいます。原因を探ろうかとも思いましたが、1.3 系はもういいかな。