CKEDITOR 拖放插件集成在编辑器实例被销毁并重新创建后停止工作

CKEDITOR Drag and drop plugin integration stops working after editor instance is destroyed and recreated

我在尝试使用 CKEditor 的拖放集成时遇到了很多麻烦。

首先,拖放到编辑器中可以正常使用 dataTransfer 等。但是每当我必须销毁并重新创建编辑器的一个实例时,拖放内容就会按预期停止工作。

我已经直接从CKEditor's SDK page about DnD integration修改了示例代码,您可以在其中看到正在重现的问题。 (我只是缩小了示例以使其更简洁,并在列表底部添加了 "Destroy and recreate" 按钮。)

无法让它在 JSFiddle 中运行,对此深表歉意,但这是代码:

        'use strict';

        var CONTACTS = [{
          name: 'Huckleberry Finn',
          tel: '+48 1345 234 235',
          email: 'h.finn@example.com',
          avatar: 'hfin'
        }, {
          name: 'D\'Artagnan',
          tel: '+45 2345 234 235',
          email: 'dartagnan@example.com',
          avatar: 'dartagnan'
        }];

        CKEDITOR.disableAutoInline = true;

        CKEDITOR.plugins.add('drag_list', {
          requires: 'widget',

          init: function(editor) {
            editor.widgets.add('drag_list', {
              allowedContent: true,
              pathName: 'drag_list',

              upcast: function(el) {
                return el.name == 'table' && el.hasClass('product_widget');
              }
            });

            editor.addFeature(editor.widgets.registered.drag_list);

            editor.on('paste', function(evt) {
              var contact = evt.data.dataTransfer.getData('contact');
              if (!contact) {
                return;
              }

              evt.data.dataValue =
                '<span class="h-card">' +
                '<a href="mailto:' + contact.email + '" class="p-name u-email">' + contact.name + '</a>' +
                ' ' +
                '<span class="p-tel">' + contact.tel + '</span>' +
                '</span>';
            });
          }
        });

        CKEDITOR.document.getById('contactList').on('dragstart', function(evt) {
          var target = evt.data.getTarget().getAscendant('div', true);

          CKEDITOR.plugins.clipboard.initDragDataTransfer(evt);

          var dataTransfer = evt.data.dataTransfer;

          dataTransfer.setData('contact', CONTACTS[target.data('contact')]);

          dataTransfer.setData('text/html', target.getText());

          if (dataTransfer.$.setDragImage) {
            dataTransfer.$.setDragImage(target.findOne('img').$, 0, 0);
          }
        });

        CKEDITOR.inline('editor1', {
          extraPlugins: 'drag_list,sourcedialog,justify'
        });

        function destroy_recreate() {
          for (var instance in CKEDITOR.instances) {
            console.log(CKEDITOR.instances[instance])
            CKEDITOR.instances[instance].destroy();
          }
          CKEDITOR.inline('editor1', {
            extraPlugins: 'drag_list,sourcedialog,justify'
          });
        }
.columns {
  background: #fff;
  padding: 20px;
  border: 1px solid #E7E7E7;
}
.columns:after {
  content: "";
  clear: both;
  display: block;
}
.columns > .editor {
  float: left;
  width: 65%;
  position: relative;
  z-index: 1;
}
.columns > .contacts {
  float: right;
  width: 35%;
  box-sizing: border-box;
  padding: 0 0 0 20px;
}
#contactList {
  list-style-type: none;
  margin: 0 !important;
  padding: 0;
}
#contactList li {
  background: #FAFAFA;
  margin-bottom: 1px;
  height: 56px;
  line-height: 56px;
  cursor: pointer;
}
#contactList li:nth-child(2n) {
  background: #F3F3F3;
}
#contactList li:hover {
  background: #FFFDE3;
  border-left: 5px solid #DCDAC1;
  margin-left: -5px;
}
.contact {
  padding: 0 10px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.contact .u-photo {
  display: inline-block;
  vertical-align: middle;
  margin-right: 10px;
}
#editor1 .h-card {
  background: #FFFDE3;
  padding: 3px 6px;
  border-bottom: 1px dashed #ccc;
}
#editor1 {
  border: 1px solid #E7E7E7;
  padding: 0 20px;
  background: #fff;
  position: relative;
}
#editor1 .h-card .p-tel {
  font-style: italic;
}
#editor1 .h-card .p-tel::before,
#editor1 .h-card .p-tel::after {
  font-style: normal;
}
#editor1 .h-card .p-tel::before {
  content: "(☎ ";
}
#editor1 .h-card .p-tel::after {
  content: ")";
}
#editor1 h1 {
  text-align: center;
}
#editor1 hr {
  border-style: dotted;
  border-color: #DCDCDC;
  border-width: 1px 0 0;
}
<script src="http://cdn.ckeditor.com/4.5.5/standard-all/ckeditor.js"></script>
<div class="columns">
  <div class="editor">
    <div cols="10" id="editor1" name="editor1" rows="10" contenteditable="true">
      <h3>Drop stuff here then press the Destroy/Recreate button and try again.</h3>

    </div>
  </div>
  <div class="contacts">
    <h3>List of Droppable Contacts</h3>
    <ul id="contactList">
      <li>
        <div class="contact h-card" data-contact="0" draggable="true" tabindex="0">
          <img src="http://sdk.ckeditor.com/samples/assets/draganddrop/img/hfin.png" alt="avatar" class="u-photo">Huckleberry Finn
        </div>
      </li>
      <li>
        <div class="contact h-card" data-contact="1" draggable="true" tabindex="0">
          <img src="http://sdk.ckeditor.com/samples/assets/draganddrop/img/dartagnan.png" alt="avatar" class="u-photo">D'Artagnan
        </div>
      </li>
    </ul>
    <button class='destroy_recreate' onclick='destroy_recreate()'>Destroy and recreate editors</button>
  </div>
</div>

其他插件如 sourcedialog 和 justify 似乎一直运行良好,但 drag_list 则不然。

有人知道为什么会这样吗?我需要做什么才能在新创建的 CKEditor 实例中拖放示例的 hcards 等内容?

提前致谢。

这看起来像是编辑器核心中的一个严重错误。我查了一下,报了个票:https://dev.ckeditor.com/ticket/14339 在票修好之前,我只能建议在编辑器上重新附加dragstart事件。您可以将: CKEDITOR.document.getById('contactList').on('dragstart', ... ); 放在插件 init 方法中。经过这样的改变拖放应该工作,但 dragstart 将被触发多次。您可以分离 dragstart 事件,然后再附加它,结束一切正常。