CKEditor Demo

Source Code of the Content Above

<p>CKEditor rocks!</p><p><strong>Insert base64–encoded image</strong></p><figure class="image"><img src="data:image/png;base64,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"><figcaption>CKEditor 5</figcaption></figure><p><strong>We now can add an image from Unsplash!</strong></p><figure class="image"><img src="https://images.unsplash.com/photo-1508144322886-717c284ab392?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjE1NDAxMH0"><figcaption>Photo by <a target="_blank" rel="noopener noreferrer" href="https://unsplash.com/@lucabravo?utm_source=DNX&amp;utm_medium=referral">Luca Bravo</a> on <a target="_blank" rel="noopener noreferrer" href="https://unsplash.com/?utm_source=DNX&amp;utm_medium=referral">Unsplash</a></figcaption></figure><pre><code class="language-php">&lt;?php
    $nextJS = "NextJS";
    $feathersJS = "FeathersJS";
    $perfect = $nextJS + $feathersJS;</code></pre>

Download NPM Package

ckeditor5-build-classic-dna

CKEditor Component

import React, { Component } from "react";
import PropTypes from "prop-types";
import CKEditor from "@ckeditor/ckeditor5-react";
import ClassicEditor from "ckeditor5-build-classic-dna";
import uploadFile from "lib/upload";

class MyUploadAdapter {
  constructor(loader) {
    // The file loader instance to use during the upload.
    this.loader = loader;
  }

  // Starts the upload process.
  upload() {
    return this.loader.file.then(async (file) => {
      let formData = new FormData();
      formData.append("file", file);
      let result = false;
      try {
        result = await uploadFile(this.loader.accessToken, formData);
      } catch (error) {
        console.log(error);
      }
      // default image - in case upload failed
      let url = "https://source.unsplash.com/random";

      if (result && result.url) {
        url = result.url;
      }

      if (result && result.thumbnail && this.loader.onUpload) {
        this.loader.onUpload(result.thumbnail);
      }

      return Promise.resolve({
        default: url,
      });
    });
  }

  // Aborts the upload process.
  abort() {
    if (this.xhr) {
      this.xhr.abort();
    }
  }
}

const DNXCustomUploadAdapterPlugin = (editor) => {
  editor.plugins.get("FileRepository").createUploadAdapter = (loader) => {
    // Configure the URL to the upload script in your back-end here!
    loader.onUpload = editor.onUpload;
    loader.accessToken = editor.accessToken;
    return new MyUploadAdapter(loader);
  };
};

class CKEditor5 extends Component {
  static get propTypes() {
    return {
      value: PropTypes.string,
      onChange: PropTypes.func,
      accessToken: PropTypes.string,
      onUpload: PropTypes.func,
    };
  }

  render() {
    return (
      <CKEditor
        editor={ClassicEditor}
        data={this.props.value}
        config={{
          extraPlugins: [DNXCustomUploadAdapterPlugin],
          table: {
            customClass: ["ui", "table", "celled"], // Important!!! need to be array
          },
          image: {
            customClass: ["ui", "fluid", "image"], // Use whatever class names defined in your theme
          },
          toolbar: [
            //customize your toolbar
            "heading",
            "|",
            "bold",
            "italic",
            "link",
            "bulletedList",
            "numberedList",
            "|",
            "indent",
            "outdent",
            "|",
            "imageUpload",
            "insertImage",
            "insertImageFromUnsplash",
            "code",
            "codeBlock",
            "blockQuote",
            "insertTable",
            "mediaEmbed",
            "undo",
            "redo",
          ],
          link: {
            decorators: {
              addTargetToExternalLinks: {
                mode: "automatic",
                callback: (url) => /^(https?:)?\/\//.test(url),
                attributes: {
                  target: "_blank",
                  rel: "noopener noreferrer",
                },
              },
            },
          },
        }}
        onInit={(editor) => {
          editor.onUpload = this.props.onUpload; //append event
          editor.accessToken = this.props.accessToken;
          // You can store the "editor" and use when it is needed.
          // console.log("Editor is ready to use!", editor);
        }}
        onChange={(event, editor) => {
          const data = editor.getData();
          this.props.onChange(data);
        }}
        onBlur={(event, editor) => {
          console.log("Blur.", editor);
        }}
        onFocus={(event, editor) => {
          console.log("Focus.", editor);
        }}
      />
    );
  }
}

export default CKEditor5;

How to Call in SSR

import React, { Component } from "react";
import PropTypes from "prop-types";
import CKEditor from "@ckeditor/ckeditor5-react";
import ClassicEditor from "ckeditor5-build-classic-dna";
import uploadFile from "lib/upload";

class MyUploadAdapter {
  constructor(loader) {
    // The file loader instance to use during the upload.
    this.loader = loader;
  }

  // Starts the upload process.
  upload() {
    return this.loader.file.then(async (file) => {
      let formData = new FormData();
      formData.append("file", file);
      let result = false;
      try {
        result = await uploadFile(this.loader.accessToken, formData);
      } catch (error) {
        console.log(error);
      }
      // default image - in case upload failed
      let url = "https://source.unsplash.com/random";

      if (result && result.url) {
        url = result.url;
      }

      if (result && result.thumbnail && this.loader.onUpload) {
        this.loader.onUpload(result.thumbnail);
      }

      return Promise.resolve({
        default: url,
      });
    });
  }

  // Aborts the upload process.
  abort() {
    if (this.xhr) {
      this.xhr.abort();
    }
  }
}

const DNXCustomUploadAdapterPlugin = (editor) => {
  editor.plugins.get("FileRepository").createUploadAdapter = (loader) => {
    // Configure the URL to the upload script in your back-end here!
    loader.onUpload = editor.onUpload;
    loader.accessToken = editor.accessToken;
    return new MyUploadAdapter(loader);
  };
};

class CKEditor5 extends Component {
  static get propTypes() {
    return {
      value: PropTypes.string,
      onChange: PropTypes.func,
      accessToken: PropTypes.string,
      onUpload: PropTypes.func,
    };
  }

  render() {
    return (
      <CKEditor
        editor={ClassicEditor}
        data={this.props.value}
        config={{
          extraPlugins: [DNXCustomUploadAdapterPlugin],
          table: {
            customClass: ["ui", "table", "celled"], // Important!!! need to be array
          },
          image: {
            customClass: ["ui", "fluid", "image"], // Use whatever class names defined in your theme
          },
          toolbar: [
            //customize your toolbar
            "heading",
            "|",
            "bold",
            "italic",
            "link",
            "bulletedList",
            "numberedList",
            "|",
            "indent",
            "outdent",
            "|",
            "imageUpload",
            "insertImage",
            "insertImageFromUnsplash",
            "code",
            "codeBlock",
            "blockQuote",
            "insertTable",
            "mediaEmbed",
            "undo",
            "redo",
          ],
          link: {
            decorators: {
              addTargetToExternalLinks: {
                mode: "automatic",
                callback: (url) => /^(https?:)?\/\//.test(url),
                attributes: {
                  target: "_blank",
                  rel: "noopener noreferrer",
                },
              },
            },
          },
        }}
        onInit={(editor) => {
          editor.onUpload = this.props.onUpload; //append event
          editor.accessToken = this.props.accessToken;
          // You can store the "editor" and use when it is needed.
          // console.log("Editor is ready to use!", editor);
        }}
        onChange={(event, editor) => {
          const data = editor.getData();
          this.props.onChange(data);
        }}
        onBlur={(event, editor) => {
          console.log("Blur.", editor);
        }}
        onFocus={(event, editor) => {
          console.log("Focus.", editor);
        }}
      />
    );
  }
}

export default CKEditor5;