2013年2月15日

jQueryのイベントで return false はしない方が良い

前回の記事を書いている時に検索にヒットしたリンクでちょっと「へぇ~っ」となったものがあったのでメモ。

 javascript - event.preventDefault() vs. return false - Stack Overflow

イベントのハンドラを書く時に、jQueryのイベントと通常のDOMのイベントでは

return false;

の意味が違うらしい。まずい、今まで気にしていなかった。。。


jQueryのイベント:

  •   デフォルト動作を抑止。
  •   イベントバブリングを中止する


通常のDOMのイベント: 

  •   デフォルト動作を抑止。(但しブラウザのバージョンに依存)
  •   イベントバブリングの中止はしない


という事らしい。


jQueryのイベントハンドラで return false; をしてしまうと、イベントバブリングまで中止されてしまう。これはあまり好ましくない事だ。

なぜイベントバブリングを中止する事が好ましくない(or やってはいけない)のかは、下の記事を読めばよく分かる。


jQuery Events: Stop (Mis)Using Return False | Fuel Your Coding


jQueryのバブリングと、「return false;」「e.stopPropagation();」「e.preventDefault();」について | ふじこのプログラミング奮闘記


JavaScriptのイベント伝播について覚書 | Linuxで自宅サーバ構築




結論



jQueryのイベントハンドラでは、

1. デフォルト動作を抑止するには、event.preventDefault() を 使う。

2. バブリングを中止する必要がある場合は、event.stopPropagation() もしくは
event.stopImmediatePropagation() を場面に応じて使い分ける。

3. return false は親要素にもイベントハンドラがアタッチされている場合などにバグの原因になり得るので、使う場合は十分に注意する。(もしくは使わない。)

というのが良いみたいだ。







  

[jQuery] Enterキーでフォーカスを移動するには

Enterキーでフォームを送信したくない時は


あるWebアプリケーションのフォームで、Enterキーを押してもSubmitされない様にする必要があって、ちょっと調べた。

リターン(Enterキー)でフォームを送信しない方法: 小粋空間

とりあえずこの記事の「4.押されたキーを判定して抑止する」の所に書いてある方法で対応出来た。


Enterキーで次のフィールドにフォーカスを移動するには


次に、どうせならEnterキーで次のフィールドにフォーカスを自動で移動させたいな~、という事になった。やってみたら、jQueryのおかげでこんな感じで割りと簡単に出来た。

Enterキーが押された時にfalseを返すのではなくて e.preventDefault() を使う様に変えた。その理由はこちらを参照。


Shift+Enterキーにも対応するには


さらについでにShift+Enterキーでの逆順の移動にも対応させてみた。




もっとキーイベントを細かく制御するには


こんな感じで作りだすと、欲が出てきてさらにファンクションキーや矢印キーにも対応したくなってくる。でも、自分で作らなくても何かあるんじゃないかな~という気もする。

探してみたら次の様なjQueryプラグインが見つかった。
Enter/Tab項目移動とFunctionKey制御をplugin化 - せかにゃ~

これで機能的には申し分無さそうだ。ただソースコードを見ると対象のフォームがdocument.forms[0]に固定されていたりするので場合によっては少し変更する必要があるかも知れない。


キーイベントを拾って独自の関数を実行するだけならこういうのもあった。(フォーカス移動の処理は自分で書く必要があるみたいだ。)
jQuery.gpKeyでキー操作が楽々に。 | Ginpen.com



最近はWindowsアプリケーションをWebに置き換える案件も多いので、きっとこの様なプラグインは役に立つと思う。




 

2013年2月14日

Azure仮想マシン上でNode.jsアプリケーションをデーモン化してユーザー権限で運用する方法

作ったNode.jsアプリケーション


初めてのNode.jsアプリケーションを作ってみた。
作ったのは、ここに載っていたもの。
Androidアプリからnode.js+Socket.IOと双方向通信する

早速Windows Azure上で動かそうと思ったのだけれど、いくつか苦労したのでメモしておきたい

「Windows Azure Web Sites」は現状ではWebSocketは不可


まず、「Windows Azure Web Sites」は現時点では使えない。このサービスのベースとなっているIISのバージョンが7.5で、まだWebSocketプロトコルに対応していないからだ。

試しにやってみると、ブラウザ同士で試すと問題なく動くが、実際にはWebSocket以外のプロトコルにフォールバックして動作している。この状態だとAndroidのネイティブアプリケーションからsocket.ioライブラリを使用しての接続は上手く行かなかった。

近い将来これが IIS8.0 にアップデートされてWebSocketが使える様になったら、多分これから下に書く様な面倒な作業は不要になると思う。


「Windows Azure 仮想マシン」でUbuntuサーバーを立てる


仕方ないのでAzure上にUbuntu仮想マシンを立ち上げる事にした。

Ubuntu 12.04 Serverのインスタンスを起動して、Node.jsやその他のパッケージをインストールするのは、何の問題もなく完了。

 node folder/app.js

で起動して3000番ポートで接続を待ち受ける。と同時にAzure仮想マシンの設定でエンドポイントを追加して、外側の80番ポートを内側の3000番ポートにつなげる。これでブラウザからもAndroidアプリからも接続出来て問題無く動作させる事が出来た。

素晴らしい!

ただ、Android側のネットワークをWiFiから3G回線にすると動作しなくなるという現象に遭遇した。どうやらキャリア側で80番ポート上のWebSocketの通信を遮断しているみたいだ。(というよりおそらく、キャリアが使っているProxyサーバーがWebSocketに対応していないのだと思う。)

これに対する対策として、Azure側のエンドポイントのポート番号を443に変更したら問題なく動作する様になった。(特に443番でなくてもいいと思うけれど、ユーザー側にFirewallがある場合に、外向きのTCPパケットがブロックされている可能性が80番の次に低いポート番号という事で、443番にしておいた。)


Node.jsアプリケーションをデーモン化したい


Node.jsのアプリケーションをデーモン化して動かすには、forever を使うのが簡単らしい。

foreverコマンドを実行するスクリプトを rc.localに追加するなり、/etc/rc2.d フォルダにシンボリックリンクを張るなりすればサーバー起動時に自動で実行される様になる。


ユーザー権限でデーモンを実行したい


ただ、root権限ではなくユーザー権限で実行する方法がすぐには見当たらなかったので、調べるのにちょっと時間がかかった。結論としては次の2つのどちらかが良さそうだ。

方法1: suコマンドと forever を使う

 su - [user] -c"cd [/home/directory] && forever start [folder]/app.js"

というコマンドへのシンボリックリンクを /etc/rc2.d フォルダに作成する。(または/etc/rc.localの最後に追加する。)


方法2: Upstartを使う
 

 Upstart を使ってお手軽 daemon 化 - インフラエンジニアway

ここに書いてある方法で initctl コマンドでデーモンとしての実行を管理出来る様になる。
実行ユーザーを指定するには、

 setuid [user]

を設定ファイルに追加すればOK。


Ubuntuの標準的な方法としては Upstart を使う方が良さそうなので、とりあえず今はこれでいいかな、と思う。