【发布时间】:2015-05-20 16:41:34
【问题描述】:
背景
我有一个非常简单的用例。我的页面有一些可配置的快捷键。我在文档节点处理 keydown 事件,如果按键是可配置的快捷方式之一,那么我执行一系列操作并调用 event.preventDefault() 等,以防止发生标准操作(例如,覆盖 Ctrl/ Cmd+S)。
问题
CKEditor 创建一个 iframe,使文档级事件处理变得复杂。我在 SO 上找到了一篇非常有用的帖子,它解释了如何将自定义文档级事件处理程序注入到编辑器的 iframe 中:
How to use custom keyboard shortcuts within CKeditor with jQuery?
不幸的是,CKEditor 没有传递原始事件对象。在我的开发控制台中四处寻找之后,我发现了一个似乎暴露了原始事件对象(event.data.$)的属性,但实际上是事件对象的副本。例如,type 属性是继承的,这会混淆 jQuery 的 trigger() 函数(由于某种原因它调用了hasOwnProperty('type'))。
我可以通过复制事件对象来解决 jQuery 问题,但这会改变“this”的含义,这似乎会破坏父处理程序中的 preventDefault() 函数。
问题
我需要 original 事件对象,我可以调用 preventDefault() 并传递给 jQuery 的 trigger() 函数而无需操作任何东西。父文档应处理 keydown 事件并确定要采取的操作:在 CKEditor contentDom 处理程序中复制所有可配置的快捷方式代码是不可行的。
示例
不幸的是,SO 对 iframe 操作的限制比 jsfiddle 更严格,所以我创建了两者。您可以查看下面 sn-p 中的代码,但您必须访问 jsfiddle 才能真正看到它的工作原理:
http://jsfiddle.net/cyborgx37/swywgb7g/
var doc = $(document).on('keydown',function(e){
if (e.keyCode === 83){
e.preventDefault();
}
});
CKEDITOR.replace( 'foobar', {
on : {
contentDom : function() {
this.document.on( 'keydown',
function(e){
var originalEvent = e.data.$;
console.log({
type: originalEvent.type,
hasOwnResult: originalEvent.hasOwnProperty('type')
});
// type is "keydown" (type is defined!)
// but type is an inherited property so
// jQuery .trigger() ignores it and attempts
// to process the event as a string
doc.trigger( 'keydown', originalEvent );
// doesn't have desired effect, because the original
// event (with keyCode) has been replaced by a generic
// event object (without keyCode)
doc.trigger(e.data.$);
// causes error, because jQuery thinks that I've sent
// in a event name string rather than an event object
doc.trigger($.extend({},e.data.$));
// causes error, "this" is no longer the original event
// resulting in an "illegal invocation" exception
}
);
}
}
}
);
var doc = $(document).on('keydown',function(e){
if (e.keyCode === 83){
e.preventDefault();
}
});
CKEDITOR.replace( 'foobar', {
on : {
contentDom : function() {
this.document.on( 'keydown',
function(e){
var originalEvent = e.data.$;
console.log({
type: originalEvent.type,
hasOwnResult: originalEvent.hasOwnProperty('type')
});
// type is "keydown" (type is defined!)
// but type is an inherited property so
// jQuery .trigger() ignores it and attempts
// to process the event as a string
doc.trigger( 'keydown', originalEvent );
// doesn't have desired effect, because the original
// event (with keyCode) has been replaced by a generic
// event object (without keyCode)
doc.trigger(e.data.$);
// causes error, because jQuery thinks that I've sent
// in a event name string rather than an event object
doc.trigger($.extend({},e.data.$));
// causes error, "this" is no longer the original event
// resulting in an "illegal invocation" exception
}
);
}
}
}
);
#debug{
font-family: monospace;
color: red;
margin: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://cdn.ckeditor.com/4.4.7/standard/ckeditor.js"></script>
<h1>Typing "s" should be prevented, since we are calling "preventDefault()" if the keyCode is 83.</h1>
<h2>Works fine when typing in an input (you can't type an "s").</h2>
<input type="text">
<h2>Breaks for CKEditor, because we either can't pass along the original event, or jQuery breaks because, for some reason, jQuery cares whether or not type is an inherited property.</h2>
<textarea id="foobar"></textarea>
<h2>Error message (when attempting to use .trigger with the "original" (or as close as I can find in CKEditor) event object):</h2>
【问题讨论】: