PopupEvents

ポップアップやメニューに関連するイベントにはいくつかの種類があります。

以下の一覧はそれらのイベントの概要です。

contextmenu コンテキストメニューを開くように要求したときに、キーボードとマウスのどちらによって開かれるかに関わらず発生する。このイベントは、コンテキストメニューを関連付けられていない要素に対しても発生する。詳しい利用法はコンテキストメニューイベントを参照。
popupshowing menupopuppaneltooltip において、それらが表示される直前に発生する。一般に、コンテキストに基づいてポップアップ上のアイテムを追加または調整するのに使用される。
popupshown menupopuppaneltooltip において、それらが表示されるとすぐに発生する。
popuphiding menupopuppaneltooltip において、それらが隠されようとするとすぐに発生する。ユーザがメニューからアイテムを選択した場合にも、他の部分をクリックしてポップアップを閉じた場合にも発生する。
popuphidden menupopuppaneltooltip において、それらが隠されるとすぐに発生する。

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 イベントを受け取った時、すべてのメニューが閉じられたことを知ることができます。

添付ファイル

ファイル サイズ 日時 添付者:
Controlsguide-button-menu.gif
1371 バイト 2008-04-03 21:23:29 Zachary8222
Popupguide-popupshowing.png
7221 バイト 2007-07-27 02:45:26 Enn

Document Tags and Contributors

Contributors to this page: Shoot, ethertank, nobuoka, Milly
最終更新者: ethertank,