ProseMirror Plugin class(트랜잭션이 발생할 때마다 count 를 1씩 증가 / 랜더링해서 view에 적용)

jini.choi·2023년 8월 2일

ProseMirror

목록 보기
2/2

문제 1

트랜잭션이 발생할 때마다 count 를 1씩 증가시키는 플러그인을 만들어 봅니다.

내가 한 풀이

import { Plugin } from "prosemirror-state";

/**
 *  1. 트랜잭션이 발생할 때마다 count 를 1씩 증가시키는 플러그인을 만들어 봅니다.
 *
 */
const counterPlugin = new Plugin({
  state: {
    init() {
      return { count: 0 };
    },
    apply(tr, value) {
      if (tr.docChanged) {
        return { count: value.count++ };
      }
      return value;
    },
  },
});
console.log(counterPlugin);
export default counterPlugin;

정답

import { Plugin } from "prosemirror-state";

/**
 *  1. 트랜잭션이 발생할 때마다 count 를 1씩 증가시키는 플러그인을 만들어 봅니다.
 *
 */
const counterPlugin = new Plugin({
  state: {
    init() {
      return { count: 0 };
    },
    apply(tr, value) {
      return { count: value.count + 1 };
    },
  },
});

export default counterPlugin;

내 풀이와 답지의 차이점

내 풀이

apply 메서드에서 if (tr.docChanged) 조건을 사용하여 트랜잭션이 문서에 변경 사항을 가지고 있는 경우에만 value.count1을 더하고 새로운 상태 객체를 반환한다. 만약 문서에 변경 사항이 없는 경우에는 value.count를 그대로 반환된다.

답지

apply 메서드에서 항상 value.count1을 더하여 새로운 상태 객체를 반환한다. 이렇게 하면 트랜잭션이 발생할 때마다 count가 무조건 1씩 증가.


용어정리

init() 메서드

ProseMirror Plugin에서 상태를 초기화하는 메서드

insertText() 메서드

ProseMirror에서 Transaction을 통해 에디터에 텍스트를 삽입하는 메서드

insertText(position, text)
  • position: 텍스트를 삽입할 위치를 나타내는 숫자. ProseMirror에서는 텍스트의 위치를 0부터 시작하는 인덱스로 표현함.

  • text: 삽입할 텍스트를 나타내는 문자열.

tr.docChanged 객체 속성

ProseMirror의 Transaction 객체의 속성 중 하나.
Transaction은 에디터의 상태를 변경하는 동작을 나타내며, tr.docChanged 속성은 해당 Transaction이 문서에 변경 사항을 가지고 있는지를 나타내는 불리언(Boolean) 값이다.


문제 2

PluginView 를 사용해 숫자를 렌더링해 봅니다.

class counterPluginView {
  /**
   *
   * @param {EditorView} editorView
   */
  constructor(editorView) {
    // 1. 숫자를 표기할 요소를 생성한다. (클래스명은 counter 로 지정한다.)
    this.counter = document.createElement("div");
    this.counter.textContent = "0";
    this.counter.classList.add("counter");

    // 2. 에디터의 부모 요소에 숫자를 표기할 요소를 추가한다.
    const editorHolder = editorView.dom.parentNode;
    editorHolder.insertBefore(this.counter, editorView.dom);
  }

  // 3. 에디터의 상태가 변경될 때마다 호출되는 update 메서드에서 숫자를 업데이트 한다.
  update(view) {
    const { count } = counterPlugin.getState(view.state);
    this.counter.textContent = count;
  }
}

counterPluginView 클래스

숫자를 렌더링하고 업데이트하는 뷰(View) 클래스
editorView를 constructor의 인자로 받아 사용한다.

💻 JSDoc 형식으로 작성된 주석.
@param는 JSDoc 태그로 counterPluginView 클래스의 생성자에 전달되는 인자 editorViewEditorView 클래스의 인스턴스임을 명시해준다.

@param {EditorView} editorView

JSDoc는 JavaScript 코드의 주석을 통해 코드의 문서화를 위한 주석 형식. JSDoc 주석은 코드에 메타데이터와 타입 정보를 추가하여 코드를 문서화하고 IDE에서 코드 자동 완성, 타입 체크 등의 기능을 지원하도록 도와준다.

💻 constructor에서는 숫자를 표시할 div를 생성한다.

this.counter = document.createElement("div");

💻 textContent를 이용해 해당 요소의 텍스트를 0으로 초기값을 설정한다.

this.counter.textContent = "0";

💻 counter 클래스명을 부여하여 스타일링을 위한 준비를 한다.

this.counter.classList.add("counter");

💻 editorView.dom은 ProseMirror 에디터의 View에 해당하는 DOM 요소이며, editorView.dom.parentNode는 이 뷰의 부모 DOM 요소를 나타낸다.

하여, editorView를 통해 에디터의 DOM 요소에 접근한 뒤, 그 부모 요소를 editorHolder 변수에 저장한다. 이렇게 함으로써 .counter 요소를 에디터 위에 추가하는 작업을 수행할 수 있다.

const editorHolder = editorView.dom.parentNode;

💻 editorHolder 요소 내에 this.counter 요소를 editorView.dom 요소의 앞에 삽입

  • this.counter: counterPluginView 클래스에서 생성한 숫자를 표시할 div 요소.
  • editorView.dom: ProseMirror 에디터 View의 DOM 요소입니다.
  • insertBefore() : HTML 요소를 다른 요소 앞에 삽입하는 메서드. 다른 요소의 앞에 추가하여 DOM 구조를 조작
editorHolder.insertBefore(this.counter, editorView.dom);

💻 update 메서드는 에디터의 상태가 변경될 때마다 호출되며, view 객체를 인자로 받아 에디터의 상태를 기반으로 숫자를 업데이트하는 역할

update(view) {...}

💻 count 변수에 counterPluginstate 객체에서 count 프로퍼티를 가져와 할당한다. count 변수는 플러그인의 state에서 count 프로퍼티의 값과 동일하게 된다.

getState() 메서드는 Plugin 클래스에 정의된 메서드로, Plugin의 상태를 가져오는 역할. 여기서는 counterPlugin의 상태를 가져와서 count라는 변수에 할당한다.

const { count } = counterPlugin.getState(view.state);

💻 this.countercounterPluginView 클래스의 인스턴스 변수로, 숫자를 표시하는 div 요소. this.counter 요소의 textContentcount 값으로 업데이트하여 숫자를 에디터 위에 표시한다.

this.counter.textContent = count;

최종

import { Plugin } from "prosemirror-state";
import { EditorView } from "prosemirror-view";

class counterPluginView {
  /**
   *
   * @param {EditorView} editorView
   */
  constructor(editorView) {
    // 1. 숫자를 표기할 요소를 생성한다. (클래스명은 counter 로 지정한다.)
    this.counter = document.createElement("div");
    this.counter.textContent = "0";
    this.counter.classList.add("counter");

    // 2. 에디터의 부모 요소에 숫자를 표기할 요소를 추가한다.
    const editorHolder = editorView.dom.parentNode;
    editorHolder.insertBefore(this.counter, editorView.dom);
  }

  // 3. 에디터의 상태가 변경될 때마다 호출되는 update 메서드에서 숫자를 업데이트 한다.
  update(view) {
    const { count } = counterPlugin.getState(view.state);
    this.counter.textContent = count;
  }
}

const counterPlugin = new Plugin({
  state: {
    init() {
      return { count: 0 };
    },
    apply(tr, value) {
      return { count: value.count + 1 };
    },
  },
  view(editorView) {
    return new counterPluginView(editorView);
  },
});

export default counterPlugin;
profile
개발짜🏃‍♀️

0개의 댓글