Open32

ProseMirrorのStateを簡単に調査

かりんとうかりんとう

開発の中だと、それぞれの役割の違いがなんとなくしか掴めなかったので、ちゃんとドキュメントを読んで役割と機能を調べる

かりんとうかりんとう

prosemirror-state provides the data structure that describes the editor's whole state, including the selection, and a transaction system for moving from one state to the next.

prosemirror-stateはエディタ全体のデータ構造(スキーマ?)と、セレクション、トランザクションシステムも含んでいるらしい。確かにstate.trはよく使う。

かりんとうかりんとう

一番使うのはEditorState

import {schema} from "prosemirror-schema-basic"
import {EditorState} from "prosemirror-state"
import {EditorView} from "prosemirror-view"

let state = EditorState.create({schema})
let view = new EditorView(document.body, {state})

公式のチュートリアルコードの中だと、EditorState.createでstateを生成し、viewに渡している。
schameはこの例だとbasic-schemaで最小構成ではない。
確かに、状態を管理するためには、その状態がどんなデータ構造か把握することが求められるので、この依存は妥当そう。

かりんとうかりんとう

トランザクションから新しいstateを作る、state.applyというメソッドがある。
ステートはイミュータブルで管理されているので、常に新しいオブジェクトを生成する。

let state = EditorState.create({schema})
let view = new EditorView(document.body, {
  state,
  dispatchTransaction(transaction) {
    let newState = view.state.apply(transaction)
    view.updateState(newState)
  }
})
かりんとうかりんとう

初期のステートを設定するためには、prosemirror-modelのDOMParserを利用する。

let content = document.getElementById("content")
let state = EditorState.create({
  doc: DOMParser.fromSchema(schema).parse(content)
})
かりんとうかりんとう

これはDOM(HTML)から直接やっているが、JSONではどうやるんだろう?
そもそも、入出力まわり詳しくないや。

かりんとうかりんとう

JSON Serializaerはビルトイン。toJSONとnodeFromJSONで対応するらしい。

Documents also come with a built-in JSON serialization format. You can call toJSON on them to get an object that can safely be passed to JSON.stringify, and schema objects have a nodeFromJSON method that can parse this representation back into a document.

かりんとうかりんとう

NodeにtoJSONが生えているので、state.doc.toJSONで全体のJSONが取り出せる。
逆に、Schemaに生えているnodeFromJSONでデシリアライズ可能。

かりんとうかりんとう

個人的には、一部を太字にしたい!というちょっとした要望だけでも、RTEはライブラリを入れて方がいいと思う。contenteditableはあまりにも、ブラウザ間の差異が激しすぎる。

かりんとうかりんとう

あ〜, MappingやRebase周りの話は理解できてないな。別途スクラップを作るか

かりんとうかりんとう

エディタのステートには、大きく分けてドキュメント・セレクション・現在ONになってるマークがある。
state.doc, state.selection, state.storedMarksで取り出せる。

かりんとうかりんとう

プラグインによっては、ヒストリーなど別途状態を管理することもある。

かりんとうかりんとう

ike documents and other state-related values, they are immutable—to change the selection, you create a new selection object and a new state to hold it.

Selectionもその他のステートと同じように、イミュータブル。

かりんとうかりんとう

基本的には,selection.from, selection.to でインデックスを取得する。
ResolvePosが欲しい場合、selection.$fromで生成可能。

かりんとうかりんとう

Many selection types also distinguish between the anchor (unmoveable) and head (moveable) side of the selection, so those are also required to exist on every selection object.

紛らわしいものに、anchorとheadもある。う〜ん、いまいち違いがわからん。

かりんとうかりんとう

あ〜〜、範囲選択する時の基準と動的な方に分けてるのか。
右方向に範囲選択する時は、from,toと変わらないのかな?

かりんとうかりんとう

TransactionとStateには密接な関わりがあって、新しい状態を生成するためには、必ずstate.applyを通す。

かりんとうかりんとう

Transaction is a subclass of Transform, and inherits the way it builds up a new document by applying steps to an initial document. In addition to this, transactions track selection and other state-related components, and get some selection-related convenience methods such as replaceSelection.

TransactionはTransformのサブクラスで、セレクションも含んでいるので便利なメソッドが呼べる。

かりんとうかりんとう

The easiest way to create a transaction is with the tr getter on an editor state object. This creates an empty transaction based on that state, to which you can then add steps and other updates.

state.trは空のトランザクションを生成して、そこに新しく処理を加えられる。
あ〜これって空だったのか。前回の変更みたいな認識だった。

かりんとうかりんとう

Similarly, the set of active marks is automatically cleared after a document or selection change, and can be set using the setStoredMarks or ensureMarks methods.

setStoredMarksensureMarksでプログラムから、マークの設定も可能。

かりんとうかりんとう

TextSelectionは最も一般的で、よく使う範囲選択。
NodeSelectionはノード単位で選択する。ctrl/cmd-click でも選択可能らしい。

かりんとうかりんとう

EditorStateで出来ること

  • doc, selection, storedMarksの取得
  • state.trでトランザクションの開始
  • state.toJSONでJSONの出力
  • state.applyで新しいステートの生成