2012-04-16 77 views
3

DHTML對話框具有以下條件的標記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> 

用戶會期望擊中逃跑取消對話框。這本身並不困難 - 只需在document.documentElement中添加一個keydown事件處理函數來檢查ev.keyCode == 27,並使用它來關閉頁面上的最頂層對話框。

問題是這樣的 - 在某些情況下瀏覽器首先看到轉義鍵很重要。例如,如果瀏覽器用<input type="text">的自動完成菜單提示,則按下轉義應取消該操作,而不取消該對話框。如果您彈出<select>的下拉菜單/彈出式菜單,則按下轉義應關閉該對話框,而不是對話框。

當且僅當瀏覽器不需要轉義按鍵的某些東西時,您如何安排處理窗口的轉義鍵?


編輯:Stack Exchange本身就有這個問題。如果我點擊「您想通過電子郵件向您發送問題的答覆嗎?」鏈接,它打開一個DHTML對話框,然後標籤到頻率下拉菜單,按下alt-down打開下拉菜單,然後退出關閉下拉菜單,整個對話框關閉。這不應該發生。在這種情況下,瀏覽器的控制實現應該首先在轉義鍵上進行選擇。

+0

我在工作的東西遐寫信給循環。當你關注某些HTML元素時,你需要將它們註冊爲活動狀態,並且當你點擊轉義時,你需要查看是否有任何元素是「活動的」,如果是的話,允許轉義行爲本身,否則關閉對話框 – 2012-04-16 17:58:44

回答

2

經過一些體面的研究和試驗/錯誤,最好/唯一的解決方案似乎在創建您自己的自定義窗體控件。


以下是解決該問題的失敗嘗試。

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

這裏的基本上它是如何工作的。


首先,有一個變量activeInput存儲該輸入的DOMElement用戶被聚焦。 (僅當輸入是允許脫離)

var activeInput = false; 

爲了填充這個變量,我創建你提到可以escaped(文本框與自動完成,選擇元素)

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

然後通過該陣列環路,並附加eventListenersfocusblur(失去焦點)事件。 (ⅰ包括在這篇文章的底部各功能)

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爲​​事件。裏面的,我檢查,看看是否有一個activeInput如果有,我只是return true;這將讓瀏覽器做就是了(從自動完成逃避等等)如果沒有一個activeInput,我檢查是否ESC被按下,並且致電hide_dialog_box(event.keyCode);

與您的問題中有關處理ESC按鍵的段落唯一的區別是我檢查是否有activeInput預先。如果有activeInput,我什麼都沒做(讓瀏覽器本地處理ESC),如果沒有activeInput我叫event.preventDefault()這將取消瀏覽器的ESC本機處理,然後調用函數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個snippits是功能hide_dialog_box(keyCode)和我寫的函數通過NodeList稱爲escapableElements

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]); 
    } 
} 
+0

好吧,兩個想法......首先,我的對話框是動態生成的(來自AJAX,來自手動構建),並且可以隨時隨地添加控件。我已經考慮過在頁面上隱藏每一個控件的代碼,但它不會工作,因爲任何添加了控件的代碼都會破壞它。 – 2012-04-16 19:30:54

+0

(GRR,註釋大小限制) --- newpara --- 更糟的是,你的解決方案塊給定的控件中逃脫** **完全。 --- newpara --- 這是一個很好的例子,如果你在Windows中。打開運行對話框,然後打開最近命令的下拉菜單,方法是輸入,按alt-down或單擊下拉按鈕。 --- newpara --- 按一次退出:此下拉列表關閉。再次按下轉義鍵:對話框關閉。這是我想要實現的。 --- newpara --- 我不想依賴於知道什麼是瀏覽器_might_做脆弱的代碼,我只是想讓它做什麼它需要。 – 2012-04-16 19:35:04

+0

我修改了一下代碼以取消打開對話框,因爲它是不必要的。讀/現在 – 2012-04-16 19:42:47