0

CKEditor自动加载内联编辑器引发的故障记录

 2 years ago
source link: https://www.daozhao.com/10342.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

CKEditor自动加载内联编辑器引发的故障记录

如果您发现本文排版有问题,可以先点击下面的链接切换至老版进行查看!!!

CKEditor自动加载内联编辑器引发的故障记录

在一次项目优化过程中,我采取了按需加载的策略,将对CKEditor入口JS文件的加载过程移动到了点击回复邮件之后,这样的话,当用户没有编辑邮件的需求时就不用加载CKEditor相关的JS文件了。但是因为这一个改动,引起了意想不到的问题。

因为我们的项目中IM聊天页面也用到了简易的富文本编辑,使用的也是contenteditable的div来实现的,问题也是因此而出现的。我们先简单介绍下CKEditor的两种模式

CKEditor使用模式

classic模式

邮件里面使用的就是这种模式。 官方的解释是:

经典编辑器是大多数用户传统上学会的与富文本编辑器相关联的东西——一个带有编辑区域的工具栏,放置在页面的特定位置,通常作为表单的一部分,用于向服务器提交一些内容。 有时它也被称为“框架编辑”,因为在这种情况下,编辑器会为自己创建一个临时的 <iframe> 元素。

这个模式是把编辑器的工具栏放到项目中,然后创建一个iframe,在该iframe中新建一个contenteditable的div作为编辑区域。

inline模式

官方的解释是:

内联编辑允许您就地编辑页面上的任何元素。 内联编辑器提供了“开箱即用”的真正所见即所得体验,因为与经典编辑器不同,编辑区域周围没有 </iframe><iframe> 元素。 用于编辑器内容的 CSS 样式与呈现此内容的目标页面上的完全相同!

这个模式是把编辑器的工具栏放到项目中,编辑器的编辑区域还是在项目主体中,或者这样说更好一点,就是编辑区域还是在项目主体中,但是给它附加了一个CKEditor的工具栏,让这个编辑区域的编辑功能更加强大了。

邮件项目不适合使用inline模式,所以在阅读CKEditor相关源码的时候,我是不关注inline模式相关的代码的,都是直接跳过。

前几天突然有人报障了,给的截图如下

file

这是用户在使用IM的时候发现的 ,截图中不是CKEditor编辑器吗,但是这又不是邮件里面使用的那种啊。怎么回事?

鉴于CKEditor编辑器会在项目的window下面挂载变量CKEDITOR,通过在console下面查看CKEDITOR.instances发现里面还有一个实例xxx。通过CKEDITOR.instances是可以看出一些端倪的。 以官网的demo为例

file

我们可以看到smapleTitle的是某个contenteditable的div的id,并以此作为对应的实例名,而editor1~editor6是一些没有id的contenteditable的div,CKEditor自行递增创建的实例名。

然后就找到了IM的输入框,它是有id的,果然和CKEDITOR.instances下的匹配上了,也就确定上图中显示的工具栏是CKEditor作用在IM的输入框的结果了。

在我们没有明确配置的情况下,CKEditor为什么会自作聪明的作用在我们IM的输入框上呢?

在源码中找到答案

// src/core/creators/inline.js

CKEDITOR.inlineAll = function() {
        var el,
            data;

        for ( var name in CKEDITOR.dtd.$editable ) {
            var elements = CKEDITOR.document.getElementsByTag( name );

            for ( var i = 0, len = elements.count(); i < len; i++ ) {
                el = elements.getItem( i );

                // Check whether an element is editable and if an editor attached is not to it already (#4293).
                if ( el.getAttribute( 'contenteditable' ) == 'true' && !el.getEditor() ) {
                    // Fire the "inline" event, making it possible to customize
                    // the instance settings and eventually cancel the creation.

                    data = {
                        element: el,
                        config: {}
                    };

                    if ( CKEDITOR.fire( 'inline', data ) !== false ) {
                        CKEDITOR.inline( el, data.config );
                    }
                }
            }
        }
};

CKEDITOR.domReady( function() {
        !CKEDITOR.disableAutoInline && CKEDITOR.inlineAll();
} );

默认情况下CKEDITOR.disableAutoInline就是undefined,当然就触发了CKEDITOR.inlineAll()

问题算是找到了。 在CKEditor的入口JS加载完成后,会对页面上的contenteditable为true的div(更准确的是符合源码中CKEDITOR.dtd.$editable的元素)进行生效。在用户先是进行了IM聊天也后,页面加载了IM的输入框,再去回复邮件,如果此时是首次加载CKEditor的入口JS的话,bug就产生了。

作为编辑器提供方,为了方便用户能在最少配置的情况下看到编辑器的效果(出现编辑器工具栏)默认加载inline编辑器这种做法也无可厚非,自己不注意的话,就中招了。。。

阅读源码的时候,可以有所侧重,但是相关部分还是不能过于轻率的跳过,尤其是自身业务中也有可能被应用的部分。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK