←これの話。

いわゆる普通のwebサイトでファイルを選択させるだけならかなり便利でいけてるこのファイル選択フォームだけども、ちょっと凝ったwebサイトになってくるとやはりというか見た目通りといかあまりいけていない。

ならこのファイルフォームは非表示にしておいて好きなタイミングでクリックイベント発行してやればいいではないか、 どん。

<html>  
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
    </head>
    <body>
        <div id="label">好きな要素</div>
        <input type="file" id="file-button" style="display:none">
    </body>
    <script>
        var myFunc = function() {
            $("#file-button").click();
        };

        $("#label").on("click", function() {
            myFunc();
        });
    </script>
</html>  

実は本当にこれだけでいい、IE11でもFireFoxでもiOS9&safariでもこれで動いた。

一見するとなんだそれだけかで終わる話なのだが、実はこのコードにはハマりどころが隠れている。
実際にそのハマりどころを知らなかったためにここしばらく予期せぬ挙動に悩まされていた。

先ほどのコードの一部をこう変更してみる。

$("#label").on("mousedown", function() {
    myFunc();
});

バインド先のイベントを変更しただけ。なのにこのコードはFireFoxとiOS9&safari環境で動かない。
動かないことはないが、ファイル選択ダイアログは起動できない。
iOS8環境ではこのコードでも動いていたのに、それがiOS9になった途端動かなくなってしまったので改めて色々試してみるはめになったという経緯。

つまりは、 ユーザが起こしたクリックイベントの中でのみ、ファイルフォームのクリックイベントをコードから発行することができる。 うまい用語がわからないが、関数呼び出しスタックの大本がユーザによるクリックイベントであることとかそういう感じ。

FireFoxでコードからファイルフォームのクリックイベントが発行できないことは前々から判明していてその解決策もwebで結構見つかるが、どの方法も上記の原則に従ったうえでの解決策のはず。実際適当な場所から解決例コードを実行してみてもファイル選択ダイアログはうんともすんとも動かなかった。

むしろこの原則を守ること以外に何もしなくていいのではないだろうか。
ただ残念なことに、この原則を守らない、ユーザがクリックイベントを起こしたかどうかにも依らないタイミングでファイルフォームのクリックイベントを発行する方法は全く見当がつかない。