オリジナルのダイアログを閉じた時に、元の要素にフォーカスを戻す方法

[`evernote` not found]
[`livedoor` not found]
[`yahoo` not found]

先日、コーディングWebアクセシビリティ – WAI-ARIAで実現するマルチデバイス環境のWebアプリケーションという本を読みました。Webアクセシビリティについて書かれた実践的な本で、WAI-ARIAについて全くと言っていいほど知らなかった自分には、もっと入門的な本も必要だと思いました(本の内容が難しいとうわけではありません。書いてあることは易しかったのですが、自分はこの本の想定読者のレベルに達してないというだけです)。ただ、この本を読んでもっとWebアクセシビリティを意識したサイトを作っていこうと思えたので、そういう意味では読んでよかったと思います。

さて、本を読み終わったらいつもブクログに本の感想というか批評というか日記というか、とにかくその本について思ったことを書くのですが、なんと今回はそのレビューページを、この本の編集の方に見てもらえたらしく、さらにレビューに書いた疑問を監訳者の方にまで見てもらえたようです(『コーディングWebアクセシビリティ – WAI-ARIAで実現するマルチデバイス環境のWebアプリケーション』のレビュー ヘイドン・ピカリング (amano225さん) – ブクログ)。たまにこうやって関係者からのコメントをもらえることがあるのですが、見られることを想定して書いてるわけではないので、嬉しくもありますが、どこか恥ずかしい気もちもあり、複雑なところです(さすがにオープンな場に書いている以上、見られたくないとは思っていません)。

ところで、自分が疑問に思ったのは本書の最後にほうに書いてあるダイアログについての記述です。ダイアログを閉じる時に、そのダイアログを開く前にフォーカスのあった要素にフォーカスを戻しましょうと書かれてあったのですが、それがあまりにも冗長のように思いました。本書には下記のように書いてありました。

ダイアログを開く時の処理

ダイアログを閉じる時の処理

つまり、開いた時にフォーカスがある要素のIDを取得し、なければその要素に’origin’というIDをつける(IDをつける処理は省略)。そして、閉じる時にそのIDから要素を選択して、その要素をフォーカスするという記述です。

なんだか冗長です。自分は下記のようにしたほうがいいのではないかとブクログに書いた次第です。

ダイアログを開く時の処理

ダイアログを閉じる時の処理

編集の方によると、確かにこちらのほうがいいだろうとのことでした。自分の意見が認められたみたいでうれしいです(意見したつもりはないのですが)。

さて、ここまでは余談です。今回、実際に作ってみることにしました。まず、HTML内にダイアログ用の記述として下記のような記述を追加します。

.dialog__layerはレイヤー用ですが、#TestDialogの背景をrgbaで指定しても同じことになるので、必要ないかもしれません。

CSSは下記のようにしました。クラスの命名は最近話題のBEMっぽくしてみました(参考:BEMを参考にしたCSS設計 – Qiita)。

次にJavaScriptの記述です。

何をしているかというと、ダイアログを開いた時にdocument.activeElementで現在フォーカスしている要素を取得しています(参考:JavaScriptでフォーカスのあたっている要素を取得する「document.activeElement」: 小粋空間)。そして、その要素をjQueryのdataメソッドでダイアログ用のタグに”back-focus”というキーで紐付け、ダイアログ内のボタンをおした時にその要素を取得してフォーカスを元に戻すという処理を行っています。

試しに、テキストボックス内に郵便番号を入力してエンターキーを押すと、書式が正しくなければ”正しい書式で入力してください”、正しければ”OKです”と表示するサンプルを作成してみました。
実行サンプル:ダイアログのテスト

エンターキーを押したらダイアログがでて、そのままエンターキーを押したらフォーカスが元に戻るのが分かると思います。注意点として、エンターキーをおした時にダイアログを表示する場合は、下記のようにe.preventDefault()がないとすぐに閉じてしまうようです。

特にこだわりがなければ、alertメソッドを使えばいいだけの話なんですけどね。ダイアログのレイアウトも変更したいという場合に。

ところで、document.activeElementという指定はつい最近知ったのですが、調べてみるとIE4の時からあった指定方法だそうです(document.activeElement – Web API インターフェイス | MDN)。昔からある手法ななのに、初めて知ることがあると、自分はまだまだ全然JavaScriptを分かってないんだなと思います。

IE10モード以上のHTAでHTA:APPLICATIONオプションを使う方法

[`evernote` not found]
[`livedoor` not found]
[`yahoo` not found]

このところの仕事は、入社してから今までなかったほどの忙しさです。仕事が終わったと思ったら、次の仕事がどこからともなく舞い込んできます。しかも、人が少ないせいで、やってる仕事のプロジェクトはほぼ一人でやっている感じがします(たまに、上司にお願いや相談や報告をするぐらい)。

そんな中、既存のウェブサイトに似たローカルアプリを作る必要がありました。しかも、ローカルにファイルを保存したりデータベースを読み書きしたりする必要があるとわかり、いろいろ悩んだすえ、HTAを使うことにしました。
参考:HTAを利用したウインドウ付きアプリケーション – マンガで分かる JavaScriptプログラミング講座

標準だと、HTAはIE7モードで起動してしまいますが、canvasを使うこともあり、metaタグでIE10モードとしました。Ajaxを使いたかったのですが、IE11からローカルだとAjaxを利用できないと分かり、IE10モードにしました。よくよく考えると、ActiveXObjectが利用できるので、最終的にはそんなことする必要なかったんですが……。
参考:VBScript + HTA(HTML Application)で Canvas を使う方法 – CX’s VBScript Diary – VBScript グループ
参考:IE11のActiveXObjectはfunctionとして存在しているが!!window.ActiveXObjectがfalse – イム日記

だけど、ここで問題が発覚。なんと、aタグでリンクをつけて同じ階層のファイルに移動しようとすると、IEが開いてしまうではないですか!! いろいろ調べてみると、HTA:APPLICATIONタグでNAVIGABLE属性を”yes”にすると同じウィンドウで開くということが分かりました(なぜデフォルトが”no”なのか不思議でなりません)。なので、設定してみたのですが、なんとIE10からこのHTA:APPLICATIONタグによる設定はなくなったとのこと。
参考:IE10 の HTA 問題 – ※ただの日記ブログです※

なので、IE9モードにしたのですが、CSSでグラデーションの指定が効きませんでした。IE9には対応していないようです。まあ、正直そこはそんなに問題ないのですが、それでもやっぱりIE10モードで使いたいなと思って試行錯誤していると簡単に解決しました。

やり方としては、リダイレクト用のhtaを用意して、下記のように記述するだけ。

ここでは、”ie10-hta.hta”が実際に利用するアプリです。拡張子はhtaではなく、htmlでも問題ありません。自分は拡張子htmlで作成して、開発時にはIEで開いて確認しました。IEだと、F12 開発者ツールを使ってデバッグできるためです。

ところで、今回作成したアプリは、タッチでの動作でも対応するようにしていたのですが、ここで問題が発覚しました。なんと、HTAのほうではポインター イベントがありませんでした。例えば、scriptタグ内に『alert(window.navigator.msPointerEnabled);』と記述すると、IEで開いた場合には、『true』となるのにたいし、HTAで開くと『false』となりました。仕方なく、mousedownやmousemoveで対応したのですが、なぜかタッチした時ではなく、離した時にmousedownイベントが発生してしまうという……。どうすりゃいいんだ……。