【问题标题】:Get original event object in CKEditor在 CKEditor 中获取原始事件对象
【发布时间】: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>

【问题讨论】:

标签: jquery ckeditor


【解决方案1】:

我找到了答案。事实证明 CKEditor 实现了它自己的(在我看来有点奇怪)事件系统。我使用的 editor.document 不是 jQuery 对象,而是 CKEditor 对象。

修复结果非常简单:

var doc = $(document).on('keydown',function(e){
    if (e.keyCode === 83){
        e.preventDefault();
    }
});

CKEDITOR.replace( 'foobar', {
        on : {
            contentDom : function() {

                // Get the low-level DOM element and
                // wrap it in a jQuery object, then call .on()
                $(this.document.$).on( 'keydown',
                    function(e){

                        // now I've got a jQuery event, which
                        // trigger() is much happier with
                        doc.trigger(e);
                    }
                );
            }
        }
    }
);

http://jsfiddle.net/cyborgx37/e2t56dht/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-10
    • 1970-01-01
    • 2018-02-18
    • 1970-01-01
    • 2010-12-05
    • 2014-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多