contenteditable属性とdocument.execCommand関数
当初はtextareaタグを使おうとしたのだが、このままだと正規表現とマッチした箇所が色付けできないようで、別の方法を使わないといけない。
そんな時はcontenteditable属性を好きなタグに付けてあげると、HTML上から好きに編集できるようになる。Web上でテキストエディタを作る時に利用されているようだ。
それに加え、document.execCommand関数を使うと太字にしたり、背景色を変えたり、いろいろな操作ができる。
実際にWeb上で動作が確認できるサイトを以下に書いておく。
https://codepen.io/chrisdavidmills/full/gzYjag/
https://codepen.io/fukaminmin/pen/JyzOLz
document.execCommand関数は一部ブラウザでは使用できない機能がある。
そのため、実際に使えるか確認する必要があるのだが、そのときはdocument.queryCommandSupported関数を使うといい。
var cmd = "bold";
if(document.queryCommandSupported(cmd)){
document.execCommand(cmd);
}
これで、ブラウザ上で正規表現とマッチした箇所を表示する準備ができた。Javascript上からテキストを選択する (Seletion型とRange型)
document.execCommand関数は選択されているテキストに対して処理を行う関数なので、どうにかしてマッチした部分を選択する必要が出てきた。
その選択もマウスを使うわけにも行かず、Javascriptから行う必要がある。
そんな時はSelection型とRange型を利用することができる。
Range: https://developer.mozilla.org/en-US/docs/Web/API/Range
Selection: https://developer.mozilla.org/en-US/docs/Web/API/Selection
var range = document.createRange(); // Range型の作成
range.setStart(node, index);
range.setEnd(node, index + regex_pattern.value.length);
//Selection型を取得して、rangeで指定した範囲を選択部分として登録する
window.getSelection().addRange(range);
//選択を解除した時は以下の関数を呼ぶ。
window.getSelection().removeAllRanges();
注意点として、Range.setStart()とRange.setEnd()に渡すnodeの型によって、indexの意味合いが変わってくる。
Text
、Comment、CDATASectionタイプ
のNodeならその中の文字列の添字と同じ意味合いになるが、それ以外のタイプのノードだと、子要素への添字になる。今回はテキストの一部を選択したかったので、分岐でうまいこと処理を実装する必要があった。
Node.nodeTypeの種類はNode型の変数からアクセスできる
Javascript初心者丸出しだが、最初はグローバル領域にあるものだと勘違いしていた。
一度、document.execCommand関数で分割されたテキストをもとに戻すと複数の子ノードに分割されたままになる。
(なんだが、ブラウザ依存な気もするが...)
正規表現で一致した箇所をdocument.execCommand関数を使ってマークした後、別の正規表現を使って他の部分をマークしたいケースが当然出てくる。
そのときは以前マークした部分をクリアーしてあげる必要が出てくるが、そのクリアーした後のテキストノードは分割されたままであって、それ起因のエラーに出くわしてしまった。
Node.textContentを使っているとそれに気が付かずに、しばらく原因がわからず困ってしまった。
一度原因がわかれば、一つの子ノードにまとめれば解決できるので、まとめようとしたところ・・・添字アクセス違反のエラーが起きてしまった。なぜ?
子要素の削除にはChildNode.remove関数を使ったほうがいい。…?
子要素へのアクセスはNode.childNodesを利用している。
はじめは、Node.removeChild関数を使ったが、なぜかundefinedになっていた。
ここらへんはHTMLDivElement型からremoveChild関数を呼び出そうとしてのが間違いだった。
子ノードの削除はChildNode型のremove関数を使うとできるようだ。
終わりに
以上のことで、やりたいことを形に大体できた。
ここに書いていないが正規表現のパイプライン化の処理を追加するとツールはできる。
ただ一つ問題点があって、置換する時に正規表現のキャプチャー機能の扱いをどうするか決めなければいけない。
実際、この機能が欲しい。というゆうより無いととても不便である。
単純に各正規表現でキャプチャーしたものを指定できるようにするのか、オレオレ仕様の謎仕様に仕立て上げるのか、正規表現の仕様を頑なに守ろうとするのか。
どのようにすれば自然な形にキャプチャーできるのかはまた別に考えることにする。
けど、$1.2みたいにドットで区切って指定する形が無難でいいと思う。
0 件のコメント:
コメントを投稿