CKEditor中的拖放问题

Issues with drag and drop in CKEditor

本文关键字:问题 拖放 CKEditor      更新时间:2023-09-26

我正在编写一个小的笔记网络应用程序,它使用CKEditor作为HTML编辑器。我已经能够很好地集成它,但有一个例外 - 拖放功能。它大部分有效 - 但尽管尝试了很多不同的方法,但我仍然无法解决两个怪癖。

我的要求很简单 - 我将任何文件从应用程序外部拖到 CKEditor 中,它应该在可编辑文本中插入一个简单的锚标签,并带有指向该文件的本地链接。目前,我正在我自己的CKEditor插件中实现拖放,称为文件管理器:

CKEDITOR.plugins.add( 'filemanager', {
init: function( editor ) {
    editor.on('contentDom', function(contentDom) { 
        //Runs upon dropping a file into the editor
        contentDom.editor.document.on('drop', function(e) {
            //prevents default behavior as long as it's an actual file drag and drop (if it's dragging text etc. inside the editor, keep default behavior)
            if(e.data.$.dataTransfer.files.length)
            {
                e.data.preventDefault();
            }
            //Goes through all the dropped files and insert HTML with links
            for (var i = 0; i < e.data.$.dataTransfer.files.length; ++i) {
                CopyData(e.data.$.dataTransfer.files[i].path);
            }
        });
    });
    //Creates the link in the editor
    function CopyData(path, range)
    {
        //Link HTML
        var fileHTML;
        /* Code to parse the path into HTML to be inserted */
        editor.insertHtml(fileHTML);
    }
}

});

我省略了大部分 CopyData 函数,因为格式无关紧要,但它会生成如下div:

fileHTML = "<a href='""+path+"'" class='"fileLink'" target='"_blank'">"+fileName+"</a>";


这确实工作得很好,因此该功能的基本实现似乎可以正常工作。但是,这是我的两个问题:

  1. 将文件拖放到编辑器中但在实际文本区域之外(例如编辑器中最后一行文本下方)不会禁用默认行为。如何为编辑器的此区域运行 preventDefault()?一直在各种地方尝试活动但没有结果。
  2. HTML 不会插入到鼠标光标的位置,即使 CKEditor 在那里预览插入符号也是如此。相反,它会插入到文档中插入符号当前所在的位置,与放置的位置无关。这会破坏该功能的核心功能 - 有没有办法在鼠标位置插入 HTML?我会这样假设,因为 CKEditor 实际上预览了鼠标所在的插入符号,但我浏览了文档但没有结果。

有没有人对如何解决上述两个问题有想法?如果有帮助,我使用的是 nw.js因此网络应用程序将始终在 Chromium 中运行。感谢任何回复!

我最终设法解决了这些问题。

为了防止 DOM 元素之外的默认行为,我将这段代码添加到我的 CKEditor 插件中:

        var iframeWin = window.document.getElementsByTagName('iframe')[0].contentWindow;
        iframeWin.addEventListener("dragover",function(e){
            e = e || iframeWin.event;
            if(e.dataTransfer.files.length)
            {
                e.preventDefault();
            }
        },false);
        iframeWin.addEventListener("drop",function(e){
            e = e || iframeWin.event;
            if(e.dataTransfer.files.length)
            {
                e.preventDefault();
            }
        },false);

这正确地标识了我需要在其中禁用默认行为的 iframe。if(e.dataTransfer.files.lenght) 条件确保这仅适用于拖入应用程序的文件,而不是在编辑器中拖动内容。

在鼠标光标处插入 HTML 更棘手!这不能归功于我 - 我找到了一个在 CKEditor 错误跟踪器上完成大部分工作的函数,并对其进行了编辑以在这种情况下工作:

    function moveSelectionToDropPosition( editor, dropEvt )
    {
    var $evt = dropEvt.data.$,
        $range,
        range = editor.createRange();
    // Make testing possible.
    if ( dropEvt.data.testRange ) {
        dropEvt.data.testRange.select();
        return;
    }
    // Webkits.
    if ( document.caretRangeFromPoint ) {
        $range = editor.document.$.caretRangeFromPoint( $evt.clientX, $evt.clientY );
        range.setStart( CKEDITOR.dom.node( $range.startContainer ), $range.startOffset );
        range.collapse( true );
    }
    // FF.
    else if ( $evt.rangeParent ) {
        range.setStart( CKEDITOR.dom.node( $evt.rangeParent ), $evt.rangeOffset );
        range.collapse( true );
    }
    // IEs.
    else if ( document.body.createTextRange ) {
        $range = editor.document.getBody().$.createTextRange();
        $range.moveToPoint( $evt.clientX, $evt.clientY );
        var id = 'cke-temp-' + ( new Date() ).getTime();
        $range.pasteHTML( '<span id="' + id + '">'u200b</span>' );
        var span = editor.document.getById( id );
        range.moveToPosition( span, CKEDITOR.POSITION_BEFORE_START );
        span.remove();
    }
    range.select();
}

在下降事件中,我然后简单地添加了

moveSelectionToDropPosition(editor, e);

一切都按预期工作!

希望这可以帮助将来遇到类似问题的任何其他人:)