AlanObject
AlanObject

Reputation: 9943

CKEditor 5 copy selected content from one editor to another

I have two editors on the screen, one read-only. What I want to do is allow the user to select content from the read-only editor and paste it into the current position of the other by clicking a button. (the logic may manipulate the text which is one reason I don't want to use the system's clipboard.)

So far I have the function that is able to paste the text like as follows. (I am using the Angular wrapper which explains the presence of the CKEditorComponent reference.

  doPaste(pasteEvent: PasteEvent, editorComponent: CKEditorComponent) {
    const editor = editorComponent.editorInstance;
    editor.model.change(writer => {
      writer.insertText(pasteEvent.text, editor.model.document.selection.getFirstPosition() );
    });
}

What I can't find from the documentation is how to extract the selected text. What I have so far is:

  clickPasteSelectedPlain(editorComponent: CKEditorComponent) {
    const editor = editorComponent.editorInstance;
    const selection = editor.model.document.selection;
    console.log('clickPasteAll selection', selection);
    console.log('clickPasteAll selectedcontent', editor.model.document.getSelectedContent);
  }

The selection appears to change depending on what is selected in the editor's view. The getSelectedContent function is undefined. How do I get the content?

Upvotes: 4

Views: 1333

Answers (1)

AlanObject
AlanObject

Reputation: 9943

With a bit of poking around I figured out how to do this. I'll document it here on the chance that it will help someone down the road avoid the process of discovery that I went through.

On the source document I have a ckeditor element like this:

  <div *ngIf="document">
    <ckeditor #ckEditor
              [editor]="Editor" [config]="ckconfig" [disabled]="true"
              [(ngModel)]="document.text"></ckeditor>
    <button mat-flat-button (click)="clickPasteSelectedPlain(ckEditor)">Paste Selected Text Plain</button>
  </div>

In the component the function called on the click event is like this:

  @Output() paste = new EventEmitter<PasteEvent>();
     ...
  clickPasteSelectedPlain(editorComponent: CKEditorComponent) {
    const editor = editorComponent.editorInstance;
    this.paste.emit({
      content: editor.model.getSelectedContent(editor.model.document.selection),
      obj: this.document,
      quote: false
    });
  }

The PasteEvent is defined as an exported interface which I will omit here to save space. The content key will refer to a DocumentFragment.

Note that I am passing the CKEditorComponent as a parameter. You could also access it via an Angular @ViewChild declaration but note that my ckeditor is inside an *ngIf structure. I think that works well in Angular 6 but in the past I have had difficulty with @ViewChild references when the target was conditionally in the DOM. This method always works but use whatever method you want.

The event fired by the emit is processed with a method that looks like this:

  doPaste(pasteEvent: PasteEvent, editorComponent: CKEditorComponent) {
    const editor = editorComponent.editorInstance;
    editor.model.insertContent(pasteEvent.content);
  }

Because the content is a DocumentFragment the paste operation will include all formatting and text attributes contained in the selected source. But that's all there is to it.

Upvotes: 4

Related Questions