简体   繁体   English

CKEditor 使用 Angular 7 拖放

[英]CKEditor Drag and drop with Angular 7

I would like to use the CKEditor and drag and drop with Angular 7. They do it with success on their site but I Can't seem to find any Angular solutions for this.我想使用 CKEditor 并使用 Angular 7 拖放。他们在他们的网站上成功做到了,但我似乎找不到任何 Angular 解决方案。 As you see here:正如你在这里看到的:

https://ckeditor.com/docs/ckeditor4/latest/examples/draganddrop.html https://ckeditor.com/docs/ckeditor4/latest/examples/draganddrop.html

But I have trouble converting this to Angular 7 component.但是我无法将其转换为 Angular 7 组件。 My code is:我的代码是:

import { Component, OnInit } from '@angular/core';
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';

@Component({
  selector: 'xxxx',
  templateUrl: 'xxxxx',
  styleUrls: ['xxxxx']
})
export class NyttInnholdComponent implements OnInit {

  public editor = ClassicEditor;

  public contacts = [];

  public model = {
        editorData: '<p>Tommy says, Hello!</p>'
    };

  constructor() { 
    this.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'
      },
      {
        name: 'Phileas Fogg',
        tel: '+44 3345 234 235',
        email: 'p.fogg@example.com',
        avatar: 'pfog'
      },
      {
        name: 'Alice',
        tel: '+20 4345 234 235',
        email: 'alice@example.com',
        avatar: 'alice'
      },
      {
        name: 'Little Red Riding Hood',
        tel: '+45 2345 234 235',
        email: 'lrrh@example.com',
        avatar: 'lrrh'
      }
    ];


  }

  ngOnInit() {
    //this.teswt ();
    this.editor.disableAutoInline = true;


    this.editor.plugins.add('hcard', {
      requires: 'widget',

      init: function(editor) {
        editor.widgets.add('hcard', {
          allowedContent: 'span(!h-card); a[href](!u-email,!p-name); span(!p-tel)',
          requiredContent: 'span(h-card)',
          pathName: 'hcard',

          upcast: function(el) {
            return el.name == 'span' && el.hasClass('h-card');
          }
        });

        // This feature does not have a button, so it needs to be registered manually.
        editor.addFeature(editor.widgets.registered.hcard);

        // Handle dropping a contact by transforming the contact object into HTML.
        // Note: All pasted and dropped content is handled in one event - editor#paste.
        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>';
        });
      }
    });

    this.editor.on('instanceReady', function() {
      // When an item in the contact list is dragged, copy its data into the drag and drop data transfer.
      // This data is later read by the editor#paste listener in the hcard plugin defined above.
      this.editor.document.getById('contactList').on('dragstart', 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 the 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.
        this.editor.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 the HTML code to be inserted into the editor. You 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.
        // * You 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', this.contacts[target.data('contact')]);

        // You 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 the editor.
        // * The content may be dropped in another place than the editor.
        dataTransfer.setData('text/html', target.getText());

        // You can still access and use the native dataTransfer - e.g. to set the drag image.
        // Note: IEs do not support this method... :(.
        if (dataTransfer.$.setDragImage) {
          dataTransfer.$.setDragImage(target.findOne('img').$, 0, 0);
        }
      });
    });

    // Initialize the editor with the hcard plugin.
    this.editor.inline('editor1', {
      extraPlugins: 'hcard,sourcedialog,justify'
    });

  }

}

Used like this:像这样使用:

<ckeditor [(ngModel)]="model.editorData" [editor]="editor"></ckeditor>

If I try this the this.editor will not contain any of the properties I was expecting.如果我尝试这个 this.editor 将不包含任何我期望的属性。 Which you find here: https://ckeditor.com/docs/ckeditor5/latest/api/module_editor-classic_classiceditor-ClassicEditor.html您可以在这里找到: https : //ckeditor.com/docs/ckeditor5/latest/api/module_editor-classic_classiceditor-ClassicEditor.html

So, anyone know how I can get Angular to work with Angular 7 and CKEditor?那么,有人知道如何让 Angular 与 Angular 7 和 CKEditor 一起工作吗?

Yes you can use Angular 7 and CKEditor5 and a Custom Directive.是的,您可以使用 Angular 7 和 CKEditor5 以及自定义指令。 You can create a Drag Directive and "drag and drop" data onto the Editor Document.您可以创建拖动指令并将数据“拖放”到编辑器文档上。

See the below for an example of a Drag Directive: https://threeventures.com/build-html-drag-drop-angular/ https://github.com/ThreeVenturesTechnology/angular-drag-and-drop请参阅以下拖动指令示例: https : //threeventures.com/build-html-drag-drop-angular/ https://github.com/ThreeVenturesTechnology/angular-drag-and-drop

There are two options:有两种选择:

  1. Use a div instead of the Angular CKEditor control.使用 div 而不是 Angular CKEditor 控件。
  2. Binding your CKEditor to the built-in drop and dragover events.将您的 CKEditor 绑定到内置的放置和拖动事件。

Option 1 -Use a div instead of the Angular CKEditor control.选项 1 - 使用 div 而不是 Angular CKEditor 控件。

Your template would look something like this.您的模板看起来像这样。

<div cols="10" id="editor1" name="editor1" rows="10" data-sample-short contenteditable="true" >
</div>

Then your typescript would look somethign like然后你的打字稿看起来像

  ngOnInit(): void {

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

      init(editor): void {
        editor.widgets.add('hcard', {
          allowedContent: 'span(!h-card); a[href](!u-email,!p-name); span(!p-tel)',
          requiredContent: 'span(h-card)',
          pathName: 'hcard',

          upcast: (el) => {
            return el.name === 'span' && el.hasClass('h-card');
          }
        });

        // This feature does not have a button, so it needs to be registered manually.
        editor.addFeature(editor.widgets. registered.hcard);

        // Handle dropping a contact by transforming the contact object into HTML.
        // Note: All pasted and dropped content is handled in one event - editor#paste.
        editor.on('paste', (evt) => {
          const 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.replace( 'editor1', {
      extraPlugins: 'hcard, sourcedialog',
        toolbar: [
          { name: 'basicstyles', items: [ 'Bold', 'Italic' ] },
          { name: 'clipboard', items: [ 'Cut', 'Copy', 'Paste', 'PasteText', '-', 'Undo', 'Redo' ] },
          { name: 'document', items: ['Source'] }
        ],
        allowedContent: true,
        fullPage: true,
        height: '500px'
    });

    CKEDITOR.on('instanceReady', (event) => {
      // When an item in the contact list is dragged, copy its data into the drag and drop data transfer.
      // This data is later read by the editor#paste listener in the hcard plugin defined above.
      CKEDITOR.document.getById('contactList').on('dragstart', (evt) => {
        // The target may be some element inside the draggable div (e.g. the image), so get the div.h-card.
        const target = evt.data.getTarget().getAscendant('div', true);

        // Initialization of the CKEditor 4 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);

        const dataTransfer = evt.data.dataTransfer;

        // Pass an object with contact details. Based on it, the editor#paste listener in the hcard plugin
        // will create the HTML code to be inserted into the editor. You 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.
        // * You 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', this.CONTACTS[target.data('contact')]);

        // You 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 the editor.
        // * The content may be dropped in another place than the editor.
        dataTransfer.setData('text/html', target.getText());

        // You can still access and use the native dataTransfer - e.g. to set the drag image.
        // Note: IEs do not support this method... :(.
        if (dataTransfer.$.setDragImage) {
          dataTransfer.$.setDragImage(target.findOne('img').$, 0, 0);
        }
      });

    });
  }

Source code (Angular 10): https://github.com/steve-giles/ckeditorApp源代码(Angular 10): https : //github.com/steve-giles/ckeditorApp

Option 2 - Binding your CKEditor to the built-in drop and dragover events.选项 2 - 将您的 CKEditor 绑定到内置放置和拖动事件。

The problem with this approach is that you can only perform drag and drop in source view.这种方法的问题在于您只能在源视图中执行拖放操作。

Your template would look something like this.您的模板看起来像这样。

<ckeditor [(ngModel)]="model.editorData" [editor]="editor" (drop)="drop($event)"
          (dragover)="allowDrop($event)"></ckeditor>

Then in your typescript add the code for drop and drag where "text" is a reference to the element your dragging.然后在您的打字稿中添加拖放代码,其中“文本”是对您拖动的元素的引用。

  allowDrop(ev): void {
    ev.preventDefault();
  }

  drag(ev): void {
    ev.dataTransfer.setData('text', ev.target.id);
  }

Finally add code to update the CKEditor with your text.最后添加代码以使用您的文本更新 CKEditor。 In this example I'm using "getElementById" but a better approach would be to use Angular binding.在本例中,我使用“getElementById”,但更好的方法是使用 Angular 绑定。 Note that for this to work, the user needs to set focus in the editor to where the element will be dropped.请注意,要使其正常工作,用户需要在编辑器中将焦点设置到元素将被放置的位置。

  drop(ev): void {
    ev.preventDefault();
    var data = ev.dataTransfer.getData("text");
    var newValue = document.getElementById(data).textContent;

    var startPos = ev.target.selectionStart;
    var endPos = ev.target.selectionEnd;

    ev.target.value = ev.target.value.substring(0, startPos)
      + newValue 
      + ev.target.value.substring(endPos, ev.target.value.length);
  }

Source code (Angular 10): https://github.com/steve-giles/draganddrop源代码(Angular 10): https : //github.com/steve-giles/draganddrop

After a lot of work around and document search.经过大量工作和文档搜索。 The easiest way to drag and drop the external text/html that I have achieved using Ckeditor5 decoupled document editor and Angular 10. The example below and reference link Where are the editor.insertHtml() and editor.insertText() methods?我使用Ckeditor5解耦文档编辑器和Angular 10实现的最简单的拖放外部文本/html的方法。下面的示例和参考链接editor.insertHtml()和editor.insertText()方法在哪里? How to insert some content? 如何插入一些内容?

app.module应用模块

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { CKEditorModule } from '@ckeditor/ckeditor5-angular';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, CKEditorModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

app.component.ts app.component.ts

import { Component } from '@angular/core';
import * as DecoupledEditor from '@ckeditor/ckeditor5-build-decoupled-document';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  public Editor = DecoupledEditor;
  editorInstance;
  public data = {
    editorData: '<p>Hello, world!</p>',
  };

  fieldMap: Map<string, string> = new Map<string, string>([
    ['studentFirstName', '{{ student.firstName }}'],
    ['studentLastName', '{{ student.lastName }}'],
    ['courseName', '{{ course.name }}'],
    ['courseHours', '{{ course.hours }}'],
  ]);

  constructor() {}

  ngOnInit() {}

  public onReady(editor) {
    editor.ui
      .getEditableElement()
      .parentElement.insertBefore(
        editor.ui.view.toolbar.element,
        editor.ui.getEditableElement()
      );
    this.editorInstance = editor;
  }

  allowDrop(ev): void {
    ev.preventDefault();
  }

  drag(ev): void {
    console.log('drage', ev.target);
    ev.dataTransfer.setData('dragElement', ev.target.id);
  }

  drop(ev): void {
    ev.preventDefault();
    const data = ev.dataTransfer.getData('dragElement');
    const dataValue = this.fieldMap.get(data);
    const viewFragment = this.editorInstance.data.processor.toView(dataValue);
    const modelFragment = this.editorInstance.data.toModel(viewFragment);
    this.editorInstance.model.insertContent(modelFragment);
  }
}

app.component.html应用程序组件.html

<ckeditor [editor]="Editor"  [data]="data.editorData" (ready)="onReady($event)"
          (drop)="drop($event)"
          (dragover)="allowDrop($event)">
</ckeditor>

Student
<ul>
  <li id="studentFirstName" draggable="true" (dragstart)="drag($event)">First name</li>
  <li id="studentLastName" draggable="true" (dragstart)="drag($event)">Last name</li>
</ul>

Course
<ul>
  <li id="courseName" draggable="true" (dragstart)="drag($event)">Name</li>
  <li id="courseHours" draggable="true" (dragstart)="drag($event)">Hours</li>
</ul>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM