JavaScript
form
Codemirror

CodeMirrorでテキストフィールドを拡張する

More than 1 year has passed since last update.

俺の考えた最強のTODOリストを作るために便利なテキストフィールドを作ってみます。

screencast 2018-03-16 22-34-36.gif

See the Pen Custom CodeMirror TextField by Yuki Takemoto (@mottox2) on CodePen.


なぜCodeMirrorか

TextFieldにハイライトをつけるには、まずはcontenteditableを使った、WYSIWYGエディタによく使われる方法が考えられますが、これを生で触るのは非常に大変です。なので便利なライブラリに頼ります。

調べたところCodeMirrorがいいのではと感じたのでCodeMirrorを使っていきます。1

CodeMirrorは、Web上で動いて、JSなどのコードにハイライトをつけることの出来るライブラリです。

各言語のハイライトはmodeという形で管理されていて、自分でmodeを追加することができます。つまり、独自のハイライトを定義することが出来ます。

今回はこのCodeMirrorに独自のハイライトmodeを定義し、TextAreaをTextFieldライクな表示にすることで、便利テキストフィールドを作っていきます。


環境

CodeMirror v5.35.0

[CSS]

https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.35.0/codemirror.css

[JavaScript]

https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.35.0/codemirror.js

https://codemirror.net/mode/javascript/javascript.js


1. CodeMirrorを導入してみる

普通にうごきます。このようにCodeMirrorはmodeを指定することでシンタックスハイライトをつけられる便利なライブラリです。

See the Pen Simple CodeMirror sample by Yuki Takemoto (@mottox2) on CodePen.

CodeMirrorでブラウザ上で動作するコードエディタを作るを見るとわかりやすいと思います。


2. mode(ハイライト方法)を定義する

1.の例では元から用意されていたJavaScript modeを選択しましたが、今回は自分でハイライトのルールを作りたいのでmodeを定義します。

公式のDoc に解説がありますが、非常に読むのがしんどいので、実際に動作しているmodeのコードを読みます。



yaml mode

js mode

このようにGithubのリポジトリに各言語で定義されているmodeがあるので読んでいくと以下の書き方で書けることがわかります。


modeの定義

CodeMirror.defineMode('MODE_NAME', {

token: function(stream, state) {
if (stream.match(/REGEXP/)) {
return 'keyword'
}
return null
}
})

streamで処理していく形です。マッチしたら keyword, commentなどのstringで返すとそれに応じたclassを付与してくれます。

ドキュメントに書いてくれればいいんですけど、defineModeに関する記述は見つかりませんでした。2

このmodeを定義して、動かしてみるとこんな感じに動かせます。

See the Pen Custom CodeMirror Sample by Yuki Takemoto (@mottox2) on CodePen.


3. TextAreaをTextFieldにします。

改行禁止にすれば同じようなものが再現できます。ここで本来注意しなければいけないのは、キーボードの挙動だけでなくペースト時の挙動も把握しておく必要があります。

しかし、CodeMirrorは便利なもので毎回の変更をbeforeChangeイベントの引数で扱うことができます。

js

beforeChange = function(editor, change, value ) {

// Do something...

}

{from: Pos, to: Pos, text: Array(1), removed: Array(1), origin: "paste"}

{from: Pos, to: Pos, text: Array(1), removed: Array(1), origin: "input"}

これらの情報を持ったオブジェクトが渡ってくるので、Changeオブジェクトをupdateすることで入力したものを上書きすることが出来ます。

参考

https://stackoverflow.com/questions/13026285/codemirror-for-just-one-line-textfield

See the Pen Custom CodeMirror TextField by Yuki Takemoto (@mottox2) on CodePen.


やっていき宣言

これからこのテキストフィールドを使って俺の考えた最強のTODOリストを作っていきます。

なおReactからCodeMirrorを使うには react-codemirror2 がよさそうな感じです。





  1. kibe.la のテキストエリアはCodeMirrorを使ってMarkdownにハイライトをつけていました。これがなかなかいい挙動で初めて触った時感動しました。 



  2. defineSinpleModeというメソッドも定義されていますが、npmで配布されているCodeMirrorではexportされていません。