About the Download

Editor.js

Whenever, We are using any 3rd party text editors, there are some functionalities we like and we wish that it would be real fun and beneficial if we can customize the part of it or can create something new on our own. We are developing a coding platform in which we needed to allow user to insert the code and also allow them to select the programming language ,  to which in editor.js we can only add the code snippet and not select the programming language. So, I created my own code insertion plugin and you can also create your own by following the given steps:

Key features

  • It is a block-styled editor
  • It returns clean data output in JSON
  • Designed to be extendable and pluggable with a simple API

We will build a Simple Code Insert Plugin, Which also allows to select a language that to our articles.

Preparation a playground

At first we need to create some files when we will develop and test our new Tool. Create a folder with these three files:

/code-insert
/code-insert.js
/code-insert.css
/example.html

In example.html we will test our plugin, so lets add some markup and connect Editor.js there:

<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>
<script src="code-insert.js"></script>
<link href="code-insert.css" rel="stylesheet"/>

<div id="editorjs"></div>

<script>
    const editor = new EditorJS({
      autofocus: true
    });
</script>

 

If you open this page in browser, you’ll see an empty Editor with only internal Paragraph Toolavailable. Now we a ready to start creating own plugin.

Ok, let’s get started with creation a JavaScript class for our Tool in code-insert.js file.

class CodeInsert {

}

 

We need at least of two methods to create a Block Tool for Editor.js — render and save.

First method, render, will create an UI of a Block that will be appended when our Tool will be selected from the Toolbox. Second method, save — will extract the Block’s data from that UI.

Our UI will be a quite simple: just an input in which users will paste image URL. So let’s implement a render method:

 

render() {
const wrapper = document.createElement('div');
        const pre = document.createElement('pre');
        const textarea = document.createElement('textarea');

        textarea.textContent = this.data.code;
        textarea.contentEditable = 'true';


        wrapper.classList.add(this.CSS.baseClass, this.CSS.wrapper);

        textarea.style.minHeight = '200px';
        textarea.style.fontFamily = 'Menlo, Monaco, Consolas, Courier New, monospace';
        // textarea.style.color = '#41314e';
        textarea.style.lineHeight = '1.6em';
        textarea.style.fontSize = '12px';
        // textarea.style.background = '#272822';
        // textarea.style.border = '1px solid #f1f1f4';
        textarea.style.boxShadow = 'none';
        textarea.style.whiteSpace = 'pre';
        textarea.style.wordWrap = 'normal';
        textarea.style.overflow = 'auto';
        textarea.style.resize = 'vertical';


        if (this.config && this.config.readOnly) {
            const selectedLanguage = document.createElement('span');
            selectedLanguage.innerText = this.data && this.data.language ? this.data.language : '';
            wrapper.appendChild(selectedLanguage);
        } else {
            const language = document.createElement('select');

            language.dataset.placeholder = CodeWithLanguageSelection.DEFAULT_LANGUAGE_PLACEHOLDER;

            language.options.add(new Option('Select a Language', '', true));

            for (const index of CodeWithLanguageSelection.DEFAULT_FORMAT_CONFIG) {
                if (index) {
                    language.options[language.options.length] = new Option(index, index);
                }
            }

            language.value = this.data.language;

            language.classList.add(this.CSS.language);

            wrapper.appendChild(language);

            this.nodes.select = language;

            // this.api.listeners.on(language, 'change', (event) => {
                // console.log(event);
                // pre.className = `language-${event.target.value}`;
                // textarea.className = `language-${event.target.value}`;
                // Prism.highlightAll();
                // selectedLanguage.innerText = event.target.value;
            // });
        }

        wrapper.appendChild(pre).appendChild(textarea);
        // wrapper.appendChild(textarea);

        this.nodes.textarea = textarea;

        // this.api.listeners.on(textarea, 'blur', () => {
        //     Prism.highlightAll();
        // });

        this.api.listeners.on(textarea, 'paste', (event) => {
            // Prism.highlightAll();
            // this.data.code = event;
            // if (event && event.type === 'paste') {
            //     console.log(event.clipboardData.getData('text/plain'));
            //     textarea.textContent = event.clipboardData.getData('text/plain')
            // }
            // console.log(event)
        });


        return wrapper;
}

 

 

Then we need to provide a save method for extracting a Block data from the UI:

/**
 * Extract Tool's data from the view
 * @param {HTMLDivElement} codeWrapper - CodeTool's wrapper, containing textarea with code
 * @returns {CodeData} - saved plugin code
 * @public
 */
save(codeWrapper) {
    return {
        code: codeWrapper.querySelector('pre textarea').value,
        language: codeWrapper.querySelector('select') && codeWrapper.querySelector('select').value ?
             codeWrapper.querySelector('select').value : ''
    };
}

 

On saving, Editor.js will pass Block’s content to the save method and we should implement a logic of which data we should save by our Tool. Block content is the Element returned by render with actual state of that.

So in our case, we just need to get input’s value and return our Tool’s data object:

data: {
code: "const a;"
language: "R"
},
type: "code"

 

Showing at the Toolbox

Our Block Plugin is almost done. To make that appear at the Toolbox, we should provide an icon and a title with a static getter toolbox.

/**
 * Get Tool toolbox settings
 * icon - Tool icon's SVG
 * title - title to show in toolbox
 *
 * @return {{icon: string, title: string}}
 */
static get toolbox() {
    return {
        icon: `<svg width="14" height="14" viewBox="0 -1 14 14" xmlns="http://www.w3.org/2000/svg" > <path d="M3.177 6.852c.205.253.347.572.427.954.078.372.117.844.117 1.417 0 .418.01.725.03.92.02.18.057.314.107.396.046.075.093.117.14.134.075.027.218.056.42.083a.855.855 0 0 1 .56.297c.145.167.215.38.215.636 0 .612-.432.934-1.216.934-.457 0-.87-.087-1.233-.262a1.995 1.995 0 0 1-.853-.751 2.09 2.09 0 0 1-.305-1.097c-.014-.648-.029-1.168-.043-1.56-.013-.383-.034-.631-.06-.733-.064-.263-.158-.455-.276-.578a2.163 2.163 0 0 0-.505-.376c-.238-.134-.41-.256-.519-.371C.058 6.76 0 6.567 0 6.315c0-.37.166-.657.493-.846.329-.186.56-.342.693-.466a.942.942 0 0 0 .26-.447c.056-.2.088-.42.097-.658.01-.25.024-.85.043-1.802.015-.629.239-1.14.672-1.522C2.691.19 3.268 0 3.977 0c.783 0 1.216.317 1.216.921 0 .264-.069.48-.211.643a.858.858 0 0 1-.563.29c-.249.03-.417.076-.498.126-.062.04-.112.134-.139.291-.031.187-.052.562-.061 1.119a8.828 8.828 0 0 1-.112 1.378 2.24 2.24 0 0 1-.404.963c-.159.212-.373.406-.64.583.25.163.454.342.612.538zm7.34 0c.157-.196.362-.375.612-.538a2.544 2.544 0 0 1-.641-.583 2.24 2.24 0 0 1-.404-.963 8.828 8.828 0 0 1-.112-1.378c-.009-.557-.03-.932-.061-1.119-.027-.157-.077-.251-.14-.29-.08-.051-.248-.096-.496-.127a.858.858 0 0 1-.564-.29C8.57 1.401 8.5 1.185 8.5.921 8.5.317 8.933 0 9.716 0c.71 0 1.286.19 1.72.574.432.382.656.893.671 1.522.02.952.033 1.553.043 1.802.009.238.041.458.097.658a.942.942 0 0 0 .26.447c.133.124.364.28.693.466a.926.926 0 0 1 .493.846c0 .252-.058.446-.183.58-.109.115-.281.237-.52.371-.21.118-.377.244-.504.376-.118.123-.212.315-.277.578-.025.102-.045.35-.06.733-.013.392-.027.912-.042 1.56a2.09 2.09 0 0 1-.305 1.097c-.2.323-.486.574-.853.75a2.811 2.811 0 0 1-1.233.263c-.784 0-1.216-.322-1.216-.934 0-.256.07-.47.214-.636a.855.855 0 0 1 .562-.297c.201-.027.344-.056.418-.083.048-.017.096-.06.14-.134a.996.996 0 0 0 .107-.396c.02-.195.031-.502.031-.92 0-.573.039-1.045.117-1.417.08-.382.222-.701.427-.954z" /> </svg>`,
        title: 'Code'
    };
}

 

Connecting to the Editor

Let’s add a tools property to the configuration object at the example.html.

<script>
    const editor = new EditorJS({
      autofocus: true,
      tools: {
        image: CodeInsert
      }
    });
</script>

 

Open example.html in a browser: if everything is fine, you will see a Plus Button of a Toolbox. Press Tab or click on the Plus Button and our Tool will be there.

After you select an Image Tool, the render will be called and returned input will be placed as a new Block. You can add some CSS classes to it and place styles at insert-code.css file.

Types
Date Created 13/08/2019
Licence MIT
Support Time(in Minutes) 20
Support Details