javascriptckeditor5ckeditor4.x

How to use CKEditor5 in a native javascript environment?


In our project, we have used CKEditor4 so far - now we want to move to CKE5.

In our index.php file, we included the requirements as is described in the documentation like this:

index.php:

<script type="importmap">
    {
        "imports": {
            "ckeditor5": "https://cdn.ckeditor.com/ckeditor5/43.2.0/ckeditor5.js",
            "ckeditor5/": "https://cdn.ckeditor.com/ckeditor5/43.2.0/"
        }
    }
</script>
<link rel="stylesheet" href="https://cdn.ckeditor.com/ckeditor5/43.2.0/ckeditor5.css">
<script type="module" src="./main.js"></script>

In the code-sample that was provided, they have a main.js file where they import all the required modules, it looks like this: main.js:

import {
ClassicEditor,
AccessibilityHelp,
Autoformat,
AutoImage,
Autosave,
BalloonToolbar,
Base64UploadAdapter,
BlockQuote,
Bold,
CloudServices,
Essentials,
FontBackgroundColor,
FontColor,
FontFamily,
FontSize,
Heading,
Highlight,
ImageBlock,
ImageCaption,
ImageInline,
ImageInsert,
ImageInsertViaUrl,
ImageResize,
ImageStyle,
ImageTextAlternative,
ImageToolbar,
ImageUpload,
Indent,
IndentBlock,
Italic,
Link,
LinkImage,
List,
ListProperties,
MediaEmbed,
Paragraph,
PasteFromOffice,
RemoveFormat,
SelectAll,
ShowBlocks,
SourceEditing,
SpecialCharacters,
SpecialCharactersArrows,
SpecialCharactersCurrency,
SpecialCharactersEssentials,
SpecialCharactersLatin,
SpecialCharactersMathematical,
SpecialCharactersText,
Table,
TableCaption,
TableCellProperties,
TableColumnResize,
TableProperties,
TableToolbar,
TextTransformation,

...(and so forth)

At the bottom of the file, they initialize the Editor with this line:

ClassicEditor.create(document.querySelector('#editor'), editorConfig);

This works, however:

Using this line, we cannot initialize the Editor in our other functions of our JS code like we used to, because all the modules arent loaded. How can we solve this?

We have tried to load the modules in our functions but we cannot use import.


Solution

  • If I understand the problem correctly, you want to use ckeditor5 in your legacy non-module js script.

    I have to say first that the recommended and only good practice approach is to refactor your legacy script into modules.

    If for some reason you don't want to do that, there is the ugly solution to share data between the module script and a non-module one through a global variable, see this SO post The simplest way to do that in the browser context is through the global window.

    Thus, the module script (main.js) may contain something like this:

    import {
        ClassicEditor,
        Essentials,
        Paragraph,
        Bold,
        Italic,
        Font
    } from 'ckeditor5';
    
    window._ckEditor = {
        ClassicEditor,
        Essentials,
        Paragraph,
        Bold,
        Italic,
        Font
    };
    

    and the legacy script would have to retrieve data from window._ckEditor, making sure that the data retrieval is run after the module was run, for instance by setting it through DomContentLoaded:

    // non-module custom code
    addEventListener("DOMContentLoaded", () => {
        const {
            ClassicEditor,
            Essentials,
            Paragraph,
            Bold,
            Italic,
            Font
        } = window._ckEditor;
        
        ClassicEditor
            .create(document.querySelector('#editor'), 
            ......
    

    Demo snippet:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Test CKEditor5</title>
        <link rel="stylesheet" href="https://cdn.ckeditor.com/ckeditor5/43.2.0/ckeditor5.css">
    </head>
    <script type="importmap">
        {
            "imports": {
                "ckeditor5": "https://cdn.ckeditor.com/ckeditor5/43.2.0/ckeditor5.js",
                "ckeditor5/": "https://cdn.ckeditor.com/ckeditor5/43.2.0/",
                "ClassicEditor": "./main.js"
            }
        }
    </script>
    
    
    <script type="module">
        import {
            ClassicEditor,
            Essentials,
            Paragraph,
            Bold,
            Italic,
            Font
        } from 'ckeditor5';
    
        window._ckEditor = {
            ClassicEditor,
            Essentials,
            Paragraph,
            Bold,
            Italic,
            Font
        };
    </script>
    
    <script>
        // your custom code here
        addEventListener("DOMContentLoaded", () => {
            const {
                ClassicEditor,
                Essentials,
                Paragraph,
                Bold,
                Italic,
                Font
            } = window._ckEditor;
    
            ClassicEditor
                .create(document.querySelector('#editor'), {
                    plugins: [Essentials, Paragraph, Bold, Italic, Font],
                    toolbar: [
                        'undo', 'redo', '|', 'bold', 'italic', '|',
                        'fontSize', 'fontFamily', 'fontColor', 'fontBackgroundColor'
                    ]
                })
                .then(editor => {
                    window.editor = editor;
                })
                .catch(error => {
                    console.error(error);
                });
        });
    </script>
    
    <body>
    <div id="editor"></div>
    </body>
    </html>

    or stackblitz with separate files; and a variant that avoids the repetitions of the imported values with the drawback that lint tools will likely complain and code assistance in the IDE will not typically recognise any of the imported values.