Firefox57.0にてmousedownイベントによるダイアログボックス表示中のmouseupの扱いが変わりました

katsuraFirefox, HTML, JavaScript

開発グループのkatsuraです。
Firefox57.0が先週リリースされましたね。
Firefox Quantumとなり、見た目が変わったり、今まで利用していたアドオンが使えなくなったりして混乱もあるようですが、表示速度が改善されたり、見た目がモダンになったりしているので、個人的には期待しています。

さてさて、デフォルトのフォントの変更等はあったものの、レンダリングの動作・見た目の変更はほぼ無いとされているFireFox57.0ですが、一部イベント周りの動きが変更されている点があり、それが起因で今まで動いていたJavascriptの動作が変わってしまうパターンを偶然発見しました。

今回はこの変更点について紹介させて頂きたいと思います。

Firefox57.0で変更された動作について

今回紹介するFirefox57.0での変更点とは、mousedownのイベント内でダイアログボックスを表示した場合、ダイアログボックス表示中でもmouseupの処理が必ず行われるようになった、というものです。

mousedownのイベント内でダイアログボックスを表示した場合の処理について、以前のFirefoxでは以下のような流れで処理されていました。なお、IE や Chrome も同様に動作します。

  1. ユーザがマウスのボタンを押した段階で、mousedownイベントが発生しブラウザがダイアログボックスを表示
  2. ユーザがダイアログボックス表示中にマウスのボタンを離す
  3. ユーザがマウス操作でダイアログボックスを閉じる
  4. mousedownイベント後、mouseupイベントは発生しない
  5. クリック対象がチェックボックス・ラジオボタンの場合でも、状態変更は行われない

一方、Firefox57.0では、以下のような動作になります。

  1. ユーザがマウスのボタンを押した段階で、mousedownイベントが発生しブラウザがダイアログボックスを表示
  2. ユーザがダイアログボックス表示中にマウスのボタンを離す
  3. ユーザがマウス操作でダイアログボックスを閉じる
  4. mouseupイベントが発生 (どうやら 2 のユーザの操作を受け付けている?)
  5. クリック対象がチェックボックスまたはラジオボタンだった場合には、チェックの状態変更などが行われる

主に、チェックボックスやラジオボタンにmousedownイベントをセットしていた場合や、一つの要素にmousedown・mouseupイベントの両方をセットしていた場合に動作が異なる可能性があります。

どういう場合に困るのか

では、具体的にどのような場合に従来想定していたものと異なる動作になってしまうのか、チェックボックスの例で見ていきたいと思います。

本来想定する動作

  1. mousedownイベント発生時、confirmを実行し、OKボタン・キャンセルボタンの表示されるダイアログボックスを表示する
  2. ダイアログボックスに対しての操作の結果下記にようにチェックボックスの状態が変化する
    • OKボタンがされた場合には、チェックボックスの状態を変更する
    • キャンセルボタンがされた場合には、チェックボックスの状態を変更しない

htmlソース

<html>
<body>
<script>
function mousedownEvent(element) {
  if (confirm("チェックを変更しますか?")) {
    var element = document.getElementById("checkbox1");
    element.checked = !element.checked;
  }
}
</script>
<input id="checkbox1" type="checkbox" onmousedown="mousedownEvent();"/>checkbox1<br />
</body></html>

実際の動作について

以前の Firefox ではブラウザ側でmouseupが実行されないので、想定した通りに動きます。IE や Chrome でも同様に動作します。

一方、Firefox57.0では、Javascript側でチェックボックスを変更後、ブラウザのmouseupが実行されてチェックボックスの状態が変更されてしまうので意図通りの動きをせず、下記のように想定と真逆に見える動作をしてしまいます。

  1. mousedownイベント発生時、confirmを実行し、OKボタン・キャンセルボタンの表示されるダイアログボックスを表示する
  2. ダイアログボックスに対しての操作の結果下記にようにチェックボックスの状態が変化する
    • OKボタンがされた場合には、チェックボックスの状態を変更しない
    • キャンセルボタンがされた場合には、チェックボックスの状態を変更する

OK ボタンが押された場合、Javascript 側でチェックボックスの状態が変更されるのですが、mouseup を受け付けたブラウザもチェックボックスの状態を変化させてしまうため、相殺して元の状態に戻るわけです。

キャンセルボタンが押された場合、 Javascript 側は何もしませんが、mouseup を受け付けたブラウザがチェックボックスの状態を変更するため、結果状態が変化された状態になります。

対策について

例えば、以下のように遅延処理を行うことで対策を行うことが出来ます。
あるいは、mousedownのイベントにて上手く分岐を行うことで、スマートな解決ができる可能性もあるかもしれません。
<html>
<body>
<script>
function mousedownEvent(element) {
  var element = document.getElementById("checkbox1");
  var checked = element.checked;
  if (confirm("チェックを変更しますか?")) {
    checked = !checked;
  }
  setTimeout(function () {
    element.checked = checked;
  }, 0);
}
</script>
<input id="checkbox1" type="checkbox" onmousedown="mousedownEvent();"/>checkbox1<br />
</body></html>

最後に

今回の動作変更について、Firefox57.0の変更点一覧には載せられていませんでしたので、意図しない動作変更の可能性もあり、今後のバージョンアップで元に戻る可能性もあるかと思います。
ただ、現時点ではFirefox57.0以降で変更が行われるのかどうか判明しておりませんので、どちらの動作でも上手く動くような修正を行うのが良さそうです。

参考サイト

katsuraFirefox, HTML, JavaScript

Posted by katsura