2008-12-31

Postal Search Ajax API の Test Suite を公開します

おはようございます。なかじまんです。Postal Search Ajax API Test Suite を公開します。

Postal Search Ajax API Test Suite は、Postal Search Ajax API をリリースするためのテスト環境とテストケース群です。それぞれ aquilegia さんが開発してくれました。ありがとうございます。

Postal Search Ajax API も改良を進めてきた結果、それなりの規模になってきました。そのため、ソースコードの根本的なところに手を入れると、どんな影響があるか手軽に確認しにくくなってきました。また、現在は、次世代ブラウザの多様化や端境期ということもあり、各ブラウザ上でのテストのバリエーションが増大してきました。という背景から、Postal Search Ajax API Test Suite という形で、テストを自動化するに至った次第です。

Postal Search Ajax API Test Suite を開くと、すぐにテストがはじまります。そして、次のように、テストの内容と結果をリスト表示していきます。グリーンはテストが成功したことを表しています。



レッドはテストが失敗したことを表します。合わせて、テストが失敗した条件や事由を表示します。↓スクリーンショットのエラーは Opera 固有の振る舞いにより、期待する結果にならなかったことを示しています。



Postal Search Ajax API は、script 要素を使って動的に JavaScript をロードする仕組みを使っていますが、ローカルファイル(file プロトコル)からのロードは、ブラウザのセキュリティモデルに依存するため、テストケースから除外しています。input 要素の type="file" の value なども同様です。

Postal Search Ajax API は、非同期の API で、背後でタイマを使っていることもあり、低スペックの PC だとタイマの誤差により、テストが失敗することがあります。また、ネットワークの帯域などその状況にも左右されて、テストが失敗することがあります。

安定したテスト環境を用意したり、Mock 的なアプローチを導入して、インタフェースのみをテストするという方法もありうるのですが、やはり、リリース後と同じ状況でテストするべきという目的は譲れないため、不安定な部分も残しつつも公開しました。ですので、個別の事象や不都合は、少しずつよくなるよう改善を進めていきます。

Postal Search Ajax API Test Suite は、aquilegia さん作の Ael という JavaScript ライブラリ で構築されています。Ael がどういうものか、その概要は把握しているのですが、どのようにして、テスト環境を構築して、テストケースを動作させているのかは、わたしも未知です。これから覗いてみます。そのうち aquilegia さんが説明してくれると、勝手に期待しています。

2008-12-30

opensocial-jquery 0.2.0 view の操作をサポートしました

こんばんは。なかじまんです。opensocial-jquery 0.2.0 をリリースしました。

opensocial-jquery 0.2.0 では、次のとおり、view の操作を追加しました。

現在の view 名を取得できます。view 名は "profile", "home", "canvas", "preview" などの文字列です。

var name = jQuery.view();
// console.log(name) => "home"

現在のコンテナで使用できる view 名を配列として取得できます。

var names = jQuery.views();
// console.log(names) => ["home", "canvas"]

view 名を指定して、view を切り替えることができます。

jQuery.view("canvas");

view を切り替えるとき、パラメータを引き渡すことができます。

jQuery.view("canvas", { name: "nakajiman" } );

そのパラメータは ready イベントの引数として取得できます。

jQuery(function($, data) {
// console.log(data) => { name: "nakajiman" }
}

jQuery(document).ready(function($, data) {
// console.log(data) => { name: "nakajiman" }
}

view の切り替えとパラメータの引渡しの実例を用意しました。

http://opensocial-jquery.googlecode.com/svn/tags/0.2.0/samples/picasa.xml

jQuery.getJSON を使って Picasa Web Albums から新着の写真を取得し、リスト表示しています。このときの view は "profile" です。



写真をクリックすると、jQuery.view を使って "canvas" view に切り替えます。そして、クリックした写真を拡大して表示します。このとき、切り替えた view でどの写真をクリックしたか判別できるように、jQuery.view のパラメータとして、写真の URL を引き渡しています。



上のスクリーンショットは Orkut sandbox のものですが、iGoogle sandbox でも動作します。 以前は動作していたと思うのですが、Orkut sandbox で jQuery(window).title (gadgets.window.setTitle) を呼び出すとエラーが発生するようになっています。あれれ。

2008-12-25

opensocial-jquery OpenSocial ガジェット向けにカスタマイズした jQuery とそのプラグインです

おはようございます。なかじまんです。opensocial-jquery 0.1.0 をリリースしました。

opensocial-jquery は、OpenSocial ガジェット (アプリケーション) 向けにカスタマイズした jQuery とそのプラグインです。opensocial-jquery を使うと、OpenSocial APIGadgets API をほとんど意識することなく、jQuery を使ってウェブサイトを開発するノリで OpenSocial ガジェットを開発できます。

実例

まずは、サンプルのソースコードを紹介します。ガジェットのソースコードですが、jQuery を使ってウェブサイトを開発するのと変わらないでしょ?



<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="jQuery.getJSON - samples - opensocial-jquery">
<Require feature="dynamic-height" />
<Require feature="settitle" />
</ModulePrefs>
<UserPref name="tag" default_value="dog" required="true" />
<Content type="html"><![CDATA[
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.gadgets.js"></script>
<script type="text/javascript">
jQuery(function($) {

// Retrieves a preference as a string.
var tag = $.pref('tag');

// Sets the gadget title.
$(window).title(tag + ' - YouTube');

// Fetches content from the YouTube that content into the callback function.
var url = 'http://gdata.youtube.com/feeds/videos';
var data = { vq: tag, 'max-results': 21, alt: 'json' };

$.getJSON(url, data, function(json) {

$.each(json.feed.entry, function() {

var img = $('<img width="80" heieht="60" />')
.attr('src', this.media$group.media$thumbnail[0].url);

$('<a target="_blank" />')
.attr('href', this.media$group.media$player[0].url)
.append(img)
.appendTo('#videos');
});

// Adjusts the gadget height.
$(window).adjustHeight();
});

});
</script>
<style type="text/css">
<!--
#videos img {
border: 0;
margin: 2px;
width: 80px;
height: 60px;
}
-->
</style>
<div id="videos"></div>
]]></Content>
</Module>

opensocial-jquery は jQuery 本体の改良とプラグインから構成しています。

jQuery 本体

(1) jQuery.ajax

jQuery.ajax を介したリクエストは、すべて gadgets.io.makeRequest に橋渡しします。すべてのリクエストがガジェットサーバのプロキシで中継されます。そのため、クロスドメインリクエストの制約がありません。

text, html, xml, json, jsonp, script すべての dataType が使えます。jsonp や script であっても Gadgets サーバのプロキシで中継します。もちろん jQuery.ajax のショートカットである jQuery.fn.load, jQuery.get, jQuery.post, jQuery.getJSON, jQuery.getScript も使えます。

(2) dataType="feed" と jQuery.getFeed

jQuery.ajax の dateType として feed を追加しました。gadgets.io.makeRequest でgadgets.io.ContentType.FEED を指定したのと同じです。ショートカットとして jQuery.getFeed が使えます。

(3) jQuery(function() {}) と jQuery.ready

ガジェットコンテナのライフサイクルを尊重し、gadgets.util.registerOnLoadHandler のタイミングで ready イベントが起こるようにしています。

jQuery プラグイン

(4) jQuery(window).title

ガジェットのタイトルを変更できます。gadgets.window.setTitle に橋渡ししています。

(5) jQuery(window).adjustHeight

ガジェットの高さを自動調整します。高さを指定することもできます。gadgets.window.adjustHeight に橋渡ししています。

(6) jQuery.pref

ガジェットのユーザ設定を取得します。gadgets.Prefs.getString に橋渡ししています。

Shindig feature

opensocial-jquery は Shindig feature 形式でアーカイブしています。Shindig の feature として追加すると、次のように Require要素で opensocial-jquery の JavaScript 群をインポートできます。そのため script タグは不要です。

<ModulePrefs title="jQuery.getJSON - samples - opensocial-jquery">
<Require feature="opensocial-jquery" />
</ModulePrefs>

今後の予定

(a) jQuery.ajax を OAuth に対応することを検討しています。OAuth やその手続きをなるべく意識せずに使えればベストです。OAuth の深い知識が必要かな。やっぱり。

(b) gadgets.* を jQuery ライクに取り込んでいきます。よく使うと思われるものから優先的に取り組みます。はじめは gadgets.views が候補です。canvas ビューなど、複数のビューを使うことをサポートします。

(c) 各 opensocial.DataRequest を jQuery ライクに取り込みます。jQuery.getData を追加して "/people/@me/@friends" のように OpenSocial RESTful Protocol や RPC Protocol 的に条件指定できることを検討しています。各 opensocial.request* は jQuery.postData として追加することを検討しています。

opensocial-jquery を通じて、OpenSocial ガジェットの開発に貢献できればと願っています。以上、リリースのお知らせでした。

2008-12-14

gooラボの BLOGRANGER TG が API も含めてサービスを終了しちゃいます

BLOGRANGER TG 実験終了のお知らせ
今回のサービス終了の対象は、BLOGRANGER TGのタグマップを使ったブログ検索サービスだけではなく、タグマップAPIや、BLOGRANGER 2.0から2年間提供してきましたブログマイニングAPI、パーツを含めて、BLOGRANGERのすべてのサービスとなります。
↑とのことです。今まで BLOGRANGER API を使って、ちょっとした遊びアプリを作ってきましたが、もう動かなくなるってことですね。なので、作ったものの中から代表的なものを振り返ってみます。

Twitter.statuses.join(BLOGRANGER::TG)
今回は Twitter API を使いました。Twitter API で public_timeline を拾い続けて、そのユーザのアイコンを並べて表示していきます。このとき同時に、オートタギング API を使って、"つぶやき" のテキストからタグを自動推定します。そして、同じタグが推定された "つぶやき" 同士をくっつけて、アイコンをグループ化します。


オートタギングAPI を使ってブログのエントリを勝手に分類してみる
少し過去の話題にさかのぼります。上記のとおり、BLOGRANGER TG のブログパーツで、このブログのミニ地図が表示できなかったので、手始めに BLOGRANGER API の オートタギング API というのを使って、指定したブログのエントリからタグを自動推定して、そのタグごとにエントリを分類して表示するアプリケーションを作ってみました。


再び BLOGRANGER TG tube サムネイルがぐるぐる回転します
BLOGRANGER TG API を使って仮想地図を表示します。そして、その仮想地図の中央付近の話題と繋がりのある動画を YouTube Data API を使って検索し、その動画のサムネイルをグルっと一周する円として表示します。さらに、その動画のサムネイルをクリックすると、その動画を Flash Player を使って再生します。


マッシュアップレシピ BLOGRANGER TG tube 地図とタグと動画のビミョーな関係
タグに関連する動画のサムネイルを、タグの周囲に表示するようにしました。動画のサムネイルは、タグをキーワードとして YouTube Data API を使って検索しています。仮想地図に表示されたタグに対して、その検索を3秒ごとに繰り返して、次々とサムネイルを表示していきます。仮想地図をスクロールすると、そのスクロール先で表示されたタグのサムネイルを繰り返し表示します。


マッシュアップレシピ BLOGRANGER TG touch の Google ニュース和え
BLOGRANGER TG の地図をタップすると、そのタップした位置が画面中央になるように移動します。画面端をタップしながら地図の上を歩いていくような感じです。タグをタップすると、そのタグで最近のニュースを検索するようにしました。ニュースの検索は Google ニュースを使っています。BLOGRANGER TG の地図とタグは、ブログ界の様相を表している?ので、ブログ界とニュースの関係とそこから何かの発見があるかもしれない・・・。


マッシュアップカフェのプレゼン資料で Postal Search Ajax API のサンプルが引用されました
マッシュアップカフェの BLOGRANGER API のプレゼン資料の中で Postal Search Ajax API のサンプルが引用されました。マッシュアップカフェの様子は、こちらにレポートがあります。
もっとあった気がするのですが、どこに何があるのか分からなくなってしまっています。旧ブログ でもいろいろ紹介していましたので、こっちにあるかもしれません。

BLOGRANGER といろいろマッシュアップしてきたその足跡を振り返ってみました。

MA4 応募者限定の忘年会に参加してきたよ!

12月10日(水)ですが、MA4 応募者限定の忘年会という集まりに参加してきました。会場は銀座メディアテクノロジーラボ のオフィスです。
Mashup Awards 4 (MA4) での受賞からその後、いかがでしょうか?直前のご案内となってしまい恐縮ですが、明日10日(水)19時半~よりリクルート メディアテクノロジーラボのオフィス(東京都中央区銀座)にて、MA4 応募者限定の交流会(忘年会)を開催いたします!
アジェンダは、次のとおりです。
  • 自己紹介 & 作品 PR タイム
  • MA4 振り返り
    • KEEP(続けるべき点)
    • PROBLEM(問題だった点)
    • TRY(次回に向けて+α)
  • 懇親会
参加者みんなで1つのテーブルを囲み、自己紹介 & 作品 PR タイムから。作品 PR タイム(例)のお題は、次のとおり。
  • お名前
  • 作品・サービス概要紹介
  • 開発裏話
    • 開発と応募の動機
    • 知られざる機能・ウラ技
    • 泣なくして語れない秘話
    • 笑える話
  • 応募後の評判・反響
  • 今後の展望
続けて、懇親会兼 MA4 振り返りへ。次のとおり、事前アンケートを分類して、参加者みんなの MA4 に思うところをシェアしたり。
  • KEEP
  • PROBLEM
  • TRY
  • TOPICS
んで、お開きしたときは 23:00 をとっくに過ぎてました。

MA4 振り返りでは、クレームに近いような要望に対して、事務局や関係者の方々は、真剣に耳を傾けていました。MA5 があるかどうかは明言していませんでしたが、何らかの形で次回もあり、よりよいものへという意気込を感じました。

私からは、個人の参加者がモチベーションを高められる企画や体制とか、私のような SIer 的な立場の人でも参加しやすいような状況作りとかを、伝えることができました(というつもりです)。なんらかの形で実現されることを願っています。

もし MA5 があれば、よい意味で期待を裏切るためにも、SIer 的な作品を応募して、新しい参加の形を開拓してみようかなと、ひそかに計画するのでありました。見せ付けてやらんといけんですよ。みなさん。そのときになりましたら、また声をかけあって作品を開発しましょう。

iGoogle サンドボックスは、ガジェットのソースコードによって環境を切り替えることで互換性を保っている!?



iGoogle サンドボックスは、ガジェットのソースコードの内容から、旧仕様のガジェットか、新仕様のガジェットかを判別して、それぞれ異なる環境で動作させるようです。

次のガジェットを iGoogle サンドボックスに追加しても、gadgets.util.* といった Gadgets API が取り込まれません。ガジェットをレンダリングする iframe の中身を確認すると、旧仕様のガジェット(現在の iGoogle)と同じ環境に見えます。

<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="gadgets.util.registerOnLoadHandler">
</ModulePrefs>
<Content type="html"><![CDATA[
<script type="text/javascript">
_IG_RegisterOnloadHandler(function() {});
</script>
]]></Content>
</Module>

しかし、次のガジェットを iGoogle サンドボックスに追加すると、状況が一変し、gadgets.util.* といった Gadgets API が取り込まれます。ガジェットをレンダリングする iframe の中身を確認すると、新仕様のガジェット(Opensocial 系コンテナ)に近い環境になっているように見えます。

<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="gadgets.util.registerOnLoadHandler">
</ModulePrefs>
<Content type="html"><![CDATA[
<script type="text/javascript">
gadgets.util.registerOnLoadHandler(function() {});
</script>
]]></Content>
</Module>

旧仕様と新仕様の切り替わる接点を調べてみましたが、Content 要素の内容が影響していました。次のとおり、Gadgets API を部分的 "gadgets.ut" に含めると、新仕様の環境に切り替わります。

<Content type="html"><![CDATA[
<script type="text/javascript">
//gadgets.ut
</script>

しかし、次のとおり、"gadgets.u" とすると、旧仕様の環境に切り替わります。

<Content type="html"><![CDATA[
<script type="text/javascript">
//gadgets.u
</script>

開発上の都合から、ガジェットのソースコードをすべて外部ファイルに追い出そうと試みたのですが、なぜか iGoogle サンドボックスだけ動作しなかったため、この事象に気がつきました。

iGoogle サンドボックスで Gadgets API を使うときは、Content 要素に Gadgets API を使ってるぞと判別できるような断片を含めておく必要があるみたいです。iGoogle は1つの環境で、新旧の互換性を確保するに至っていないということでしょうかね!?

2008-11-15

自ページのリンクを削除する jQuery remove self link plugin を公開します。

ページから自ページのリンクを削除してユーザビリティを改善する
ホームページのユーザビリティを改善できると知りながら、何も手を打たないのは歯がゆいことです。そこで WEB ブラウザでページを表示したときに JavaScript (jQuery) を使って、ページの中から自ページのリンクを削除する方法を考えました。
↑のエントリを投稿しから1年になりましたが、JavaScript を使ってページ内から自ページのリンクを削除するという手法は、とてもバランスのよい妥協で有効であったことが確認できました。

私が手がけたいくつかのサイトで使っていますし、今後も使っていく予定です。一般性のある JavaScript コードである(だった)という結論です。そこで、この機会に jQuery プラグインとして整理して公開しましたので、よかったら試してみてください。

jquery.removeSelfLink.js

次のように、コンテンツがロードした後に、jQuery.fn.removeSelfLink メソッドを呼び出してください。これだけで、ページ内から自ページのリンクを削除してくれます。また、アンカー(#flagment)による自ページのリンクは削除しないようにしてあります。

<script type="text/javascript">
//<![CDATA[
jQuery(function($) {
$(document).removeSelfLink();
});
//]]>
</script>

ページ全体ではなく、特定の要素を対象とすることもできます。

<script type="text/javascript">
//<![CDATA[
jQuery(function($) {
$('#foo').removeSelfLink();
});
//]]>
</script>

jQuery と同じライセンスにしておきますね。お役に立てれば幸いです。

2008-11-10

『オックスフォード ピクチャー ディクショナリー 第2版』で単語を覚える!?

おはようございます。なかじまんです。

村上式シンプル英語勉強法―使える英語を、本気で身につける の中で、単語を覚えるための教材として、オックスフォード ピクチャー ディクショナリー 第2版 を紹介していたので、さっそく取り寄せてみました。

村上式シンプル英語勉強法―使える英語を、本気で身につける Oxford Picture Dictionary: English/ Japanese (Oxford Picture Dictionary)

一般生活に関わる英単語を、写真と絵付きで表現しているものです。子供のことに読み返していた乗り物図鑑とか、昆虫図鑑とかいったものを連想させます。これがなかなか面白いです。

漠然としてますが、写真や絵と英単語がいうイメージとして関連付くので、意識的に記憶しようとするときとは、別の質の記憶感みないなものを感じます。しばらくペラパラめくって、何か変化があるか確認するつもりです。

ディクショナリーというだけあって、紙質に良いものを使っています。また、ディクショナリーというとコンパクトなものを想像していましたが、大判? B4 くらい? の大きさです。少し重くかさばるので、通学や通勤で持ち歩くには、手軽さにかけています。

CARWINGS-CASTING のリクエストに位置情報が付与されない例外があるので考慮しておきましょう。

Golazo MA4 team のなかじまんです。

動的なCARWINGS-CASTINGをに配信するには
動的にCARWINGS-CASTINGを生成するCGIを配置することで車の状態に合わせた情報配信が可能になります。CARWINGセンターからはhttpのGET形式で以下のパラメータがCARWINGS-CASTINGコンテンツプロバイダ側に渡されます。
CWC 技術情報では、上記のとおり、CARWINGS-CASTING のリクエストパラメータ仕様を解説しているのですが、CARWINGS-CASTING の URL を インターネット情報チャンネルに登録する ときのリクエストパラメータの例外を説明していないようです。

この例外ですが、ほとんどのケースで不都合ないと判断できるのですが、実際に Golazo MA4 の開発の中で、Golazo MA4 の CARWINGS-CASTING がインターネット情報チャンネルに登録できないことがありましたので、CWC 技術情報の補足として、この例外を紹介しておきます。

CARWINGS-CASTING をインターネット情報チャンネルに登録するとき、指定した URL に対してリクエストを発行し、CARWINGS-CASTING が存在するかどうか確認するようです。そして、存在するときは、RSS 2.0 のタイトル (channel/title) を取得して、インターネット情報チャンネルのタイトルとして使うようです。

このときのリクエストパラメータに例外があります。すべてのパラメータ値が、空欄となってリクエストされます。ですので、必ずパラメータ値が指定されると期待して、パラメータ値を検査してエラーとすると、インターネット情報チャンネルに登録できません。

ですので、リクエストのパラメータ値が、空欄となっても RSS 2.0 をレスポンスする必要があります。このとき、RSS 2.0 のタイトル (channel/title) が使われることになるので、エラーを表すタイトルにならないよう考慮する必要があります。

なお、CARWINGS エミュレータ という CARWINGS-CASTING を評価する環境がありますが、このエミュレータは、インターネット情報チャンネルに登録した後の環境をエミュレートするものということです。ですので、CARWINGS-CASTING を開発するときは、CARWINGS-CASTING エミュレータでのテストに加えて、インターネット情報チャンネルに登録するときの例外もテストすべきでしょう。

少し話題が変わりますが、先日(10/29)に、次のような発表がありました。

日産|日産自動車、Googleマップと連携した目的地設定をカーウイングスナビゲーションで実現
日産自動車株式会社(本社:東京都中央区銀座 社長:カルロスゴーン)は29日、同社のカーナビゲーション向け情報配信サービス「カーウイングス」において、世界最大の検索エンジンGoogle(グーグル)が行う Googleマップと連携し、カーナビゲーションの目的地設定などの操作をより便利に使うことを可能とするサービスを開始する。
まだ、WEB サービスとの連携という色合いが濃いですが、もしかすると近い将来、カーナビのあり方を変えてしまう(地殻変動を起こす)サービスが登場するかもしれませんね。その主導者が外資系の新興企業ではなく、国内から現われることを期待しています。

2008-11-03

FLOWER LOCK 2.0 は、何がどのくらい 2.0 なのだろうか。

とある店頭で FLOWER LOCK 2.0 のパッケージが並んでいたのですが、そのパッケージには、昔のフラワーロックからどう新しくなったのか説明がないんですね。ちょっと気になるので、調べちゃいましたよ。

パッケージは ノースポールタイプコスモスタイプ の2種類だけです。外形のバリエーションではなく、特殊な LED による様々な色や光で、個性を表現しようという趣旨のようです。LED は50色くらい表現できるということで、現実に見てみたいですね。

フラワーロック 2.0 (ノースポールtype) フラワーロック 2.0 (コスモスtype)

iPod とかのミュージックプレーヤーと接続できるように、外部スピーカーも備えているとか。その延長で、複数の FLOWER LOCK 2.0 を繋がられるとあります。繋げるとなんかまた不思議なことが起こったりするのだろうか。

で、FLOWER LOCK 2.0 は、何がどのくらい 2.0 なのだろうか。ネットで軽く調べた感じだと良く分からずです。いずれ実物を見て、確認することにしよう。アマゾンでは入荷待ちとあるから、人気があるようです。

2008-11-01

Aptana Jaxer 1.0 がリリースされました。Golazo MA4 もちょっぴり貢献しています。

Aptana Jaxer 1.0 がリリースされました。正確にいうと Release Candidate から Stable Release になりました。

Jaxer 1.0 released. Jaxer Pro 1.0 also available.
I am excited to announce that the 1.0 version of Jaxer, the free, open source Ajax server, has been released.


Golazo MA4 も Aptana Jaxer で構築しています。その中で Jaxer team にフィードバックして反映してもらった部分も含まれているはずなので、Aptana Jaxer 1.0 のリリースは、少しばかり思い入れのあるものとなりました。

Golazo MA4 は Aptana Jaxer を使って JavaScript のみで動かしています
先日公開した Golazo MA4 ですが、サーバサイド JavaScript (Ajax Server) の仕組みを備えた Aptana Jaxer を使って、アプリケーションを構築し、運用しています。
このブログは、いつのまにか Aptana Jaxer のエントリ の占める割り合いが高くなってしまいました。少しバージョンが古い 0.9.7 ものが中心ですが、参考になればうれしいです。ほとんどの問題は 1.0 で解決しています。

2008-10-27

GMap2 と GStreetviewPanorama の位置情報を相互に連携する方法

Golazo MA4 team のなかじまんです。新機能のお知らせです。

Golazo MA4 で Google ストリートビューを使って、メモの位置の風景を確認できるようにしました。
Golazo MA4 でメモを表示するとき、そのメモの位置を表す Google マップに加え、Google ストリートビューを表示して、その位置の風景を確認できるようにしてみました。今回は、ココメモの "よく読む" のリンク先だけ対応しました。今後は、ココメモの追加や編集でも対応する予定です。
予定どおり、Golazo MA4 で、ココメモを追加するときと編集するときに、Google ストリートビューを表示して、その位置の風景を確認しながらメモできるようにしました。次のスクリーンショットのとおりです。



Google マップの移動に応じて、ストリートビューが連携します。また、ストリートビューの移動に応じて、Google マップが連携します。つまり、マップとストリートビューが相互に連携します。さらに、マップの地点で、ストリートビューのデータが存在しなときは、ストリートビューを非表示にします。

GMap2 と GStreetviewPanorama の移動イベントをハンドリングして、緯度経度を軸として、相互に連携するだけで簡単ジャンと思いきや、GStreetviewPanorama の不完全さ? により、実現にかなり苦労しました。

ので、ソースコードを抜粋して、ポイントを紹介しておきます。

// GStreetview
var pano = new GStreetviewPanorama(document.getElementById('pano'));
//pano.hide(); //BUG

GMap2 は生成してあるとします。まず、GStreetviewPanorama を生成します。このとき、オプションである初期の緯度経度は指定しません。

はじめは非表示とするため、hide メソッドを呼び出したいところですが、この時点で hide メソッドを使うと、show メソッドで表示できなくなってしまいました。バグっぽいです。

// GStreetviewClient
var client = new GStreetviewClient();
client.getNearestPanoramaLatLng(point, function(latlng) {
if (latlng) {
$('#pano').show();
if (pano.isHidden())
pano.show();
pano.setLocationAndPOV(point);
}
});

GStreetviewClient を使って、GMap2 の中心の緯度経度から、getNearestPanoramaLatLng メソッドを使って、ストリートビューのデータを探します。point が中心の緯度経度です。データが見つかったときは、GStreetviewPanorama を表示し、現在地として GMap2 の中心の緯度経度を指定しています。データが見つからないときは、非表示のままです。

var initialized = 0;

// GMap2.moveend
GEvent.addListener(map, 'moveend', function() {
client.getNearestPanoramaLatLng(map.getCenter(), function(latlng) {
if (latlng) {
$('#pano').show();
if (pano.isHidden())
pano.show();
if (initialized == 0)
pano.setLocationAndPOV(map.getCenter());
} else {
if (!pano.isHidden())
pano.hide();
$('#pano').hide();
}
if (initialized > 0)
initialized -= 1;
});
});

// GStreetview.initialized
GEvent.addListener(pano, 'initialized', function(location) {
initialized++;
map.setCenter(location.latlng);
});

GStreetviewPanorama の initialized イベントをハンドリングして、ストリートビューで移動したとき、GMap2 の中心がその緯度経度になるように指定しています。

GMap2 の moveend イベントをハンドリングして、マップを移動したとき、その移動先の緯度経度から、getNearestPanoramaLatLng メソッドを使って、ストリートビューのデータを探しています。データが見つかったときは、GStreetviewPanorama を表示し、現在地として GMap2 の中心の緯度経度を指定しています。データが見つからないときは、、GStreetviewPanorama を非表示としています。

ストリートビューで移動したとき、その移動先をマップの中心としていますが、このままだとマップが移動したことになり、さらに、ストリートビューを移動しようとします。つまり、意味のない連鎖のループが形成され、パラパラチラチラと、同じ緯度経度でのストリートビューの表示が繰り返されてしまいます。

ですので、initialized 変数を使って、ストリートビューの再表示が、ただ1回になるように工夫しています。何かもっと正規な方法がありそうな気がするのですが、今のところ見つかっていません。

主要ブラウザで動作確認しましたが、Opera 9.5 で、ストリートビューの現在地が更新されないという不都合を確認しています。それ以外のブラウザは大丈夫でした。原因は分からずじまいです。Opera 9.2 では期待どおりですので、Flash Player とかプラグインと関係がありそうな気もします。

2008-10-26

Postal Search Ajax API 1.1.1 アップデート! タイマの扱いを見直しました。

Postal Search APIs & Solutions team のなかじまんです。

Postal Search Ajax API をアップデートしました。バージョンは 1.1.1 です。アップデートの内容は、次のとおりです。必要に応じて差し替えてください。

(1) 個々に JavaScript の setTimeout と setInterval を使うのをやめ、1つの setInterval で複数のタイマを擬似的に扱うようにしました。

次の Firefox2 のバグに対応することが目的でした。ただ1つの setInterval タイマしか使わないようにしたため、Postal Search Ajax API 単独では、このバグは再現しなくなりました。

FirefoxのsetIntervalに不具合?
FirefoxのsetIntervalは複数を一度に登録して実行するとまとめて処理してしまいます。次のコードは1秒間隔で3回、テキストエリアに実行回数と時間(秒.ミリ秒)を出力する関数を定義して、それを10回呼び出しています。
ただ、聞いたところによると、Firefox2 のセキュリティ更新の提供は、2008年12月中旬をもって終了するそうです。あと1ヶ月ちょいです。無駄なことしたかなぁという感じもありますが、

1つの setInterval を使って複数のタイマを擬似的に実現するようにしたため、同時に多数の API を呼び出すケースで、ツマッた感じがなくなって、滑らかに処理が進むようになったはずです。

(2) 最新の jQuery 1.2.6 に差し替えました。

Postal Search Ajax API に同封の jQuery 1.2.3 を 1.2.6 に差し替えました。

(3) Google Chrome にも対応しました。

Google Chrome の動作確認をし、不都合がないことを確認できました。

2008-10-25

カバンに MA4 バッチをつけて街中を歩いてます。見かけたら声をかけてくださいね。

Golazo MA4 team のなかじまんです。

Golazo MA4 は Mashup Awards 4 で沖電気工業賞と日産自動車賞をダブル受賞しました!
10月19日(日)、リクルート本社で Mashup Awards 4 の表彰式があり、Golazo MA4 は、沖電気工業賞と日産自動車賞をダブル受賞することができました。協力してくださったみなさん。ありがとうございました。
その後の Mashup Awards 4 の広まりがいまひとつという印象がありますので、自主的にささやかな宣伝活動をしちゃいます。しばらくの間、わたしのカバンに MA4 バッチをつけておきます。



金沢文庫、青物横丁、品川(駅中)、品川シーサイド、大崎(駅中)、大手町、三田(駅中)あたりを歩くことが多いです。見かけたら声をかけてくださいね。

カバンの写真は、沖電気工業さんから副賞でもらった Nikon デジタルカメラ COOLPIX P6000 で撮ったものです。



愛犬(コーギー)の写真も撮ってみました。デジカメの知識はほとんどないので、どないなもんでしょう。

2008-10-20

Golazo MA4 は Mashup Awards 4 で沖電気工業賞と日産自動車賞をダブル受賞しました!

Golazo MA4 team のなかじまんです。

10月19日(日)、リクルート本社で Mashup Awards 4 の表彰式があり、Golazo MA4 は、沖電気工業賞と日産自動車賞をダブル受賞することができました。協力してくださったみなさん。ありがとうございました。

↓表彰状の盾です。沖電気工業賞と日産自動車賞とあります。



↓受賞者みんなでの記念撮影の様子です。私は中央付近、黄色いTシャツ(ここらっとさん)の後ろにいます。わかるかな。



さっそく、沖電気工業さんの OKILab.jp 開発日記でも紹介して頂けました。ありがとうございます。今のところ機能や精度で LocoSticker 位置表現特定 API にとって変わるもの見つかっていませんので、突っ走っちゃてください。さらなる発展を期待しています。

MA4の最優秀賞は、ChaMap! LocoSticker賞は、Golazo MA4 (OKILab.jp開発日記)
LocoStickerの位置表現特定APIをうまく使っていただき、地図上にメモを残すといった実用性の高いサービスにマッシュアップしていただけたと思います。また、カーナビとの連携も興味深く、まさにその場所の情報を取るというサービスにぴったりです。
日産自動車さんのカーウイングスブログでも紹介して頂けました。ありがとうございます。日産車のオーナーじゃないのが心苦しいですが、一般車向けの NV-BD600DT というカーウィングスに対応したカーナビを発売するとのことで、購入を検討しています。

カーウイングスブログ: 【MA4】日産自動車賞は「Golazo MA4」に決定!
Golazo MA4は、ココナビという機能を有しており、PCで場所に関するメモをして、それをクルマの中ではインターネット情報チャンネルを利用して、使うことができます。これまでのインターネット情報チャンネルとは違って、利用者が自分のためにコンテンツを作るようなサービスと言ってもいいでしょう。素晴らしい作品ですね。
↓沖電気工業さんから副賞として、Nikon デジタルカメラ COOLPIX P6000 を頂きました。GPS を搭載していて、写真に位置情報を付与できるとのことです。位置情報と写真の関係も関心がありますので、いろいろと活用してみます。



↓日産自動車さんから副賞として、日産(モータースポーツ含む)の関連グッズをたくさん頂きました。なんと!「8曲しか入らないMP3プレーヤーを実現した、128MBのMP3プレーヤー(通称:はっちゃん)」もあるじゃないですか... ネタがわからず、ごめんなさい。NISSAN 提供のラジオドラマと関係してるみたい。

<

↓受賞者だけに配られたバッチです。



↓表彰式の出席者に配られたお土産です。リクルートさんとサンマイクロさんのグッズが盛りだくさんです。



当初は Mashup Awards 4 に応募することが目的でしたが、受賞という結果が出てさらに達成感が高まりました。ただ、優秀賞の作品は非常にレベルが高いので、比較してしまうと、ひぇーと感心するほかありませんでした。素晴らしすぎて、お手上げです。

受賞作品のリスト も公開されました。刺激になりますので、見てみるといいですよ。

2008-10-17

Golazo MA4 で公開してもらったメモを削除できるようにしました。

Golazo MA4 のなかじまんです。機能改善のお知らせです。

Golazo MA4 で、友達から公開してもらったメモを削除できるようにしました。

↓次のスクリーンショットのとおり、友達から公開してもらったメモに、削除するリンクを表示するようにしました。このメモが不要になったら削除できるということです。ここでいう削除とは、公開を中止するということで、友達のメモ自体を削除するわけではありません。



今までは、メモを公開する側の意図を優先していたのですが、公開してもらった側でメモの削除の自由がないため、その結果、メモを公開する側も気を使ってしまい、友達の間で、気軽にメモを分かち合えないという、あまりよくない状況になってしまいました。

ですが、今後は、メモを公開された側で自由にメモを削除できますので、少しでも公開したいメモがあれば、気兼ねなくどんどん公開できるようになりました。これで、メモの輪が広がることを期待しています。

2008-10-15

Golazo MA4 で Google ストリートビューを使って、メモの位置の風景を確認できるようにしました。

Golazo MA4 team のなかじまんです。新機能のお知らせです。

Golazo MA4 でメモを表示するとき、そのメモの位置を表す Google マップに加え、Google ストリートビューを表示して、その位置の風景を確認できるようにしてみました。

↓次のスクリーンショットのとおりです。

今回は、ココメモの "よく読む" のリンク先だけ対応しました。今後は、ココメモの追加や編集でも対応する予定です。



Google ストリートビューは、日本の主要都市しか対応していません。ですので、Golazo MA4 では、ストリートビューを表示できる位置(つまり、データが存在するとき)だけ、ストリートビューを表示する工夫をしてみました。

↓ソースコードを抜粋したものです。

// GStreetview
var pano = new GStreetviewPanorama(document.getElementById('pano'));

var client = new GStreetviewClient();
client.getNearestPanoramaLatLng(point, function(latlng) {
if (latlng) {
$('#pano').show();
pano.setLocationAndPOV(point);
}

GStreetviewPanorama オブジェクトを生成するとき、オプションの緯度経度をを与えません。そして、ストリートビューを表示する div 要素は、事前に display:none; で非表示としています。

GStreetviewClient オブジェクトの getNearestPanoramaLatLng メソッドを使って、メモの位置(point 変数がそれ)付近に、ストリートビューのデータがあるかどうか問い合わせています。

メモの位置付近にデータ(latlng 変数がそれ)が存在するときは、前述の div 要素を表示し、GStreetviewPanorama オブジェクトの setLocationAndPOV メソッドを使って、その位置のストリートビューを表示しています。メモの位置付近にデータが存在しないときは、何もしないので、ストリートビューは表示されなことになります。

Google ストリートビュー APIのノウハウをいくつか tips [okyuu.com] がとても参考になりました。ありがとうございます。

今回は、ただ単に、ストリートビューを表示するだけで、地図との連携といったインタラクティブな機能はありません。どのような機能や操作性が有益なのか、まだ掴めきれていませんので、よいアイディアがありましたら、ぜひ教えてください。

注意点です。主要な OS とブラウザで動作確認しましたが、MacOS X の Firefox2 だとストリートビューが表示されない現象を確認しています。また、古いバージョンの Flash Player だと、ストリートビューを操作するとき、JavaScript エラーが発生することがあります。Flash Player 9 以上をオススメします。

2008-10-12

Golazo MA4 のココモバでメモるとき、その場で友達に公開できるようにしました。

Golazo MA4 team のなかじまんです。新しい機能のお知らせです。

Golazo MA4 のココモバ(携帯電話版)で、現在地をメモするとき、指定した会員に、そのメモを公開できるようにしました。外出先のその場から直接メモを公開して共有できますので、即時性のあるフレッシュなメモを分かち合うことができます。また、PC を使ってメモを公開するという手間もなくなりました。

次のとおり、ココメモの登録ページに "公開する会員" という項目を追加し、メモを公開できる会員を一覧表示するようにしました。ここで、公開したい会員をチェックして、メモを登録すると、チェックした会員にそのメモが公開されます。



そうそう。昨日、Mashup Awards 4 の応募作品一覧 が公開されました。Golazo MA4 は、CARWINGSLocoStickerMextractr (メタデータ自動抽出API) のカテゴリに登録されています。ほかの応募作品などを見ると、いろいろな使い方や応用方法が見れるので、アイディアを刺激されます。

2008-10-08

Golazo MA4 のココモバで、現在地からメモまでの乗換案内を表示できるようにしました

Golazo MA4 team のなかじまんです。新しい機能のお知らせです。

Golazo MA4 のココモバ(携帯電話版)で、現在地からメモまでの乗換案内を表示できるようにしました。現在地から少し離れたメモが見つかったとき、そのメモの場所までの路線や所要時間を確認できるので、役立つこと間違いなしです。

次のとおり、メモのページに "乗換案内" というリンクを追加しました。このリンクを選択すると、



現在地からメモの場所までの乗換案内を表示します。乗換案内は Google トランジット を使っています。最寄り駅の直近の発車時刻とかも分かるので、駅で待ちぼうけしないような時間調整にも役立つかもしれませんね。



Google トランジットは、地名や駅名などのテキストしか入力できない印象があったのですが、いろいろ試してみると、"35.278834,139.675839" といった緯度経度が入力でき、地点から地点の乗換案内も検索してくれるようです。素晴らしいのひとこと。

乗換案内は aquilegia さんから貰った要望 & アイディアです。ありがとうございました。

2008-10-03

Aptana Jaxer で生成したページが70文字前後で意図せず改行されてしまう(ことがある)

次のような、改行を含まない textarea 要素があったとします。

<textarea rows="12" cols="48">Modern web sites and applications use Ajax to create engaging user experiences: the HTML and CSS are set in motion using JavaScript running in the browser and calling back the server. To achieve this, the server needs to prepare the web page appropriately, and to know what to do when the JavaScript calls it. But the server knows nothing about the HTML and CSS DOM, nor how to handle JavaScript data, and you can't code it in JavaScript...</textarea>

ブラウザで、この textarea 要素を表示すると、当然ですが、次のようになります。



Aptana Jaxer 0.9.7.2472 を介して、この textarea 要素を含む HTML ページを生成すると、次のように、70文字前後で意図せず改行されてしまうのです。

<textarea rows="12" cols="48">Modern web sites and applications use
Ajax to create engaging user experiences: the HTML and CSS are set in
motion using JavaScript running in the browser and calling back the
server. To achieve this, the server needs to prepare the web page
appropriately, and to know what to do when the JavaScript calls it. But
the server knows nothing about the HTML and CSS DOM, nor how to handle
JavaScript data, and you can't code it in JavaScript...</textarea>

ですので、ブラウザで、この textarea 要素を表示すると、次のように、意図しないところで改行されることになります。なんてこった。



サーバサイドの JavaScript で textarea 要素の内容を調べてみたところ、意図しない改行は含まれていなかったので、Aptana Jaxer が DOM をシリアライズするときに、なんらかの理由(理由なんてあるのか?)で、改行を追加していると推測できます。

んで、新しい Aptana Jaxer 1.0.0.3674 RC B で試してみたら、改行されることなく、期待どおり表示されました。どうやら Aptana Jaxer の不具合だったようですね。ただ、Aptana Support を探しても、それらしき報告が見つからないのです。いつ直したんだろうか。

なので、別の視点で調べたところ、Mozilla 関連で同じような事象がある(あった?)ようです。2005年となっているので、かなり古い話題ですね。

Mozilla-gumi Forum [One Topic All View / Re[4]: composerでソースの改行の抑制 / Page: 0]
HTMLのソースファイルが72文字くらいで自動的にwrapされてしまいます。時々半角英数字と全角文字の間で改行されることがあって,困っております。「元のソースの形式を維持する」,「HTMLソースを再整形する」どちらでも同じです。この自動的な改行を抑制することは可能でしょうか?
新しいバージョンの Aptana Jaxer では改善されているので、深追いする必要はないのですが、改善する意図なく Mozilla との関係で、なんとなく直っちゃったみたいな感じだと嫌(なんて自分勝手な感覚なんでしょう)なので、時間があるときに、もう少し背景を調べてみます。

2008-10-02

Aptana Jaxer から Mextractr を使ってメモから位置表現と緯度経度を抽出する(後編)

Aptana Jaxer から Mextractr を使ってメモから位置表現と緯度経度を抽出する(前編)
Golazo MA4 は Mextractr メタデータ自動抽出 API も使って、メモから位置情報を自動抽出しています。... Google Maps API を使って、位置表現から緯度経度を求めています。Google Maps API をどのように呼び出しているかは、後編で紹介しようと思います。
Golazo MA4Mextractr メタデータ自動抽出 API を使って抽出した位置表現の緯度経度を Google Maps API (Geocoding via HTTP) を使って求めています。Google Maps API というと JavaScript API のイメージが強大ですが、REST API もサポートしてたりするのです。

Golazo MA4 から Google Maps API をどう呼び出しているか、実際のソースコードを引用して紹介します。

// Google Maps API - Geocoding via HTTP
// http://code.google.com/apis/maps/documentation/services.html#Geocoding_Direct
var url = 'http://maps.google.com/maps/geo?' +
$.param({ q: text, output: 'xml', key: Golazo.GOOGLE_APIKEY });

Google Maps API の URL とクエリを準備します。クエリの URL エンコードは jQuery を使っています。text は抽出対象のテキストです。apikey は Google Maps API キー です。output は出力形式です。省略すると json になりますが、eval が好みじゃないので XML を取得してから JSON に変換するアプローチとしています。

var xml;
try {
xml = Jaxer.Web.get(url, { as: 'xml' });
} catch (e) {
throw new Error(''+e);
}

Google Maps API を GET メソッドで呼び出して、実行結果の XML を DOMDocument オブジェクトとして取得しています。as プロパティに xml を指定すると、XML をパースしてくれます。

// jQuery XML to JSON Plugin
// http://fyneworks.com/jquery/xml-to-json/
var kml = $.xml2json(xml, true);

jQuery XML to JSON Plugin を使って XML を JavaScript オブジェクトに変換しています。第2引数の true は、要素数に関わらず Array オブジェクトに変換することを意味しています。

//var code = kml
//.Response[0]
//.Status[0]
//.code[0]
//.text;

実行結果を表すコードを参照できますが、コード分類が大雑把な印象で、具体的なメッセージも付与されないため、エラーであっても処理を継続しています。ですので、コメントアウトしてあります。

var places = (kml.Response[0].Placemark || [])
.map(function(placemark) {

//var address = placemark
//.AddressDetails[0]
//.Country[0]
//.AddressLine[0]
//.text;

var coordinates = placemark
.Point[0]
.coordinates[0]
.text
.split(/,/);

return {
//address: address,
latitude: coordinates[1],
longitude: coordinates[0],
altitude: Golazo.WHERE_TOKYO.altitude
};
});

return places;

実行結果から緯度経度を取り出して、配列にまとめています。抽出対象のテキストから、さらに具体的な位置表現をも得られます。が、今回は使っていないので、コメントアウトしています。address 変数がそれです。

なお Mextractr メタデータ自動抽出 API は、代表的な地名(都市名などかな?)のとき、実行結果に緯度経度を付与して返却してくれます。ただ、すべての位置表現に対して、緯度経度が付与されるわけではないので、Google Maps API を使って、位置表現から緯度経度を求めています。

2008-10-01

Aptana Jaxer から Mextractr を使ってメモから位置表現と緯度経度を抽出する(前編)

Aptana Jaxer から LocoSticker を使ってメモから位置表現と緯度経度を抽出する
Golazo MA4 は LocoSticker 位置表現特定 API を使って、メモから位置情報を自動抽出しています。... 1件も位置表現が抽出できないときは、別の API を使って、メモから位置情報を抽出しようと試みます。この続きは、後日、紹介します。
Golazo MA4Mextractr メタデータ自動抽出 API も使って、メモから位置情報を自動抽出しています。 Mextractr メタデータ自動抽出 API は、場所などの位置表現に加えて、人名や法人名、日時表現、何をするかの表現など、テキストから様々な角度のデータを抽出できます。まさにメタデータ抽出といったところです。

Golazo MA4 から Mextractr メタデータ自動抽出 API をどう呼び出しているか、実際のソースコードを引用して紹介します。

// Mextractr Web API
// http://www.emetadata.net/doc
var url = 'http://api.emetadata.net/mextractr';
var data = $.param({ text: text, apikey: Golazo.MEXTRACTR_APIKEY });

Mextractr メタデータ自動抽出 API の URL とクエリを準備します。クエリの URL エンコードは jQuery を使っています。text は抽出対象のテキストです。apikey は Mextractr API キー です。

var xml;
try {
xml = Jaxer.Web.post(url, data, { as: 'xml' });
} catch (e) {
throw new Error(''+e);
}

Mextractr メタデータ自動抽出 API を POST メソッドで呼び出して、実行結果の XML を DOMDocument オブジェクトとして取得しています。as プロパティに xml を指定すると、XML をパースしてくれます。

// jQuery XML to JSON Plugin
// http://fyneworks.com/jquery/xml-to-json/
var feed = $.xml2json(xml, true);
if (feed.message)
throw new Error(feed.message[0].text);

jQuery XML to JSON Plugin を使って XML を JavaScript オブジェクトに変換しています。第2引数の true は、要素数に関わらず Array オブジェクトに変換することを意味しています。

// 位置表現だけを抜き出す
feed.entry.forEach(function(entry) {
if (entry.where) {
entry.where.forEach(function(where) {
response.push({ label: where.valueString });
});
}
});

実行結果から位置表現だけを取り出して、配列にまとめています。

// 位置表現から緯度経度を求める
Golazo.each(response, function(i, where) {
var geos;
try {
geos = Golazo.Geo.get(where.label);
} catch (e) {
throw new Error(''+e);
}

var geo = geos[0] || {};
where.latitude = geo.latitude;
where.longitude = geo.longitude;
where.altitude = geo.altitude;

if (where.latitude)
return false; // break
});

Google Maps API を使って、位置表現から緯度経度を求めています。Google Maps API をどのように呼び出しているかは、後編で紹介しようと思います。

位置表現から緯度経度が取得した時点でループを抜け出します。つまり、メモの先頭よりの位置表現を採用しているということです。ですので、メモの意味するところと違う結果になることがありえます。まだまだ改善の余地があるところです。

2008-09-30

CSS Browser Selector を使って Google Chrome を個別対応する。textarea のフォントサイズの相対値がおかしな件。

Google Chrome だけ textarea の font-size がひとまわり小さくなってしまう
Google Chrome を使って Golazo MA4 の動作確認をして気が付いたのですが、Google Chrome だけ、次のように textarea の font-size がひとまわり小さく表示されてしまうのです。em 単位で指定してるのが良くないのかなぁ。ネットで調べてみたのですが、それらしき話題は見つかりませんでした。時間があるときに原因を調べてみます。
引き続き、調べてみました。Google Chrome の textarea は、気になるところが2点ほどあります。

1つ目は、textarea のフォントサイズが、他のブラウザに比べて、ひとまわり小さいことです。他のブラウザに比べて 80% くらいの大きさでしょうか。Styling even more form controls を使うと、様々なフォームのスタイルを手軽に確認できます。

2つ目は、次のように textarea のフォントサイズに相対値を指定すると、元々の textarea のフォントサイズに対して .8em 分、小さく表示されるということです。CSS の仕様は、あまり詳しく把握できていないのですが、.8em と指定したときは、1em に対する .8em のフォントサイズになると理解しているのですが、どうもそうじゃないようです。Safari 3.1 だと期待どおりなのですが...。

#content form input,
#content form textarea {
font-size: .8em;
}

次のとおり、フォントサイズに絶対値を指定すると、Google Chrome も含め、すべてのブラウザで、期待どおりのフォントサイズで表示できます。ただし、フォントサイズを固定すると、文字サイズの拡大と縮小で、ブラウザ間で差異が出てしまう(特にIE)ため、対処としては不完全といえます。

#content form input,
#content form textarea {
font-size: 13px;
}

Google Chrome だけ個別に対応する手法(いわゆる CSS Hack)がないか探してみましたが、Google Chrome は Safari 3 の CSS Hack を適用できるが、Google Chrome だけ適用できる CSS Hack はなさそうでした。Google Chrome を調整すると Safari 3 に影響が出ちゃうということですね。う~む。

ということで CSS だけでの対応はあきらめ、CSS Browser Selector という JavaScript を使って、User-Agent ごとに CSS を切り替える仕組みを使って対応することにしました。

CSS Browser Selector の導入はとても簡単です。次のように JavaScript をロードして、

<script type="text/javascript" src="css_browser_selector.js"></script>

次のように、ブラウザごとに CSS を記述するだけです。Google Chrome だけ textarea のフォントサイズを 1em にしています。これで、すべてのブラウザで、ちょうど 80% の大きさになります。

#content form input,
#content form textarea {
font-size: .8em;
}

.chrome #content form textarea {
font-size: 1em;
}

CSS Browser Selector が何をするかというと、navigator.userAgent を見分けて、HTML 要素にブラウザの種類を表すクラス名を動的に追加するというだけです。ブラウザのエンジン、オペレーティングシステムの区別もできます。なかなかシンプルなアイディアに感心します。

<html class="gecko ff2 win js">

JavaScript が無効だと使えないという欠点がありますが、JavaScript の有無による CSS の区別も備えるため、JavaScript が無効なときの妥協的な CSS を用意するといった対応もできます。

2008-09-29

Google Chrome だけ textarea の font-size がひとまわり小さくなってしまう

Google Chrome を使って Golazo MA4 の動作確認をして気が付いたのですが、Google Chrome だけ、次のように textarea の font-size がひとまわり小さく表示されてしまうのです。



次のように、その他のブラウザ (画像は Firefox2) では、だいたい同じ大きさで表示されます。



font-size を指定するスタイルシートは、次のとおりです。

#content form input,
#content form textarea {
font-size: .8em;
}

em 単位で指定してるのが良くないのかなぁ。ネットで調べてみたのですが、それらしき話題は見つかりませんでした。時間があるときに原因を調べてみます。ひとまず、デザインに方針に影響を与えそうなので、事象だけお伝えしときます。

2008-09-27

Aptana Jaxer から LocoSticker を使ってメモから位置表現と緯度経度を抽出する

Golazo MA4LocoSticker 位置表現特定 API を使って、メモから位置情報を自動抽出しています。LocoSticker 位置表現特定 API は、住所やスポットのテキストを抽出することに加えて、テキストの主題との関連の強さを判断し、関連の強いものを抽出するという、頭の良さを備えた優れものの API です。

Golazo MA4 は Aptana Jaxer を使って JavaScript のみで動かしています
先日公開した Golazo MA4 ですが、サーバサイド JavaScript (Ajax Server) の仕組みを備えた Aptana Jaxer を使って、アプリケーションを構築し、運用しています。
LocoSticker 位置表現特定 API は、GET や POST でクエリを与えると、JSON 形式で結果を返すという、よくあるパターンの API なので、具体的な呼び出し方を紹介する必要はないのですが、Golazo MA4 は Aptana Jaxer を使って、サーバサイドの JavaScript から LocoSticker 位置表現特定 API を呼び出していますので、どうやってるの?という関心があるかと思います。

そこで、Golazo MA4 から LocoSticker 位置表現特定 API をどう呼び出しているか、実際のソースコードを引用して紹介します。

// LocoSticker 位置表現特定 API
// http://okilab.jp/project/location/2007/11/locosticker_api.html
var url = 'http://api.locosticker.jp/v1/extract_place/';
var data = $.param({ text: text, selection: 'on' });

LocoSticker 位置表現特定 API の URL とクエリを準備します。クエリの URL エンコードは jQuery を使っています。text は抽出対象のテキストです。selection を on とすると、前述の頭の良さを発揮します。

var clusters;
try {
clusters = eval('(' + Jaxer.Web.post(url, data) + ')')
.result_select;
} catch (e) {
throw new Error(''+e);
}

LocoSticker 位置表現特定 API を POST メソッドで呼び出して、実行結果の JSON を JavaScript オブジェクトに変換しています。

// クラスタをフラットな配列に変換する
clusters.forEach(function(cluster) {
cluster.forEach(function(where) {
where.label = where.text;
where.latitude = where.lat;
where.longitude = where.lng;
where.altitude = Golazo.WHERE_TOKYO.altitude;
response.push(where);
});
});

実行結果から位置表現、緯度、経度を取り出して、配列にまとめています。

// 住所よりもスポットを優先し、重みでソートする
response.sort(function(a, b) {
if (a.type == b.type)
return a.weight - b.weight;
else if (a.type == 'spot')
return -1;
else
return 1;
});

実行結果は、住所とスポットが入り混じっているので、スポットを優先に重み(スコアが高い)順で並べ替えをしています。

// 位置表現が特定できたら継続しない
if (response.length > 0)
return response; // found.

そして、その並べ替えた実行結果を使って、メモに位置情報を付与しています。1件も位置表現が抽出できないときは、別の API を使って、メモから位置情報を抽出しようと試みます。この続きは、後日、紹介します。

2008-09-23

Golazo MA4 は Aptana Jaxer を使って JavaScript のみで動かしています

Golazo MA4 という Mashup Awards 4 応募作品をオープンしました。
ここ1ヶ月ほど、Mashup Awards 4 応募作品の開発に専念するため、エントリの投稿をサボっていました。いろんな人からの協力もあり、おかげさまで Mashup Awards 4 に作品を応募することができました。この場を借りてお礼します。ありがとうございました。
先日公開した Golazo MA4 ですが、サーバサイド JavaScript (Ajax Server) の仕組みを備えた Aptana Jaxer を使って、アプリケーションを構築し、運用しています。

Mashup Awards をどう取り組むかは、様々な想いがあると思いますが、Golazo MA4 team としては、新しい技術を試す絶好の機会と捉えていて、実際に Aptana Jaxer を使って JavaScript のみでどこまで開発できるのかチャレンジしてみた次第です。

Aptana Jaxer サイトに Ajax アプリケーションの特性をよく表している図があります。この図は Aptana Jaxer に限らず、一般的な Ajax アプリケーションの構成をも表すもと理解できます。

1 がサーバサイド、2 がクライアントサイド、3 が XMLHttpRequest (XHR) を使ったサーバサイドとクライアントサイドの関係を表しています。一般的に 1 は Java、PHP、Ruby、Python などを使い、2 は JavaScript を使うことになります。3 はその組み合わせになりますが、1 が持つフレームワークの仕組みで 2 と 3 を実現することも多いですね。


Copyright 2005-2008 Aptana, Inc.

Golazo MA4 は 1~3 のすべてを JavaScript を使って実現しています。Golazo MA4 の中身がどんな構成になっていて、どんなことをしているのか、その概観を紹介します。

Jaxer Server は HTTP サーバの機能を持ちません。ですので、Apache 2.2 をフロントエンドにしています。そして、mod_jaxer というモジュールを介して Apache と Jaxer Server を繋げています。

データベースは SQLite を使っています。データベースの操作は Jaxer Framework がサポートしています。Google Gears のインタフェースを包含しています。MySQL などにも対応しているので、必要があればスケールアップすることも考えています。


Copyright 2005-2008 Aptana, Inc.

会員のプロフィール画像をアップロードして、ローカルファイルとして保存しています。ローカルファイルの操作も Jaxer Framework がサポートしています。JSLib をベースにしているようです。ですので、ソケットなんかも使えたりします。

外部の WEB API を呼び出して (GET/POST) して、データ (JSON/XML) を取得しています。外部ホストに対する操作も Jaxer Framework がサポートしています。Jaxer Server は Firefox3 をエンジンとするため、サーバサイドから XHR が使えたりします。


Copyright 2005-2008 Aptana, Inc.

メモの登録や削除、友達になる、友達をやめるなどの操作は、XHR を使ってクライアントサイドからサーバサイドを操作しています。いわゆる Ajax といわれるものです。このとき、Jaxer Framework がクライアントサイドとサーバサイドを仲介してくれるので、JSON のエンコードやデコード、シリアライズというデータ交換のコードはいっさい書いていません。次のように JavaScript の関数を定義して呼び出すだけです。


Copyright 2005-2008 Aptana, Inc.

送信フォームの入力チェックは、基本的にクライアントサイドで実行しています。が、同じ入力チェックをサーバサイドでも実行しています。クライアントサイドとサーバサイドで、同じコードを共有しているので、クライアントサイドだから、サーバサイドだからといった余計なことを考えなくて済んでいます。


Copyright 2005-2008 Aptana, Inc.

サーバサイドでの HTML ページの生成は DOM/CSS をベースとしています。これは Firefox3 をエンジンとする Jaxer Server の特長ともいえます。上から下に向かって HTML ページを生成する一般的なテンプレートエンジンとは発想が異なるため、今までの経験が適用しにくく戸惑いました。


Copyright 2005-2008 Aptana, Inc.

Jaxer Server は、HTTP リクエストがあると、その HTML ページを読み込んで DOM にします。そして、その DOM に対して操作をするタイミングを用意し、その後、操作した DOM をシリアライズして HTTP レスポンスとします。ですので、普段クライアントサイドで使っている JavaScript ライブラリをサーバサイドでも使えるメリットがあります。今回は jQuery を使って、サーバサイドで HTML ページを生成しています。

残念ながら CARWINGS-CASTING (RSS 2.0) は Aptana Jaxer ではなく Ruby を使っています。というのは、Aptana Jaxer は HTML を扱うことを基本(例外もあるらしいが未確認)としているためです。このとき、Ruby から前述の SQLite のデータベースを参照して、Aptana Jaxer と Ruby の共存をはかっています。

う~ん。ざっと全体像をなぞったつもりですが、いろいろ書きたいことがあって、うまく伝わらないかもしれません。今後は、それぞれの領域で、具体的なコードとかをまじえて紹介できればと思います。Aptana Jaxer 自体の Tips は、過去にこのブログで取り上げていますので、参考にしてください。

2008-09-22

Aptana Jaxer は同名パラメータの複数値を扱えないので個別の対応が必要です

チェックボックスを並べた送信フォームを用意し、そのチェックボックスのパラメータ名(input@name)を同じにして、送信先で、その複数のパラメータ値を取得する... といったことは、ウェブアプリケーションの開発でよく使うパターンです。

ですが、Aptana Jaxer の Jaxer.Request クラスは、同名パラメータの複数値を扱えないため、個々のパラメータ名を重複しないようにするか、Jaxer.Request を使わない個別の対応が必要です。

Jaxer の実装がどうなっているかというと、GET メソッドのときは、次のとおり、QUERY_STRING を解析しています。同じパラメータ名があると、後のパラメータ値で上書きしています。

var queryStrings = query.split("&");
for (var i = 0; i < queryStrings.length; i++)
{
var nameValue = queryStrings[i].split("=");
hash[Util.Url.formUrlDecode(nameValue[0])] = (nameValue.length > 1)
? Util.Url.formUrlDecode(nameValue[1])
: null;
}

POST メソッドのときは、次のとおり、HTTP ボディを解析しています。GET メソッド同様に、同じパラメータ名があると、後のパラメータ値で上書きしています。

var postCount = _request.GetDataItemCount();
for (var i = 0; i < postCount; i++)
{
var name = _request.GetDataItemName(i);
var value = _request.GetDataItemValue(i);
data[name] = value;
}

この Jaxer.Request クラスの良し悪しを簡単に断定することはできません。が、RPC ベースの Jaxer Callback を主体とする Jaxer としては、用途を限定することを知りつつも、HTTP リクエストのデータ構造を単純にして、手軽さを採用したのだと推測しています。

ですので、同名パラメータの複数値を扱いたいときは、Jaxer.Request クラスのパラメータ解析に頼らず、次のように、自らのコードでパラメータを解析することになります。

このコードは、POST メソッドのとき、subscriber というパラメータが複数の値になることを前提としています。GET メソッドのときは Jaxer.Request.query プロパティ、POST メソッドのときは Jaxer.Request.postData を解析するとよいでしょう。

var subscribers = [];
request.postData.split('&').forEach(function(param) {
param = param.split('=');
if (param[0] == 'subscriber')
subscribers.push(param[1] || '');
});

なお、ここで扱った Aptana Jaxer のバージョンは 0.9.7.2472 (Linux) です。ですので、公開中の 1.0.0 RC B では改善されているかもしれません。

2008-09-21

『マイクロフォーマット Webページをより便利にする最新マークアップテクニック』

Microformats をどう使うかにもフォーカスしている『Microformats: Empowering Your Markup for Web 2.0』
Microformats wiki は、リファレンスとしての要素が強く、具体的にどう使ってよいのかが弱かったり、見つけにくいという印象があります。また、たくさんの情報が集まっていますが、その情報が多すぎて、必要な情報を見つけにくく、見落としてしまう実感があります。『Microformats: Empowering Your Markup for Web 2.0』という洋書は、前述の欠点を補ってくれるものですので、その内容を簡単に紹介します。
以前に紹介した洋書を翻訳したものが発売されていました。2008年7月末ころの発売だったようです。知らなかった。

マイクロフォーマット Webページをより便利にする最新マークアップテクニック (Web Designing BOOKS)

マイクロフォーマット ~Webページをより便利にする最新マークアップテクニック~ (Web Designing BOOKS)

2008-09-20

Safari2 で Golazo MA4 の CSS が適用されない不具合を解消しました

Golazo MA4 team のなかじまんです。

ごめんなさい。Golazo MA4 ですが、Safari2 だと CSS が適用されない状態となっていました。本日(9/20)、その不具合を改善したことをお知らせします。

その原因ですが、Golazo MA4 を iPhone (iPod touch を含む) 向けに最適化したものを公開しようと考えていました。その前準備として、メディアクエリを使って、CSS を切り替えるようにしていたのですが、Safari2 がメディアクエリに対応していないため、CSS が適用されないという状態になっていました。これらの経緯は、次のエントリにまとめてあります。

メディアクエリによる iPhone スタイルの切り替えは万能じゃないのか?
メディアクエリを使って iPhone (iPod touch を含む) とその他のブラウザで、スタイルシートを切り替えようと試みているのですが、Apple の開発者サイトやネット上で紹介している方法だと、なぜか Safari 2.0.4 (Multi-Safari) が期待どおり振る舞ってくれません。
まだ準備の段階にも関わらず、iPhone (iPod touch を含む) を意識したコードを HTML ページに忍ばせたのが失敗でした。Safari2 はきっと大丈夫という勝手な判断もよくなかったですね。ちょー反省です。

MacOS X Tiger と Safari3、Safari2 (Multi-Safari)、Firefox3、Firefox2 を使ってみて、どのブラウザでも不都合なくレンダリングしていることを確認できました。もしも、まだ不都合があるようでしたら教えてください。改善していきます。

2008-09-19

メディアクエリによる iPhone スタイルの切り替えは万能じゃないのか?

メディアクエリを使って iPhone (iPod touch を含む) とその他のブラウザで、スタイルシートを切り替えようと試みているのですが、Apple の開発者サイトやネット上で紹介している方法だと、なぜか Safari 2.0.4 (Multi-Safari) が期待どおり振る舞ってくれません。

次のとおり link 要素を記述しました。ですが、

<link media="only screen and (min-device-width:480px)" rel="stylesheet" type="text/css" href="/css/golazo-iphone.css" />
<link media="screen and (min-device-width:481px)" rel="stylesheet" type="text/css" href="/css/golazo.css" />

IE6 と IE7 がスタイルシートを読み込まなかったため、次のとおり [if IE] .. [endif] を追加して個別に対応しました。

<link media="only screen and (min-device-width:480px)" rel="stylesheet" type="text/css" href="/css/golazo-iphone.css" />
<link media="screen and (min-device-width:481px)" rel="stylesheet" type="text/css" href="/css/golazo.css" />
<!--[if IE]>
<link rel="stylesheet" type="text/css" href="/css/golazo.css" />
<![endif]-->

これで OK という気になっていたのですが、MacOS X Tiger の Safari 2.0.4 (Multi-Safari) を使ってみると、どのスタイルシートも読み込まれないのです。[if IE] .. [endif] はコメントでスキップしているので、つまり、メディアクエリを指定した link 要素をスキップしているということです。

何か方法が悪いのか、勘違いしているのか、自分自身の中で謎が深まっていくばかりです。Safari 2.0.4 (Multi-Safari) 固有の振る舞いなんでしょうか。今となっては Safari 2.0.4 を試す環境がないので、確認もできないのです。困りました。ヘルプみー。

追記です。-- 2008-09-19

明確な記述のある文献は見つかっていないのですが、ネット上などの情報を総合すると、Safari 2.0.4 の時点では、メディアクエリに対応していなかったようです。

ですので、1~1.5世代くらい前のブラウザも範疇に含める必要があるなら、UserAgent を見分けた切り替えが妥当という結論です。う~む。やっぱり、何らかのプログラム的な要素が必要になりますね。

2008-09-18

Jaxer Server (mod_jaxer) と Apache Etag と Last-Modified の矛盾を解消せよ

Aptana からダウンロードできる Jaxer のアーカイブ には Apache HTTP server も含まれますが、そのアーカイブをそのまま使うと、Apache の Etag と Last-Modified が働いてしまい、Jaxer Server (mod_jaxer) の動的コンテンツのキャッシングに矛盾が発生してしまいます。

どういうことかというと、次のような HTTP レスポンスヘッダ(抜粋)が返ってきます。Expires、Cache-Control、Pragma ヘッダで、ブラウザにキャッシュするなという一方で、Last-Modified と Etag ヘッダで、キャッシュを促すようにもしています。

HTTP/1.x 200 OK
Server: ModJaxer/0.9.7.2472 Apache/2.2.4
Expires: Fri, 23 May 1997 05:00:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Last-Modified: Wed, 17 Sep 2008 13:42:10 GMT
Etag: "351aa-3f1b-a2952661"

これは Jaxer Server (mod_jaxer) が、Apache のフィルタとして機能することに起因しています。Jaxer Server は、動的コンテンツを生成しているつもりでも、Apache は静的コンテンツを扱っていると認識しているという矛盾です。

IE7 や Opera は Last-Modified を優先するらしく、このまま使うと、HTML ファイルの最終更新日に応じてキャッシュが効いてしまい、ページ遷移したり、リロードしたりしても、動的コンテンツにも関わらず、304 Not Modified になってしまいます。

また、プロキシを介している環境であれば、ブラウザによらず、そのプロキシの振る舞いに影響を与えるかもしれません。

本来なら Jaxer Server (mod_jaxer) で Etag と Last-Modified を制御すべきなんだろうと思うのですが、[#JXR-308] Remove ETag and 'Last-Modified" response headers - ASAP - The Aptana Issues Tracker のとおり、Jaxer Server で何か対応するつもりはなさそうです。

ですので、Apache の設定で対応することになります。その一例は、次のとおりです。

FileETag ディレクティブを使って ETag ヘッダを送出しないようにしています。Header ディレクティブを使って Last-Modified ヘッダを送出しないように除去しています。すべての HTTP レスポンスに適用する必要はないので、FilesMatch を使って、Jaxer Server がフィルタするコンテンツのみに適用すればいいでしょう。

FileETag None
<FilesMatch ".\html">
Header unset Last-Modified
</FilesMatch>

なお、ここで扱った Aptana Jaxer のバージョンは 0.9.7.2472 (Linux) です。ですので、公開中の 1.0.0 RC B では改善されているかもしれません。

2008-09-17

Golazo MA4 という Mashup Awards 4 応募作品をオープンしました。

ここ1ヶ月ほど、Mashup Awards 4 応募作品の開発に専念するため、エントリの投稿をサボっていました。いろんな人からの協力もあり、おかげさまで Mashup Awards 4 に作品を応募することができました。この場を借りてお礼します。ありがとうございました。

その応募作品を簡単に紹介します。Golazo MA4 といって、場所をメモして活用することを目的としたサービスです。興味や関心がありましたら、ぜひ使ってみてください。
Golazo MA4 - ココで何する?
http://golazo.offtheball.jp/

Golazo MA4 は、ブラウザで見ているページや入力した文章の内容から位置情報を自動抽出し、気になるお店やプレイスポットなどの情報を、場所付きのメモとして、簡単にクリッピングできるサービスです。

外出先の携帯電話から使えば、現在地に最も近いメモを検索したり、その場所でメモを残せるので、行ってみたかったレストランを探したり、お店での買い物リストを見たり作ったりなど、クリッピングした場所付きのメモをアクティブに活用できます。

NISSAN のカーナビ に対応しており、インターネット情報チャンネル として登録すれば、自動車の現在地からメモが検索され、地図上で場所を確認したり、その内容を音声で読み上げることができます。

場所付きのメモは、知人や友人に公開できるので、待ち合わせ場所やお勧めのお店などを共有して楽しむこともできます。
今後、このブログを使って、Golazo MA4 の開発を通じて得たことや、Golazo MA4 の内側の技術的なところを紹介していきます。

Google ChromeのJavaScriptで見つけた振る舞いの違い

Google製のブラウザがでたので自前のJavaScript実装テストを流してみたところ、Array#lastIndexの振る舞いが他のブラウザと違うのことを見つけたので、レアケースで役に立たないネタですがメモとして書いておきます。

一つ目はlastIndexで、第二引数にnullやundefined、NaN、{}を指定するとChrome、Safari or Air、その他の間で振る舞いが異なります。次のコードを実行すると
var array = [1, "0", NaN, 1];
array.lastIndexOf(1, null);
array.lastIndexOf(1, void 0)
array.lastIndexOf(1, NaN)
array.lastIndexOf(1, {})

各ブラウザで以下の結果になります。
//Chrome
3
3
0
0

//Safari or Air
0
3
3
3

//その他
0
0
0
0
nullやundefinedを指定した時の始点が違うようで、0と3がばらばらな結果になります。ChromeはWebKitベースなのでJavaScriptエンジンもSafariと同じJavaScriptCoreだと思ったのですが、V8という独自のエンジンを積んでいるそうで、この振る舞いはそこが原因のようです。

二つ目はArray#sortメソッドの振る舞いで、以前実施したテスト(ここここ)をChromeでも実施してみたところ、今までにないユニークな結果を返しました。結果がいい感じにバラバラですがFirefoxは3が振る舞いをIEに合わせるなど徐々に統一されているようです。
["",void 0,null,NaN,0]    //並び替え前

[NaN,"",0,null,void 0] //Chrome
[null,void 0,NaN,"",0] //Dreamweaver, Netscape7
[void 0,null,NaN,0,""] //NN4
["",void 0,null,NaN,0] //Mozilla
[NaN,null,"",0,void 0] //Firefox
["",null,NaN,0,void 0] //IE, Opera, Rhino, Firefox3
[null,NaN,0,"",void 0] //Safari, AIR

追記:
lastIndexについて以前同じようなこと記事で書いたことを忘れていました。lastIndexで振る舞いが異なるのは仕様書が曖昧なのが原因のように感じます。テストコード付きの仕様書があると説得力あるのだけどどこかにあるのかなぁ。

2008-08-06

Aptana Jaxer でファイルをアップロードすると、特定の条件で mod_jaxer がエラーになる

次のようなフォームを使って、Aptana Jaxer に対してファイルをアップロードを試みました。

ファイルのアップロードは期待どおり動作するのですが、ファイルを指定せずにアップロードしようとすると、mod_jaxer がエラーになり、Apache が 500 Internal Server Error になってしまいます。

<form method="post" action="/picture.html" enctype="multipart/form-data">
<input id="form_picture" type="file" name="picture" value="" />
<input type="submit" value="写真をアップロードする ≫" />
</form>

Apache のエラーログには、次のように出力されます。

[Wed Aug 06 06:46:20 2008] [warn] (OS 10054)既存の接続はリモート ホストに強制的に切断されました。 : mod_jaxer: receive data over socket error: total len=3 read=0
[Wed Aug 06 06:46:20 2008] [warn] (-1)Unknown error: mod_jaxer: read data from socket error

いろいろ確認してみたところ、Safari 3 と Opera 9 (ともに Windows XP) でのみ再現することがわかりました。どうやら、ファイルを指定しないときの multipart/form-data の扱いが、ブラウザによって違いがあり、その違いが mod_jaxer の期待と異なることがあると推測できます。

次のように、送信ボタンに name="submit" と名前を指定したところ、この不都合は発生しなくなりました。つまり、multipart/form-data でファイルをアップロードするときは、type="file" 以外のフィールドも合わせて送信するのが無難そうです。

<form method="post" action="/picture.html" enctype="multipart/form-data">
<input id="form_picture" type="file" name="picture" value="" />
<input type="submit" name="submit" value="写真をアップロードする ≫" />
</form>

ということで、実用上は不都合はないという結論です。

Aptana Jaxer のバグ報告を検索してみましたが、それらしきバグは報告されていないようです。ここで扱った Aptana Jaxer のバージョンは 0.9.7.2472 (Windows XP) です。ですので、先日公開された 1.0.0 RC B では改善されているかもしれません。もしも、改善されていないようでしたら、Aptana に報告したいと思います。

2008-08-02

Aptana Jaxer で foo.html? といった ? で終わる ページは callback に失敗する

Aptana Jaxer で http://127.0.0.1:8081/foo.html? といった ? で終わる URL でページを表示し、JavaScript から Jaxer にコールバックしようとすると、次のような例外が発生します。



http://127.0.0.1:8081/foo.html のように ? がないときや http://127.0.0.1:8081/foo.html?bar のように ? 以降があるときは、このエラーは発生せず、期待どおり動作します。

注意さえすれば実用上は不都合ないと思いますが、気になったので原因を調べてみたところ、Jaxer が HTML ページをレンダリングするとき、自動的に追加する JavaScript コードに誤りがありました。

本来なら Jaxer.Callback.pageName の値には、このページの識別子が指定されるはずなのですが、? で終わるときのみ空欄になってしまいます。これはバグですね。

Jaxer.Callback.pageSignature = 610035010;
Jaxer.Callback.pageName = '';
Jaxer.CALLBACK_URI = '/jaxer-server/callback';
Jaxer.ALERT_CALLBACK_ERRORS = true;

具体的な事象が分かったので、Aptana に報告せねばと調べたところ、URL with question mark at the end fails Jaxer という Issue があり、解決済みとなっていました。貢献できると思ったのにちょっと残念。

ここで扱った Aptana Jaxer のバージョンは 0.9.7.2472 です。ですので、先日公開された 1.0.0 RC B では改善されているということですね(未確認です)。

Permission denied to get property Object.constructor

Firefox 3.0にFirebugアドオン(1.2.0b7)を入れたところ、JavaScriptを使ったページで次のエラーが表示されました。FirebugがFirebugを無効にすると直ります。
Permission denied to get property Object.constructor

Firebugは独自にプロパティのアクセス制御をしているのですね。便利ですが使う際に注意が必要そう。

2008-08-01

実践! Ajax フレームワーク jQuery

実践! Ajax フレームワーク jQuery という本が書店に並んでいました。パラパラっと流し読みした感じですと... (立ち読みしちゃった)

実践!Ajaxフレームワーク jQuery

jQuery API のメソッドを1つ1つ取り上げて、サンプルコードとその実行結果を見せながら解説するというスタイルになっています。jQuery 公式サイトの API リファレンスにもサンプル(demo)がありますが、少し読みにくく分かりにくい印象があるので、それを補うための本としての活用があると感じました。ですので、jQuery を使って WEB サイトをどう構成して開発していくかといった視点は弱いですね。