CKEditor Перетаскивание с помощью Angular 7

Я хотел бы использовать CKEditor и перетаскивать с помощью Angular 7. Они успешно справляются с этим на своем сайте, но я не могу найти для этого никаких решений Angular. Как вы видите здесь:

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

Но у меня проблемы с преобразованием этого в компонент Angular 7. Мой код:

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: '[email protected]',
        avatar: 'hfin'
      },
      {
        name: 'D\'Artagnan',
        tel: '+45 2345 234 235',
        email: '[email protected]',
        avatar: 'dartagnan'
      },
      {
        name: 'Phileas Fogg',
        tel: '+44 3345 234 235',
        email: '[email protected]',
        avatar: 'pfog'
      },
      {
        name: 'Alice',
        tel: '+20 4345 234 235',
        email: '[email protected]',
        avatar: 'alice'
      },
      {
        name: 'Little Red Riding Hood',
        tel: '+45 2345 234 235',
        email: '[email protected]',
        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'
    });

  }

}

Используется так:

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

Если я попробую это сделать, this.editor не будет содержать никаких свойств, которые я ожидал. Который вы найдете здесь: https://ckeditor.com/docs/ckeditor5/latest/api/module_editor-classic_classiceditor-ClassicEditor.html

Итак, кто-нибудь знает, как я могу заставить Angular работать с Angular 7 и CKEditor?

не уверен, действительно ли это возможно / практично делать с помощью cdk-drag-and-drop. По умолчанию вы помещаете элементы в cdkDropLists, но cdkDropLists не похожи на этот редактор. Я бы скопировал тот же подход, который они используют. Помните, что «javascript - допустимый машинописный текст».

Andre Elrico 16.01.2019 16:13

Обратите внимание, что вы используете CKEditor 5 и плагины и API для CKEditor 4. Это просто не сработает.

Maciej Bukowski 04.02.2019 10:56

Ну, я знаю ... сейчас. Но тогда не было;). Мне просто нужно было вызвать CKEditor 4 через CDN и внести небольшие изменения в контроллер, чтобы заставить его работать. Жаль, что у них нет подходящего решения Angular 2+ для перетаскивания. Теперь это «хак».

TommyF 04.02.2019 14:17
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
3
2 701
3

Ответы 3

Да, вы можете использовать Angular 7, CKEditor5 и настраиваемую директиву. Вы можете создать директиву перетаскивания и «перетащить» данные в документ редактора.

См. Ниже пример директивы перетаскивания: https://threeventures.com/build-html-drag-drop-angular/https://github.com/ThreeVenturesTechnology/angular-drag-and-drop

Есть два варианта:

  1. Используйте div вместо элемента управления Angular CKEditor.
  2. Привязка вашего CKEditor к встроенным событиям перетаскивания и перетаскивания.

Вариант 1 - используйте div вместо элемента управления Angular CKEditor.

Ваш шаблон будет выглядеть примерно так.

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

Тогда ваш машинописный текст будет выглядеть примерно как

  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);
        }
      });

    });
  }

Исходный код (Angular 10): https://github.com/steve-giles/ckeditorApp

Вариант 2 - привязка вашего CKEditor к встроенным событиям перетаскивания и перетаскивания.

Проблема с этим подходом заключается в том, что вы можете выполнять перетаскивание только в исходном виде.

Ваш шаблон будет выглядеть примерно так.

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

Затем в свой машинописный текст добавьте код для перетаскивания и перетаскивания, где «текст» - это ссылка на элемент, который вы перетаскиваете.

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

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

Наконец, добавьте код для обновления CKEditor вашим текстом. В этом примере я использую getElementById, но лучше использовать привязку Angular. Обратите внимание, что для того, чтобы это сработало, пользователю необходимо установить фокус в редакторе на то место, где элемент будет помещен.

  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);
  }

Исходный код (Angular 10): https://github.com/steve-giles/draganddrop

После долгой работы и поиска документов. Самый простой способ перетащить внешний текст / html, которого я добился, используя независимый редактор документов Ckeditor5 и Angular 10. Пример ниже и ссылка на ссылку Где находятся методы editor.insertHtml () и editor.insertText ()? Как вставить какой-нибудь контент?

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

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.info('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

<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>

Другие вопросы по теме