ProseMirrorのStateを簡単に調査
ProseMirrorはview, state, model, transformなど機能ごとにパッケージが分かれている。
開発の中だと、それぞれの役割の違いがなんとなくしか掴めなかったので、ちゃんとドキュメントを読んで役割と機能を調べる
ProseMirrorのguideとReferencesでも読むかな
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の方かな
初期のステートを設定するためには、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
でデシリアライズ可能。
Backlogでも使われている。
割と色々な会社で使われているイメージがある(ラッパーライブラリを含めて)
個人的には、一部を太字にしたい!というちょっとした要望だけでも、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と変わらないのかな?
One reason I can think of is if you wanted to display a tooltip at the location closest to the user’s mouse after a selection. For this, you would use the selection $head.
なるほど〜。最後に選択した一の近くにツールチップを表示したいとかの用途があるのか。
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.
setStoredMarks
やensureMarks
でプログラムから、マークの設定も可能。
Selectionには以下の3つがある
- TextSelection
- NodeSelection
- AllSelection
Pluginに閉じた?状態もあるらしい。
TextSelectionは最も一般的で、よく使う範囲選択。
NodeSelectionはノード単位で選択する。ctrl/cmd-click でも選択可能らしい。
prosemirror-state
には、EditorState
, Transaction
, Selection
などが実装されている。
トランザクションもここなのか。
EditorStateで出来ること
-
doc
,selection
,storedMarks
の取得 -
state.tr
でトランザクションの開始 -
state.toJSON
でJSONの出力 -
state.apply
で新しいステートの生成