ポップアップイベント
ポップアップやメニューに関連するイベントにはいくつかの種類があります。
以下の一覧はそれらのイベントの概要です。
contextmenu |
コンテキストメニューを開くように要求したときに、キーボードとマウスのどちらによって開かれるかに関わらず発生する。このイベントは、コンテキストメニューを関連付けられていない要素に対しても発生する。詳しい利用法はコンテキストメニューイベントを参照。 |
---|---|
popupshowing |
menupopup 、panel 、tooltip において、それらが表示される直前に発生する。一般に、コンテキストに基づいてポップアップ上のアイテムを追加または調整するのに使用される。 |
popupshown |
menupopup 、panel 、tooltip において、それらが表示されるとすぐに発生する。 |
popuphiding |
menupopup 、panel 、 tooltip において、それらが隠されようとするとすぐに発生する。ユーザがメニューからアイテムを選択した場合にも、他の部分をクリックしてポップアップを閉じた場合にも発生する。 |
popuphidden |
menupopup 、panel 、 tooltip において、それらが隠されるとすぐに発生する。 |
popupshowing
イベント
ポップアップが表示される直前には、そのポップアップで popupshowing
イベントが発生します。このイベントは、ポップアップが開かれる方法に関係なく、ユーザの操作によって開かれた場合にも、スクリプトから openPopup
メソッドや openPopupAtScreen
メソッドを呼び出した場合にも発生します。popupshowing
イベントのリスナーは、一般にコンテキストに基づいてポップアップの内容を調整するのに使用されます。たとえば画像上で右クリックしたら画像に関係するアイテムをコンテキストメニューに表示し、リンク上で右クリックしたらリンクに関係するアイテムを表示するといったことができます。popupshowing
イベントリスナーでは、メニューが表示される前に、必要に応じてメニューの追加や変更を行うことができます。popupshowing
イベントのコンテキストメニューに対する使用例はコンテキストによるメニューアイテムの表示非表示を参照してください。
また、この方法はどんな種類のポップアップにも使用できます。この例では、パネル内部のラベルが現在の時間に基づいて初期化されます。
<panel id="time-panel" onpopupshowing="this.lastChild.value = (new Date()).toLocaleFormat('%T')"> <label value="Time:" /> <label id="time" /> </panel> <toolbarbutton label="Show Time" popup="time-panel" />
popupshowing
リスナー内から preventDefault
メソッドを呼び出すことにより、メニューやポップアップの表示を抑止することができます。popupshowing
イベントのデフォルトの動作は、ポップアップの表示を継続させることです。preventDefault メソッドはこの動作の発生を抑止するため、ポップアップは開かれなくなります。
<menu label="Edit"> <menupopup onpopupshowing="if (gDisallowed) event.preventDefault();"> <menuitem label="Undo" /> <menuitem label="Redo" /> </menupopup> </menu>
この例では、グローバル変数 gDisallowed
をチェックしたあと、 preventDefault
メソッドを呼び出しています。If you want to prevent a context menu from opening it is better to call preventDefault
with a handler for the contextmenu event instead, to avoid the extra steps necessary to fire the popupshowing
event if it isn't needed.
入れ子のサブメニューを使う時には、popupshowing
イベントの中で、そのイベントが適切なポップアップに対応するものかどうか必ず確認するようにしてください。なぜなら、ポップアップイベントは浮上 (bubble)するので、親メニューはそれ自体が開いた時にも、サブメニューが開いた時にも popupshowing
イベントを受け取るからです。例を示します。
<menu label="File"> <menupopup onpopupshowing="if (event.target == this) adjustFileMenu(this);"> <menu label="Open"> <menupopup> <menuitem label="File..." /> <menuitem label="Page" /> </menupopup> </menu> </menupopup> </menu>
イベントのターゲットを調べて、イベントが目的の menupopup に対応するものかを調べています。このようにしなければ、関数 adjustFileMenu は外側の menupopup が開かれた時にも、内側の menupopup が開かれた時にも呼び出されてしまいます。イベントの浮上はすべてのポップアップイベントで発生します。
popupshown
イベント
popupshown
イベントは、ポップアップが表示されるとすぐに発生します。openPopup
メソッドや openPopupAtScreen
メソッドを呼び出した場合、ポップアップはそれらのメソッドが返るまで開かれません。したがって、popupshown
イベントはスクリプトが終了し、UI が更新されるとすぐに発生します。popupshown
イベントはこれがいつ起こるかを知るのに役立ちます。
popupshown
イベントの利用法の 1 つとして、他のメニューを開くために使用する方法があります。この方法は、次の例のように、プログラムからサブメニューを開かなければならないときに必要になります。なぜなら、親メニューを開かずにサブメニューを直接開くことはできないからです。
<script> function openFileMenu() { var filemenu = document.getElementById("file-menu"); filemenu.addEventListener("popupshown", fileMenuOpened, false); filemenu.open = true; } function fileMenuOpened(event) { if ( event.target != document.getElementById("file-menupopup") ) { return; } var filemenu = document.getElementById("file-menu"); filemenu.removeEventListener("popupshown", fileMenuOpened, false); var openmenu = document.getElementById("open-menu"); openmenu.open = true; } </script> <menu id="file-menu" label="File"> <menupopup id="file-menupopup"> <menu id="open-menu" label="Open"> <menupopup> <menuitem label="File..." /> <menuitem label="Page" /> </menupopup> </menu> </menupopup> </menu> <button label="Open" oncommand="openFileMenu();" />
ボタンを押すと、関数 openFileMenu
が呼ばれます。この関数は、 addEventListener
メソッドを使って "File" メニューに popupshown
イベントリスナーを取り付けます。これにより、"File" メニューで popupshown
イベントが発生すると、関数 fileMenuOpened
が呼ばれるようになります。
関数 fileMenuOpened
は、まずイベントのターゲットが適切なポップアップかどうかを調べ、そうでなければすぐに返ります。次に、popupshown
イベントリスナーをふたたび削除します。イベントリスナーが重複して追加されないようにするため、必ずこれを実行しなければなりません。最後に、関数 openFileMenu
と同じ方法を使って "Open" サブメニューを開きます。このようにすると、外側のメニューと内側のメニューの両方を開くボタンが完成します。
popuphiding
イベント
ポップアップが閉じると、画面から消える直前に、そのポップアップで popuphiding
イベントが発生します。popuphiding
イベントに対するリスナーを利用すると、popupshowing
イベントとは逆に、ポップアップ上のアイテムをふたたび削除したり隠したりできます。popuphiding
イベントは、ポップアップが隠された方法に関わらず、ユーザがメニューからアイテムを選択した場合でも、ポップアップの外側をクリックした場合でも、Escape キーを押してメニューをキャンセルした場合でも発生します。また、popupshowing
イベントと popuphiding
イベントは、ユーザがメニューバー上でマウスを動かして、メニューやサブメニューを表示させたり隠したりした場合にも発生します。
この例では、ポップアップが隠れるたびに textbox
の内容が消去されます。
<panel onpopuphiding="document.getElementById('search').value = '';"> <textbox id="search" /> <button label="Search" oncommand="doSearch();" /> </panel>
イベントの preventDefault
メソッドを呼び出すと、ポップアップが非表示になるのを抑止することができます。そうすると、ポップアップは閉じられなくなります。通常は、これはするべきではありません。たとえば、確実に値が入力されるようにしたければ、値が入力されていなくてもコードがそれを処理できるように UI を作り直した方がはるかに良いでしょう。そうしないと、ユーザはポップアップが閉じられないことに混乱してしまいます。
ユーザがメニューの中から何かを選択した場合には、 menupopup
が閉じるのをキャンセルすることはできません。キャンセルするにはすでに遅すぎるからです。この場合、選択された menuitem にすでに command
イベントが送られており、その操作はすでに実行されています。これは、ポップアップが取り除かれた後に popuphiding
イベントが発生する特殊なケースの 1 つです。こうなっている理由は、非常によくあるケースである、メニューアイテムの動作がモーダルダイアログを開くものである場合のためです。この場合、ダイアログが開かれる前に、まずメニューを取り除く必要があります。そうしないと、すでにアクティブではない親ウィンドウにメニューが残されたままにされてしまいます。そのため、ポップアップがまず取り除かれるのです。すなわち、popuphiding
イベントはモーダルダイアログが閉じられるまで発生しないということに注意してください。
メニューが閉じられても popuphiding
イベントが発生しない場合があります。そのため、popuphiding
イベントリスナでは必要なコードを呼び出さないようにするべきです。メニューやポップアップを再初期化する場合には、popupshowing
イベントで行う方が良いでしょう。popuphiding
イベントが送られないケースの 1 つは、メニューがドキュメントから削除された場合です。これはイベントを送る対象となる要素がすでに存在しないからです。もう 1 つは、ドキュメントがアンロードされた場合です。
popuphidden
イベント
popuphidden
イベントは、ポップアップが閉じられた後に発生します。
メニューが連鎖的に開かれている場合、すなわち、あるメニューと少なくとも 1 つの階層のサブメニューが開かれている場合、まず最も低い階層の【訳注: 最も深い】サブメニューで popuphiding
イベントが発生します。それからそのメニューが閉じ、popuphidden
イベントが発生します。そして、次に高い階層のメニューで、すべてのメニューが閉じられるまでこの行程が繰り返されます。すなわち、サブメニューが長く連なって開かれている場合、popuphiding
イベントと popuphidden
イベントが順番に何度も発生するということになります。最上位のメニューが popuphidden
イベントを受け取った時、すべてのメニューが閉じられたことを知ることができます。