jQuery Mobile メモ - name, value 付きのsubmitボタンの問題

まず先にこの問題はalpha2の時点の話で、alpha3以降では修正されていると思われます(後述)


formの実装では、submitボタンを複数用意して同じ入力に対して別のアクションを取りたい場合があります。
例えば、以下のようなコードです。

<form action="#" method="post" id="form-test">
<input type="text" name="title" />
<button type="submit" name="test" value="true">テスト</button>
<button type="submit">決定</button>
</form>


これは、「テスト」ボタンの方が押されると

$_POST["test"] = "true"


と値が入ってくるので、この有無でボタンの識別をするようにしています。


ただ、これがjQuery Mobileでは入ってこない…。
コードの処理を追ってみると、通常のボタンのコードを上書きしてJavaScriptのコード上でただsubmit()をしています。
これでは値がPOSTに含まれないのも当然です。


しようがないので、ボタンのタイプをbuttonとして無理矢理処理をコーディングしてみました。

<button type="button" id="submit-test">テスト</button>
<script type="text/javascript">
$(function() {
	$('#submit-test').click(function(){
		$form = $('form#form-test');
		$form.append('<input type="hidden" name="test" value="true" />');
		$form.submit();
	});
});
</script>


実はJavaScriptの知識は狭いので、まずは思った通りに動けばいいと適当です。


正直、これは不具合なのでフォーラムにも合わせて投稿しました。
するとある方から下のような回答が。
jquery.mobile-1.0a2.js の以下の部分を書き直せば汎用になるよという回答でした。

if( type == "submit" ){
	$(this).closest('form') .append('<input type="hidden" name="'+$el.attr( "name" )+'" value="'+$el.attr( "value" )+'">') .submit();
}

http://forum.jquery.com/topic/two-or-more-form-submit-buttons-value


結果としては同じですが、汎用なのが素晴らしい!
といっても、これだとライブラリのコードを直接書き換えることになるのが難点です。
バージョンアップしたときに再度、このコードを差し込まないといけません。


それもあって正規のコードにこれが反映されないかな〜と思っていると、昨日こんなコミットがありました。


> make sure submit button name/value is submitted with form values. Fixes #551
https://github.com/jquery/jquery-mobile/blob/419787affec72d7cfcca69999b48e4b58e02d079/js/jquery.mobile.forms.button.js


紛れもなくこの問題の修正です。
試しにこのコードをalpha2に適用してみると、なんも問題なく動作しました。
そういうわけで、次のバージョンアップではこの問題は解決しているものと思われます。


…というかこの修正、元々 type=="submit" だったら $el.submit();、そうでなかったら el.click(); するというコードが、ただの $el.click(); になっただけです。
元々が余計なことをしてただけってこと?

追記 2010・12・12

その後、ふとリポジトリ上の最新のコードを覗いてみたところ、再び変更されていました。
そのままclick()だとなにか問題があるらしく、reset なボタンでなければ、同じname, valueの<input type="hidden"... />タグを挿入する仕様になっているようです。

jQuery Mobile メモ - List view の小技

jQuery Mobile のList viewは、iPhoneアプリなどでよく見られる標準的なリスト表示をお手軽に実現することができる便利なコンポーネントです。
そのList viewのデモでは紹介されていないちょっとした小技を。


まず、リンク付きのリストの基本形。



こう記述します。

<ul data-role="listview" data-inset="true">
<li><a href="#">あずま きよひこ</a></li>
<li><a href="#">羽海野 チカ</a></li>
<li><a href="#">伊坂 幸太郎</a></li>
<li><a href="#">荒川 弘</a></li>
<li><a href="#">石川 雅之</a></li>
</ul>


次に、いろいろとすっとばして左右で別のリンクを設定できる Split button list。



これも簡単で、<li>の中にリンクが2個あれば自動的に左右に配置されます。

<ul data-role="listview" data-inset="true">
<li>
	<a href="#">あずま きよひこ</a>
	<a href="#">編集</a>
</li>
<li>
	<a href="#">羽海野 チカ</a>
	<a href="#">編集</a>
</li>
<li>
	<a href="#">伊坂 幸太郎</a>
	<a href="#">編集</a>
</li>
<li>
	<a href="#">荒川 弘</a>
	<a href="#">編集</a>
</li>
<li>
	<a href="#">石川 雅之</a>
	<a href="#">編集</a>
</li>
</ul>


このSplit listsの右側に配置されるリンクのアイコンは、<ul>にdata-split-iconを設定することで変更されます。

<ul data-role="listview" data-inset="true" data-split-icon="plus">


ただ実はこれ、それぞれの項目で設定することができます。



それぞれのリンクの<a>に対してdata-iconを設定するだけです。
併せて、data-themeで個々にテーマを設定することもできたりします。

<ul data-role="listview" data-inset="true">
<li>
	<a href="#">あずま きよひこ</a>
	<a href="#" data-icon="plus" data-theme="a">編集</a>
</li>
<li>
	<a href="#">羽海野 チカ</a>
	<a href="#" data-icon="check" data-theme="b">編集</a>
</li>
<li>
	<a href="#">伊坂 幸太郎</a>
	<a href="#" data-icon="gear" data-theme="c">編集</a>
</li>
<li>
	<a href="#">荒川 弘</a>
	<a href="#" data-icon="arrow-r" data-theme="d">編集</a>
</li>
<li>
	<a href="#">石川 雅之</a>
	<a href="#" data-icon="arrow-u" data-theme="e">編集</a>
</li>
</ul>


ちなみにこのアイコンの変更は、通常のList viewでも有効です。



ただしこの場合は<a>ではなく、<li>へ設定する必要がありました。
残念ながらテーマを個々に設定することはできませんでした。

<ul data-role="listview" data-inset="true" data-icon="plus" >
<li data-icon="plus">   <a href="#">あずま きよひこ</a></li>
<li data-icon="check">  <a href="#">羽海野 チカ</a><</li>
<li data-icon="gear">   <a href="#">伊坂 幸太郎</a></li>
<li data-icon="arrow-r"><a href="#">荒川 弘</a></li>
<li data-icon="arrow-u"><a href="#">石川 雅之</a></li>
</ul>


あともうひとつ、通常のList viewと、Split listは混在することができます。



ちなみに、これらは正式にドキュメント化されている訳ではないので、もしかしたら偶然動作しているだけかもしれません。
たぶんそんなことは無いと思いますけど。

ethnaで国際化対応 - gettextとEthnaメッセージカタログの併用

ethnaの標準エラーメッセージの表示がうまくいっていないことについ最近になって気がつきました。*1
どうも今年の4月に、Sinkan.comで国際化対応として「gettext」を適用した際に仕込んでしまったようです。


なお、米国版のSinkan.comではこの問題は出ていません。
これはSinkan.net/comのエラーメッセージは日本語ですが、Ethnaのエラーメッセージは標準で英語だからです。


さて、この問題を解決するにはgettextのメッセージカタログに移植すればいいのですが、それはなんだかめんどう(笑)
というわけで、標準で排他的に機能している「gettext」と「Ethnaメッセージカタログ」を同時に機能するよう、Ethna_I18Nを上書きしてみました。

class Discover_I18N extends Ethna_I18N
{
    function setLanguage($locale, $systemencoding = null, $clientencoding = null) {
        parent::setLanguage($locale, $systemencoding, $clientencoding);

        // 強制的にメッセージカタログ再生成
        // Ethna_I18N では、if (!$this->use_gettext) { } で再生成される。
        if ($this->use_gettext) {
            $this->messages = $this->_makeEthnaMsgCatalog();
        }
    }

    function get($msg) {
        // use_gettextの場合のみ
        // Ethnaメッセージカタログを先に反映
        if ($this->use_gettext) {
            $this->use_gettext = false;
            $msg = parent::get($msg);
            $this->use_gettext = true;
        }

        return parent::get($msg);
    }
}


これに併せてDiscover_Controllerの$classを変更すると、英語で表示されていたエラーメッセージが日本語に置き換わり、修正されました。
ただ同じような機能を2重に適用するというのはリソースの無駄であるのは確かなので、いづれかに統一する標準の実装は間違っていないと思います。


強いていえば、

    'use_gettext' => true,
    'use_ethna_msg_catalog' => false,

のようにそれぞれの可否をconfigファイルで設定できると嬉しいかもしれません。

*1:慣れすぎてしまって、標準エラーメッセージがでるような操作をしないため。

jQuery Mobile メモ - “automatic AJAX page loading”を無効にする

AJAX page loading でアニメーションページ変移されるのは格好良いので是非とも使いたいのですが、なぜだかうまく次のページが表示されないことがあります。
相性が悪いのか、理解が足りないのか、まだ不具合があるのかはよくわかりません。


aタグでの遷移は rel="external" を付加して

<a href="http://sinkan.net/" rel="external" data-role="button">新刊.net</a>

と書けばいいのですが、なぜかフォームだとうまくいきません。*1
後々に付加したタグを解除するのも面倒なので、以下のようにまとめて無効化しました。

<script src="jquery/jquery-1.4.4.min.js"></script>
<!-- jQueryMobile CUSTOM -->
<script type="text/javascript">
$(document).bind("mobileinit", function(){
  $.extend( $.mobile , {
    ajaxLinksEnabled: false,
    ajaxFormsEnabled: false
  });
});
</script>
<script src="jquery/jquery.mobile-1.0a2.min.js"></script>

ajaxLinksEnabled が通常のリンク、ajaxFormsEnabled がフォームでの遷移となります。
ポイントは、jQuery MobileのJavaScriptを読み込む前に書くことです。


他にも初期設定値を変更することができるようです。
詳しくは、以下を参照ください。

*1:これはいまだに未解決

jQuery Mobile メモ - リンク集

ちょうど、お手軽にサービスをiPhoneを筆頭としたスマートフォン対応する為になにかないかなと探していたら、ちょうどこのライブラリ「jQuery Mobile」を発見しました。
まだ先月中にα版が公開され始めたばかりで挙動にちょっと不審な点もありますが、今年中にはβを、来年1月には1.0を公開する予定らしいので早々に安定することを期待しています。


まだ実装中なのですが、思いついたところからメモっていきます。


まずは、実装時に常に開いているリンク集(?)です。
といってもほとんど公式サイトです。

http://jquerymobile.com/

まずは公式サイトのトップページ。

http://jquerymobile.com/demos/1.0a2/

公式の「ドキュメントとデモ」、挙動と基本的なコーディングの確認はここでだいたい事足ります。
URLでわかるようにこれはアルファ2版、バージョンアップすると変わるので注意。

https://github.com/jquery/jquery-mobile/

最新版のリポジトリ
「docs」の中に↑のデモページのソースがあります *1
jQuery Mobileは、原則Ajaxで次のページを読み込んでいる為にブラウザの「ページのソースを表示」ではそのページのソースを確認できないことがあります。
そのときはここで直接ソースを眺めることにしています。

http://forum.jquery.com/jquery-mobile

公式のフォーラム。
わからないことがあれば、ここで検索するとだいたい同じ事で悩んでいる人が見つかります。
まだ利用者が多い訳ではないからか、答えまで見つかるとは限らないのが難点。

jQuery Mobile リファレンス的なもの - へっぽこプログラマーの日記

この中で唯一の公式以外のサイト。
特に触り初めの理解が薄い頃、コーディングの参考にさせてもらっていました。

*1:最新版なので配布版と内容が違っていることもあるので注意

ethnaで国際化対応 - ActionFormの選択肢があるフォーム

ethnaフレームワークを利用して開発されている「新刊.net」を「Sinkan.com」へ国際化対応しました。
実際には別サービスなので正確にいうと国際化対応ではないのですが、ethnaの国際化対応の手法を利用して実装したのでご容赦を。


対応するに当たっていくつかコツがあったのでメモ代わりに順次書いていきたいと思います。
…というか id:hidea に残しておけと怒られました (^^;


なおこの内容は、以下にあるethnaのプロジェクト国際化のテキストを前提に書かれています。

ActionFormの選択肢があるフォームと、{form_input}フォームヘルパへの対応

FORM_TYPE_CHECKBOX、FORM_TYPE_RADIO、FORM_TYPE_SELECT などの選択肢があるフォームは、ActionForm で以下のように指定できます。

'access_level' => array (
	'type'		=> VAR_TYPE_INT,
	'form_type'	=> FORM_TYPE_SELECT,
	'name'		=> '公開・非公開',
	'required'	=> true,
	'option'	=> array('0' => '非公開', '1' => '公開')
),

これはテンプレートで、

{form_input name="access_level"}

とフォームヘルパを利用することで手軽にフォームとしてHTML出力することができます。


詳しくは、ethna のリファレンスをご覧ください。

>> フォームヘルパ:選択肢があるフォーム - ethna


ただこの書き方だと、'option'で設定する選択肢が「ethna i18nコマンド」でカタログ化されません。
それ所か、カタログを手動で用意したとしても出力が翻訳されません。
gettextで翻訳される箇所だけならフォームヘルパをオーバーライドしてがりがりと書き換えればいいので、さして難しくはないのですがカタログ化されない部分を書き直すのは面倒です。 *1


そこで別途方法を探っていたところ、'option'には関数名を指定できることを知りました。
ならば、と上のコードを以下のように書き換えました。

class Discover_Form_Options extends Discover_ActionForm {
	/**
	 *  @access private
	 *  @var    array   フォーム値定義
	 */
	var $form = array(
		'access_level' => array (
			'type'		=> VAR_TYPE_INT,
			'form_type'	=> FORM_TYPE_SELECT,
			'name'		=> '公開・非公開',
			'required'	=> true,
			'option'	=> 'access_level_option',
		),
		'notify_checkbox' => array(
			'type'      => array(VAR_TYPE_INT),
			'form_type'	=> FORM_TYPE_CHECKBOX,
			'name'		=> 'メール通知',
			'option'	=> 'notify_checkbox_option',
		),
	}

	function access_level_option() {
		return array(
			'0' => _et('非公開'),
			'1' => _et('公開'),
		);
	}
	function notify_checkbox_option() {
		return array(
			NOTIFY_STATUS_DISCOVER => _et('新着/更新されたアイテムを通知'),
			NOTIFY_STATUS_RELEASE  => _et('発売日直前のアイテムを通知'),
		);
	}
}

これならカタログ化も翻訳の問題も同時にクリアされます。
直接配列を指定するのと比べるとほんの少し見通しが悪くなりますが、問題にするほどでもないでしょう。

*1:後々ethnaがアップデートされた時なんか特に

EBSブートなAMIイメージで、EBSの容量を増量する

「EBSブートなAMIイメージで、インスタンスストレージを割り当てる」のついでにEBSブート時にルートデバイスとなるEBSの容量を増量する方法をメモしておきます。 *1


下記のようにインスタンスを立ち上げるとsda1のEBSデバイスの容量が100GBに増量されます。

$ ec2run ami-xxxxxxxx -b /dev/sda1=:100 -k user_key -g user_group


このままだとシステムが増量された分を認識していません。
resize2fsを使ってファイルシステムのサイズを変更します。

$ df
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1             15481840   2212052  12483356  16% /
none                    874032         0    874032   0% /dev/shm

$ resize2fs /dev/sda1
resize2fs 1.40.4 (31-Dec-2007)
Filesystem at /dev/sda1 is mounted on /; on-line resizing required
old desc_blocks = 1, new_desc_blocks = 7
Performing an on-line resize of /dev/sda1 to 26214400 (4k) blocks.
The filesystem on /dev/sda1 is now 26214400 blocks long.

$ df
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1            103212320   2230872  95739656   3% /
none                    874032         0    874032   0% /dev/shm

*1:id:hidea に書いておけといわれた。