Catalyst で作る簡単 Web アプリケーション: Feed2JS 解説を参考にしながら、Catalystをいじっていたのですが、ajaxな部分を司るCatalyst::Plugin::Prototypeについて調べたことを、ここにメモしておきます。
まず、「prototype」という名が示すのは、「原型」という意味ではなくて、prototypeという名のオブジェクト指向Javascriptライブラリです。俺は最初それが分からず、「ん?何かの原型を作るようなモジュールなのか?」と悩んでました。このライブラリの実態はこんな感じです。prototype.js
で、Catalyst::Plugin::Prototype自体は、HTML::PrototypeのメソッドをCatalystのビューから呼び出せる様にするものです。なので、Catalyst::Plugin::Prototypeの使い方を知るためには、まずはHTML::Prototypeの使い方を知る必要があります。
このHTML::Protoytypeは何をするものなのかというと、prototype.js内のajax関連の関数を呼び出すようなHTMLを手軽に生成するためのもの、ということになります。以下、HTML::Prototypeの使い方と、Catalystから呼び出す方法についてHTML::Prototypeのドキュメントを参考にしながら、実行例も交えて順に見ていきます。また、ドキュメントに載っていないものの、ソースコードから読みとれるものもできる限り記述したいと思います。
基本的なHTML::Prototypeの使い方は以下の様になります。
use HTML::Prototype; my $prototype = HTML::Prototype->new; print $prototype->define_javascript_functions;
HTML::Prototypeで利用できるメソッドは以下の通りです。
各メソッドを順に見ていきます。
このメソッドはprototype.jsの内容そのものを返します。つまり、
print $prototype->define_javascript_functions;
を実行すると、以下の内容が出力されます。
<script type="text/javascript"> <!-- /* Prototype: an object-oriented Javascript library, version 1.2.0 * (c) 2005 Sam Stephenson <sam@conio.net> * * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff * against the source tree, available from the Prototype darcs repository. * * Prototype is freely distributable under the terms of an MIT-style license. * * For details, see the Prototype web site: http://prototype.conio.net/ * /*--------------------------------------------------------------------------*/ var Prototype = { Version: '1.2.0' } ... (省略)
これはあんまり使い道ない気がします。HTML内で、
<script type="text/javascript" src="prototype.js"></script>
としてやればいいですし、Catalystでも、
$ script/my-app_create.pl Prototype
でroot以下にprototype.jsが生成されますから。
このメソッドでは、xmlHttpRequestでサブミットする様なformタグを生成します。オプションとその説明は以下の通りです。
$prototype->form_remote_tag({ method => 'post', url => '/url', update => 'id', position => 'Before', type => 'synchronous', callback => 'callback()', });
実際にこのメソッドが吐き出すHTMLコードを見るために、
print $prototype->form_remote_tag({ url => '/url', update => 'id', type => 'synchronous', loading => 'loading()', });
というコードを実行してみると、以下の様に出力されます。
<form onsubmit=" new Ajax.Updater( 'id', '/url', { parameters: Form.serialize(this),asynchronous: 0,onLoading: function(request){loading()} } ) ; return false;">
このメソッドでは、$functionを呼び出す、$nameで指定したアンカーを持つリンクを生成します。実行すれば一目瞭然、ってことで、
print $prototype->link_to_function( "Greeting", "alert('Hello World!')" );
と実行すると、
<a href="#" onClick="alert('Hello World!'); return false;">Greeting</a>
というHTMLを吐きますし、
print $prototype->link_to_function( '<img src="really.png"/>', 'do_delete()' );
と実行すると、
<a href="#" onClick="do_delete(); return false;"><img src="really.png"/></a>
というHTMLを吐きます。
このメソッドでは、指定したURLに対してxmlHttpRequestでリクエストする様なリンクを返します。オプションと説明は以下の通りです。
$prototype->link_to_remote( 'anchor', { with => 'name=value', url => 'url', update => 'id', type => 'synchronous', callback => 'callback()', })
実際にこのメソッドが吐き出すHTMLコードを見るために、
print $prototype->link_to_remote( 'anchor', { update => 'id', url => 'url', type => 'synchronous', } );
というコードをを実行すると、
<a href="#" onClick=" new Ajax.Updater( 'id', 'url', { asynchronous: 0 } ) ; return false;">anchor</a>
というHTMLを吐きます。
このメソッドでは、$idで指定されたidを持つフィールドを監視して、変更があればxmlHttpRequestでリクエストを出すようなスクリプトを返します。%optionsは$prototype->form_remote_tag(\%options)と同じです。
実際にこのメソッドが吐き出すJavascriptコードを見るために、
print $prototype->observe_field( 'field_id', { update => 'id', url => 'url', type => 'synchronous', } );
と実行すると、
<script type="text/javascript"> <!-- new Form.Element.Observer( 'field_id', 2, function( element, value ) { new Ajax.Updater( 'id', 'url', { parameters: value,asynchronous: 0 } ) } ); //--> </script>
というJavascriptコードを吐きます。
$prototype->observe_fieldと基本的に同じですが、$idで指定されたフォーム全体を監視して、変更があればxmlHttpRequestでリクエストを出すようなスクリプトを返します。%optionsは$prototype->form_remote_tag(\%options)や他と同じです。
実際にこのメソッドが吐き出すJavscriptコードを見るために、
print $prototype->observe_form( 'form_id', { update => 'id', url => 'url', });
と実行すると、
<script type="text/javascript"> <!-- new Form.Observer( 'form_id', 2, function( element, value ) { new Ajax.Updater( 'id', 'url', { parameters: value,asynchronous: 1 } ) } ); //--> </script>
というJavascriptコードを吐きます。
このメソッドでは、xmlHttpRequestによるサーバへのリクエストを、一定間隔で呼び出すようなスクリプトを返します。$options->{frequency}で時間を秒間隔で指定します。(デフォルト2秒。)他のオプションについては、他のメソッドと同様です。
print $prototype->periodically_call_remote({ update => 'id', url => 'url', });
と実行すると、
<script type="text/javascript"> <!-- new PeriodicalExecuter( function () { new Ajax.Updater( 'id', 'url', { asynchr onous: 1 } ) }, 10 ); //--> </script>
というJavascriptコードを吐きます。
このメソッドでは、$name, $valueで指定されたnameとvalueをxmlHttpRequestでsubmitするボタンを生成します。%optionsは他のメソッドと同様です。
実際にこのメソッドが吐き出すHTMLコードを見るために、
print $prototype->submit_to_remote( 'name', 'value', { update => 'id', url => 'url', });
と実行すると、
<input type="button" name="name" value="value" onsubmit=" new Ajax.Updater( 'id', 'url', { asynchronous: 1 } ) ; return false;"/>
というHTMLコードを吐きます。
HTML::Prototypeのメソッドを、Catalystのビューから呼び出すためには、テンプレートに以下の様に記述します。
[% c.prototype.observe_field( 'editor', { url => 'url', with => "'body='+value", update => 'view' }) %]
ご覧頂くと分かるように、オプションの渡し方は、perlでのメソッド呼び出しと何ら変わりありませんので、詳細は省きます。(手抜きですんません。HTML::Prototypeの説明で力尽きました。)