2012-04-16 76 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