[컴] Editor.js 의 Block tool 만들기

extension , addon / plugin 만들기 / editorjs plugin / wyswyg editor / block style editor / editorjs extention / editorjs plugin

Editor.js 의 Block tool 만들기

Block tool 은 다양한 기능을 하게 만들 수 있다. 여기서는 가장 기본적인 내용만 정리했다. 자세한 내용은 ref. 1을 확인하자.

그래서 Block tool 은 2가지 경우를 처리한다.

  1. 원하는 type 으로 값을 입력하도록 정해졌을 때,
    • 그것에 대한 입력화면(render)
      • 여기서 input 에 event handler 등을 설정해 놓을 수 있다.
      • 예를 들어 image plugin 경우에 paste event 가 발생하면, 그 url 에 대한 image tag 를 만들게 하는 등의 작업을 하도록 할 수 있다.
      • 또는, 추가로 입력받는 곳을 보여주는 등의 작업.
    • 입력된 값을 data 로 추출될때 어떤 format 으로 만들것인지 결정(save)
  2. 특정 type 으로 된 값이 들어올때 어떻게 처리할지.
  3. type 이 정해지지 않은 값이 paste 될 때, 그 값의 패턴을 보고 특정 작업을 하도록 할 수도 있다.

다시말하면, 해당 block을 특정 type 으로 처리할 수 있게 해준다고 보면 될 것 같다.

다음처럼 BlockTool 을 만들면, EditorJS 로 연결하게 된다. 이때 이 BlockTool 이 어떤 type 을 처리할 지를 정하게 된다. 아래 코드를 보면 MyBlockTool 은 type image100 으로 들어오는 값을 처리하게 되는 것이다.

const editor = new EditorJS({
  autofocus: true,
  tools: {
    // 여기의 `image` 가 type 이 된다.
    image100: MyBlockTool
  }
});

예를 들면, 다음과 같은 모습의 data 를 만들어주게 된다.

{
    "time": 1691648520461,
    "blocks": [
        {
            "id": "kuuLDGZNXn",
            "type": "image100", // <-- image100 type
            "data": {
                "url": "wtew"
            }
        }
    ],
    "version": "2.27.2"
}

입력 부분

기본적인 구조는 다음과 같다. rendersave 는 필수이다.

  • render 함수는 Toolbox 에서 선택됐을 때의 UI 를 그려준다.
  • save 함수는 block 에서 data 를 추출하는 역할을 한다.
  • Toolbox(메뉴) 에 보이게 하려면 static get toolbox 도 구현해야 한다.
    • 참고, Toolbox 는 그림에서 ‘+’ 기호를 누를 때 나오는 메뉴를 이야기한다.
class MyBlockTool {
    // 메뉴(Toolbox)에 보이는 내용
    static get toolbox() {
      return {
        title: 'Image',
        // icon: '<svg width="17" height="15" viewBox="0 0 336 276" xmlns="http://www.w3.org/2000/svg"><path d="M291 150V79c0-19-15-34-34-34H79c-19 0-34 15-34 34v42l67-44 81 72 56-29 42 30zm0 52l-43-30-56 30-81-67-66 39v23c0 19 15 34 34 34h178c17 0 31-13 34-29zM79 0h178c44 0 79 35 79 79v118c0 44-35 79-79 79H79c-44 0-79-35-79-79V79C0 35 35 0 79 0z"/></svg>'
      };
    }

    // 메뉴(Toolbox)에서 해당 tool을 선택해서 실행할 때 보이는 UI
    render(){
        return document.createElement('input');
    }
    
    save(blockContent){
      return {
        url: blockContent.value
      }
    }

    validate(savedData){
      if (!savedData.url.trim()){
        return false;
      }
      return true;
    }
}

Editor.js 와 연결

위에서 만든 BockTool 을 연결하려면 아래처럼 해주면 된다. 그러면 이제 화면의 메뉴에서 보인다.

const editor = new EditorJS({
  autofocus: true,
  tools: {
    // 여기의 `image` 가 type 이 된다.
    image: MyBlockTool
  }
});

그림처럼 toolbox 에서 정의한 내용이 menu 에 보여진다.

full code

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title></title>


<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>

<script type="text/javascript">


class MyBlockTool {
  constructor({
    data
  }) {
    this.data = data;
  }

  static get toolbox() {
    return {
      title: 'Image',
      icon: '<svg width="17" height="15" viewBox="0 0 336 276" xmlns="http://www.w3.org/2000/svg"><path d="M291 150V79c0-19-15-34-34-34H79c-19 0-34 15-34 34v42l67-44 81 72 56-29 42 30zm0 52l-43-30-56 30-81-67-66 39v23c0 19 15 34 34 34h178c17 0 31-13 34-29zM79 0h178c44 0 79 35 79 79v118c0 44-35 79-79 79H79c-44 0-79-35-79-79V79C0 35 35 0 79 0z"/></svg>'
    };
  }

  render() {
    this.wrapper = document.createElement('div');
    const input = document.createElement('input');

    this.wrapper.classList.add('simple-image');
    this.wrapper.appendChild(input);

    input.placeholder = 'Paste an image URL...';
    input.value = this.data && this.data.url ? this.data.url : '';

    input.addEventListener('paste', (event) => {
      this._createImage(event.clipboardData.getData('text'));
    });

    return this.wrapper;
  }

  _createImage(url) {
    const image = document.createElement('img');
    const caption = document.createElement('input');

    image.src = url;
    caption.placeholder = 'Caption...';

    this.wrapper.innerHTML = '';
    this.wrapper.appendChild(image);
    this.wrapper.appendChild(caption);
  }

  save(blockContent) {
    return {
      url: blockContent.value
    }
  }

  validate(savedData) {
    // if (!savedData.url.trim()) {
    //   return false;
    // }

    return true;
  }
}
</script>
<style type="text/css">
  .simple-image {
    padding: 20px 0;
  }

  .simple-image input {
      width: 100%;
      padding: 10px;
      border: 1px solid #e4e4e4;
      border-radius: 3px;
      outline: none;
      font-size: 14px;
  }
</style>

</head>
<body>
<div id="editorjs"></div>
<button id="save-button">Save</button>
<pre id="output"></pre>

<script>
    const editor = new EditorJS({
      // logLevel: 'VERBOSE',
      autofocus: true,
      tools: {
        image2: MyBlockTool,
      },
      
      data: {
        time: 1552744582955,
        blocks: [
          {
            type: "image2",
            data: {
              url: "https://cdn.pixabay.com/photo/2017/09/01/21/53/blue-2705642_1280.jpg"
            }
          }
        ],
        version: "2.11.10"
      }
    });

    const saveButton = document.getElementById('save-button');
    const output = document.getElementById('output');

    saveButton.addEventListener('click', () => {
      editor.save().then( savedData => {
        console.log(savedData)
        output.innerHTML = JSON.stringify(savedData, null, 4);
      })
    })
</script>
</body>
</html>

See Also

  1. 쿠…sal: [컴] Editor.js 에서 Inline Tool 예시

Reference

  1. Creating a Block Tool

댓글 없음:

댓글 쓰기