textarea で Enter キーが押されたら

textarea で Enter キーが押されたらフォームデータを送信したい、といった処理を JavaScript で行う場合のメモです。
※「textarea で Enter キーが押されたら・・・追記」もどうぞ。

実装のポイントとしては、

  1. 文字変換確定の際の Enter キーには反応しないように。
  2. 「送信」のつもりで Enter キーが押された場合、改行コードが入力されないように。

の2点。

まず 1. について。
通常の Enter と変換確定の Enter とをどうやって区別するかだけど、これは、Enter によって textarea に入力された文字が改行コードか否かで判断する。
通常の Enter なら、当然改行コードが入力される。
変換確定の Enter なら、確定した文字が入力され、改行コードは入力されない。

2. については、1. の流れで処理できる。
すなわち、Enter キーが押されたらカーソルの直前の文字を調べて、それが改行コードなら除去して「送信」処理を、改行コードでなければそのまま何も行わない。
考え方としては、思ったより簡単だ。

ただ、カーソルの直前の文字を調べるのがけっこう面倒臭い。

まずはカーソルの位置を調べなければならないということで、ネットで調べて、以下のコードを参考にさせて頂きました。
http://www.teria.com/~koseki/memo/xbselection/

カーソルの位置だけ分かればいいので、ちょっと端折ってこんな感じ。

var textareaElement = document.getElementById("textareaID")
if (document.selection != null
    && textareaElement.selectionStart == null) {
    // IE
    var range = document.selection.createRange();
    var bookmark = range.getBookmark();
    var originalContents = textareaElement.value;
    var marker = "\t";
    while(originalContents.indexOf(marker) != -1) {
        marker += "\t";
    }
    range.text = marker + range.text;
    var contents = textareaElement.value;
    var position = contents.indexOf(marker);
    range.moveToBookmark(bookmark);
    range.select();
    textareaElement.value = originalContents;
}
else {
    // FireFox
    var position = textareaElement.selectionStart;
}

position がカーソルの文字位置になるので、次はその直前の文字が改行コードか否かを調べる。
if (textareaElement.value.charAt(position - 1) == "\n")
でチェックして終わり、と思ってしまうけど、実はちょっとした落とし穴があって。

どうやら、IE だと textarea の改行コードは \r\n で、FireFox だと \n になるらしい。
Mac だと \r になるのかな。
Mac は持っていないので分からないけど。

まぁ、単に改行コードか否かを調べるだけなら、\n と \r の両方をチェックすればいいだけなので、特に苦労もないけど。
改行コードを除去しようと思ったら、改行コードが 1 文字のケースと 2 文字のケースがあるのは面倒だ。
ざっとこんな感じに処理すればいいだろうか。

var val = textareaElement.value;
var p = position - 1;
var flag = false;
var c = textareaElement.value.charAt(p);
if (c == "\n") {
    if (val.charAt(p - 1) == "\r") {
        p--;
    }
    flag = true;
}
else if (c == "\r") {
    flag = true;
}
else {
    p++;
}
textareaElement.value = val.substr(0, p) + val.substr(position);

これで flag が true なら通常の Enter なので「送信」処理を行えばいいということになる。

以上で終わりと言いたいけれど、最後にもうひと工夫必要。
IE の場合、textarea の value に値をセットすると、カーソル位置は文章の末尾に移動するらしい。
これでは、変換確定のたびにカーソルが文章末尾に移動してしまって不便だ。
末尾に文字を追加しているときは良いけど、文章の途中に文字を挿入しようという場合に困る。

そこで最後に

if (range != null) {
    range = textareaElement.createTextRange();
    range.move( "character" , p);
    range.select();
}

としてカーソルの位置を移動させておく。

ざっとこんな感じで行けると思うのだけど、どうだろう。

Leave a Reply