在CKEditor

时间:2015-05-20 16:41:34

标签: jquery ckeditor

上下文

我有一个非常简单的用例。我的页面有一些可配置的快捷键。我在文档节点处理keydown事件,如果keypress是可配置的快捷方式之一,那么我执行一系列操作并调用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问题,但这会改变"这个"的含义。这似乎搞砸了父处理程序中的preventDefault()函数。

问题

我需要原始事件对象,我可以在其上调用preventDefault()并传递给jQuery的trigger()函数,而无需操作任何内容。父文档应处理处理keydown事件并确定要采取的操作:复制CKEditor contentDom处理程序中的所有可配置快捷方式代码是不可行的。

示例

不幸的是,SO对iframe操作的限制比jsfiddle更严格,所以我创造了两者。您可以在下面的代码段中查看代码,但是您必须访问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>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:0)

我找到了答案。事实证明,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/