3

次のマークアップを含む DHTML ダイアログ ボックスを想像してください。

<div id="someDialog" class="dialog">
    <h2>Title of dialog</h2>

    Lots: <input ...>
    of: <select ...>
    controls: <textarea ...>

    <input type="submit" value="OK">
    <input type="reset" value="Cancel">
</div>

ユーザーは、エスケープを押してダイアログをキャンセルすることを期待します。これ自体は難しいことではありません。keydown イベント ハンドラーを document.documentElement に追加して ev.keyCode == 27 をチェックし、それを使用してページの一番上のダイアログを閉じます。

問題はこれです。ブラウザが最初にエスケープ キーを認識することが重要な特定の状況があります。たとえば、ブラウザで のオートコンプリート メニューが表示された場合、Esc キーを<input type="text">押すと、ダイアログがキャンセルされるのではなく、それがキャンセルされます。のドロップダウン/ポップアップ メニューを表示する場合、Esc キーを<select>押すと、ダイアログではなく、それが閉じます。

ブラウザが何かのためにエスケープキーを押す必要がない場合に限り、ウィンドウのエスケープキーをどのように処理しますか?


編集: Stack Exchange 自体にこの問題があります。「質問への回答をメールで送信しますか?」をクリックすると、リンクをクリックすると、DHTML ダイアログ ボックスが開き、タブで頻度ドロップダウンに移動し、alt-down を押してドロップダウン メニューを開き、エスケープしてドロップダウン メニューを閉じると、ダイアログ全体が閉じます。これは起こらないはずです。このような状況では、ブラウザーのコントロールの実装では、最初にエスケープ キーを選択する必要があります。

4

1 に答える 1

2

適切な調査と試行錯誤の後、ここでの最善/唯一の解決策は、独自のカスタム フォーム コントロールを作成することのようです。


以下は、問題を解決するための失敗した試みです。

http://jsfiddle.net/CoryDanielson/4jBgs/10/

これが基本的にどのように機能するかです。


まず、ユーザーが注目している入力activeInputを格納する変数があります。DOMElement(入力がエスケープ可能な場合のみ)

var activeInput = false;

この変数を設定するために、あなたが言及したDOMElementsの配列を作成しましたescaped(オートコンプリート、選択要素のあるテキストボックス)

var escapableElements = [];
escapableElements = escapableElements.concat(
    Array.prototype.slice.call(document.getElementsByTagName('select')),
    Array.prototype.slice.call(document.getElementsByTagName('input'))
    //add more elements here
);

次に、配列をループしてand (フォーカスを失う) イベントにアタッチeventListenersします。(この投稿の下部に for each 関数を含めました)focusblur

forEach(escapableElements, function() {
    this.addEventListener('focus', registerActiveElement);
    this.addEventListener('blur', deregisterActiveElement);
});

function registerActiveElement() {
    if (!activeInput)
        activeInput = this;
    //console.log('registered'); //testing only
}

function deregisterActiveElement() {
    if (activeInput)
        activeInput = false;
    //console.log('deregistered'); //testing only
}

その後、イベントeventListener用に配線しました。keydownその中に、あるactiveInput場合return true;はブラウザが必要なことを実行できるかどうかを確認しました(オートコンプリートからのエスケープなど)がない場合は、押されたactiveInputかどうかを確認して呼び出しますESChide_dialog_box(event.keyCode);

キープレスの処理に関する質問の段落との唯一の違いは、事前ESCにあったかどうかを確認したことです。activeInputがある場合activeInput、私は何もしませんでした (ブラウザーに ESC をネイティブに処理させます) ない場合は、ブラウザーの ESC のネイティブ処理をキャンセルし、関数をactiveInput呼び出してから、ブラウザーがキープレスを処理するのを防ぐのにも役立ちます。event.preventDefault()hide_dialog_box(keyCode)return false;ESC

document.addEventListener('keydown', function(event) {
    if (!activeInput) {
        if (event.keyCode == 27) { //esc
            event.preventDefault();
            hide_dialog_box(event.keyCode);
            return false;
        }
    } else {
        return true; //if active input, let browser function
    }
    /*
        if the browser prompts with an autocomplete menu for 
        <input type="text">, or options on a <select> drop down
        pressing escape will cancel that, not cancel the dialog. 
    */
});

コードの最後の 2 つのスニペットは、関数と、呼び出されhide_dialog_box(keyCode)た関数をループするために書いた関数です。NodeListescapableElements

function hide_dialog_box(keyCode) {
    var dialog_box = document.getElementById('dialog_box');
        dialog_box.style.display = 'none';
}

function forEach(list, callback) {
    for (var i = 0; i < list.length; i++)
    {
        //calls the callback function, but places list[i] as the 'this'
        callback.call(list[i]);
    }
}
于 2012-04-16T18:44:57.750 に答える