ウィンドウのテスト2006年06月11日 01時12分20秒

前回に引き続き、今度は HTML でページ上に表示するウィンドウのようなものを作ってみた。サンプルはこちら。ソースはリンク先で「ソースを表示」して参照してちょ。

Ajax の開発環境である TIBCO が Ajax 上で動作していたりAjax で動作するデスクトップ環境なんてものまで存在する昨今、ウィンドウ一つ作って見せたところで別にどってことも無いんだが、それなりにわかりやすいソースを示したサンプルともなるとあんまりないんじゃなかろかのーということで。実用化の再には折りたためたりサイズ変更できたり表示・非表示を制御できるようにしたりして、これまでポップアップウィンドウで実現しようとしていたようなサイトのサイドツール (ヘルプ表示とか、サイトマップとか、メッセンジャーとか) を作るのに応用すると面白いかもね。

今回のサンプルだが、JavaScript にて記述した部分をいじらなければ、以下のような HTML を追記することによって簡単にウィンドウを増やすことができる。

<div class="window" id="ウィンドウID">
  <div class="titlebar">
    ウィンドウタイトル
  </div>
  <div class="client">
    <!-- ...表示する内容... -->
  </div>
</div>

ウィンドウ ID はウィンドウごとに違う文字列を指定する必要があるだよ (ウィンドウの識別に使用している為)。

今回書いてみたサンプルのポイントは以下の通り。

  • ウィンドウのドラッグ移動を制御するコードを、オブジェクト指向で記述してみた (windowMove オブジェクト)。まぁ、結果的にはあんまりオブジェクト指向にした意味無かったけどな。つか、JavaScript って、オブジェクト指向言語なのよ。
  • スタイルシートに JavaScript による振る舞いを記述することはできないので、<body> 要素の onload メッセージハンドラから呼び出す自前の関数の中で、titlebar クラスの <div> 要素を拾い上げて、メッセージハンドラの設定などをやっている。
  • タイトルバー部分にマウスカーソルを合わせてボタンを押下すると、その <div> 要素の onmousedown メッセージハンドラから呼び出される処理の中で、動かそうとするウィンドウに結び付けられた windowMove オブジェクトを、変数 capturing_window にセットする。ドラッグ中のマウス移動、およびマウスボタン解放時のハンドラは、<div> 要素のものではなく document のものを使用し、ハンドラの中で変数 capturing_window を参照して、現在移動中のウィンドウとして識別。こうすることで、マウスを思いっきり素早く移動してもちゃんとウィンドウが付いてくるようになる。ウィンドウ移動中でなければ capturing_window には null が入る。
  • ウィンドウ移動中でも、通常のドラッグ操作によって行われる動作 (すなわち、テキストの選択) が行われてしまうことがある。これを防ぐため、以下の対策を行っている。
    • IE の場合: ウィンドウのドラッグを開始する際の onmousedown ハンドラの中で、document.onselectstart メッセージハンドラに return false; する関数をセットする。これによって、ドラッグ操作によるテキスト選択が禁止される。ドラッグ終了時の onmouseup ハンドラの中で、document.onselectstart メッセージハンドラに return true; する関数をセットすることで、テキスト選択が行われる状態に戻る。この手法は多くのサイトで紹介されているが、IE でしか動作しないため、これだけでは不十分である。
    • IE 以外の場合: ECMA-262 準拠の JavaScript 実装を備えたブラウザであれば、event.preventDefault() メソッドの利用が期待できる。このメソッドは、ハンドラを呼び出しているイベントが、本来デフォルトで行うべき動作を、行わせないようにしてくれる。ボタン押下時、およびドラッグ中にこのメソッドを呼び出しておくことによって、テキストの選択を行わないだけでなく、それまで選択されていたテキストの選択範囲を変更しないでおくことも可能だ。
  • ウィンドウを表す <div> 要素は、position: fixed;、すなわち (本物の) ウィンドウに対する絶対位置として実装している為、例えば画面をスクロールしても、ウィンドウの、ブラウザ表示領域に対する表示位置は変わらない (つまり、一緒にスクロールされない)。これは、今回のサンプルでは、6.0 以下のバージョンの IE 以外での動作となっている。IE 6.0 以下では、position: fixed; が使用できない為、<body> 要素の onload メッセージハンドラの中で、position: absolute; を使用するように書き換えている。
    ここで、そんなことせんでもスタイルシートを以下のように書いてしまえばいいではないか、という声が上がりそうなものなんだが、
    div.window {
        position:           fixed   !important;
        position:           absolute;       // IE 6.0 以下
    /* ... */
    
    この場合、position: fixed; で動作できるはずの IE 7.0β2 においても position: absolute; として動作してしまうようなので、敢えて JavaScript の中で書き換えるという手法を選んでみた (つまり IE 7.0 β2 は CSS の !important をこのケースでは無視してしまうということ?)。

今回も、Firefox、IE、Opera にて動作確認済み。さすがに、メニューと比べればかなり複雑な実装になった。実際には位置を動かせるだけでは実用にはならないので、実用レベルで実装するにはもっと複雑なコードになる。でも、ブラウザ間の動作の違いなどに対するノウハウは、ここまでの実装で大体吸収できてるんではないかな。

あともう一つ。先日からたびたび紹介している「JavaScript ビジュアルリファレンス」ですが、JavaScript のプロトタイプベースなオブジェクト指向言語としての性質についてはちっとも触れられていません。その他、言語仕様的な部分の説明についても、やはり不十分な感は否めないです。その辺の部分がしっかり書かれた参考書をこれから探してみようかなぁなどと思う次第。。。やっぱ O'REILLY かなぁ。

とりあえずそんな感じで。

# ぷーさんて まさにいまの おいらだね 字足らず。