ckeditor拖放小部件

时间:2016-03-30 15:15:35

标签: drag-and-drop widget ckeditor

我有最新的ckeditor版本4.5.7和拖放API,我有一个案例,我需要将一个小部件从一个编辑器拖放到另一个编辑器。 正如这张票说的那样建议的功能是无声地失败并且什么都不做。

link to ckeditor ticket

在我的情况下,我需要复制小部件,如果它被拖动到另一个编辑器并移动,如果它在同一编辑器中拖动。第二种情况已经在工作

有关如何做的任何想法?

editor.on( 'contentDom', function() {
    var dropTarget = CKEDITOR.plugins.clipboard.getDropTarget( editor );
    editor.editable().attachListener( dropTarget, 'drop', function( evt ) {
    // The target may be some element inside the draggable div (e.g. the image), so get the div.h-card.
    var target = evt.data.getTarget().getAscendant( 'div', true );

    // Initialization of CKEditor data transfer facade is a necessary step to extend and unify native 
    // browser capabilities. For instance, Internet Explorer does not support any other data type than 'text' and 'URL'.
    // Note: evt is an instance of CKEDITOR.dom.event, not a native event.
    CKEDITOR.plugins.clipboard.initDragDataTransfer( evt );

    var dataTransfer = evt.data.dataTransfer;

    // Pass an object with contact details. Based on it, the editor#paste listener in the hcard plugin
    // will create HTML to be inserted into the editor. We could set text/html here as well, but:
    // * It is a more elegant and logical solution that this logic is kept in the hcard plugin.
    // * We do not know now where the content will be dropped and the HTML to be inserted
    // might vary depending on the drop target.
    dataTransfer.setData( 'contact', CONTACTS[ target.data( 'contact' ) ] );

    // We need to set some normal data types to backup values for two reasons:
    // * In some browsers this is necessary to enable drag and drop into text in editor.
    // * The content may be dropped in another place than the editor.
    dataTransfer.setData( 'text/html', target.getText() );
    } );
} );

link to codepen example

此外,如果ckeditor是readOly通过readOnly选项,我可以选择一些内容并将其拖到另一个编辑器,从而将其从源编辑器中删除

2 个答案:

答案 0 :(得分:3)

我在这里发现了3个问题:

  1. 从元素中获取联系信息并不简单,
  2. 正如您提到的CKEditor块小部件在编辑器之间拖放,
  3. 当您拖放时,CKEditor会从源区域删除drop元素。
  4. 我设法解决了前两个问题。

    广告。 1.

    要在交叉编辑器中插入联系人,请按照从联系人列表中插入联系人的方式进行拖放,您需要在数据传输对象contact上设置dataTransfer.getData( 'contact' );数据。遗憾的是,您拖动的小部件不会将联系人存储为对象。最简单的方法是将字符串化的联系人存储为附加属性:

    <span class="h-card" data-contact=\'' + JSON.stringify( contact ) + '\'>...</span>
    

    广告。 2。

    实际上CKEditor块小部件在编辑器之间拖放。为了解决这个问题,您可以创建一个drop侦听器,它将在默认侦听器(优先级2)之前调用,并将子站点类型从窗口小部件更改为联系人,因此它的处理方式与从中拖动的联系人相同。编辑下面的列表。

    // Create a drop listener which change the object from the widget to the contact.
    editor.on( 'drop', function( evt ) {
      var dataTransfer = evt.data.dataTransfer,
          sourceEditor = dataTransfer.sourceEditor;
          id = dataTransfer.getData( 'cke/widget-id' );
    
      // If it was a widget from another editor...
      if( sourceEditor && typeof id == "number" ) {
        // ...get contact info from the data attribute...
        var contact = sourceEditor.widgets.instances[ id ].element.data( 'contact' );
        contact = JSON.parse( contact );
    
        // ...set the contact info...
        dataTransfer.setData( 'contact', contact );
    
        // ...and remove the information that it was a widget.
        dataTransfer.setData( 'cke/widget-id', null );            
      }
    }, null, null, 2 );
    

    广告。 3。

    我无法阻止CKEditor表单删除拖动的元素而不会阻止掉落。删除由以下代码完成:https://github.com/ckeditor/ckeditor-dev/blob/06362a8715809f23d439986a122b87a37eef2e13/plugins/clipboard/plugin.js#L1409并且不准备被阻止。我的另一个想法是防止这种拖放和火灾单独的下降事件,但不幸的是,我没有下降位置。您可以更改剪贴板插件以防止删除源元素并添加如下内容:

    if( dataTransfer.getData( 'doNotRemoveSource' )
      dataTransfer.sourceEditor.editable().extractHtmlFromRange( dragRange );
    

    但是我不保证它会正常工作,它可能需要在小部件系统中进行一些更改,这些更改也会监听掉落事件。

    整个解决方案都是一个黑客,完美的解决方案需要在剪贴板插件中进行更深层次的更改。

    您可以在此处找到我的解决方案:http://codepen.io/pjasiun/pen/aNLWWM

答案 1 :(得分:0)

我已经成功地按照你说的优先事项

来说

首先在新的widget插件中我使用了dragstart事件

chmod 644

然后我使用优先级为2的drop事件(1是在此之前调用的默认事件)。

我使用验证来检查小部件是否在编辑器中拖动。如果是,那么我不想创建新的小部件,但移动现有小部件,以便我们取消此活动

editor.on("dragstart", function (evt) {
     evt.stop();
     var target = evt.data.target;

     if (isDomDragHandler(target)) {
         var widget = evt.editor.widgets.getByElement(target);
         CKEDITOR.plugins.clipboard.initDragDataTransfer(evt, evt.editor);
         evt.data.dataTransfer.setData('cke/widget-id', widget.id);
         evt.data.dataTransfer.setData('cke/editor-name', evt.editor.name);
         evt.data.dataTransfer.setData('text/html', widget.element.getOuterHtml());

         // IE needs focus.
         editor.focus();

         // and widget need to be focused on drag start (#12172#comment:10).
         widget.focus();
     }
}, null, null, 1);

最后,我们必须使用另一个侦听器,再次使用drop效果来判断事件是来自同一编辑器还是来自其他编辑器,以设置数据。

editor.on('drop', function (evt) {
    // do nothing if widget is dragged in source segment
    if (evt.editor.name.indexOf("sourceSegment") != -1) {
       evt.cancel();
       return;
    }

    //get hold of global data transfer object
    var dataTransfer = evt.data.dataTransfer;
    var sourceEditorName = dataTransfer.getData('cke/editor-name');

    if (sourceEditorName == evt.editor.name) return;
}, null, null, 2);      // 2rd called

最后的改变是评论小部件插件中取消事件

https://github.com/ckeditor/ckeditor-dev/blob/master/plugins/widget/plugin.js#L2381

editor.on('drop', function (evt) {

    var dataTransfer = evt.data.dataTransfer,
        id = dataTransfer.getData('cke/widget-id'),
        transferType = dataTransfer.getTransferType(editor);

        // Disable cross-editor drag & drop for widgets - #13599.
    if (id !== '' && transferType === CKEDITOR.DATA_TRANSFER_CROSS_EDITORS) {
       //do nothing
    }

    if (id === '' || transferType == CKEDITOR.DATA_TRANSFER_INTERNAL) {
       return;
    }

    evt.data.dataTransfer.setData('text/html', evt.data.dataTransfer.getData('text/html'));
}, null, null, 9999);      // 3rd called

通过这种方式,您可以在编辑器之间拖动小部件,从源代码复制到目标编辑器,并在同一个编辑器中移动小部件。

声明: 我提出的这个解决方案是我发现的最好的,没有过多地操纵ckeditor本身的核心功能(仅1行)。但是,如果有人有更好的解决方案,请发表评论!