(JavaScript) OperaでselectionStartする時の注意

テキストボックスの中のキャレットの位置を知るには、IE以外は"selectionStart"を使います。




(HTML)
<textarea id="hoge">aaaa
bbbb
cccc</textarea>

(JavaScript)
var pos = document.getElementById('hoge').selectionStart;
alert(pos);

※ (jQuery)
var pos = $('#hoge').get(0).selectionStart;


しかし、Operaの場合は、改行を2文字として扱ってしまうようです。
(Opera11, Opera12で確認)
キャレットを移動させる"setSelectionRange"でも同様です。


文字列を抜き出す"substr"などは、Operaでも改行を1文字として扱います。
取得したキャレットの位置と、これらのメソッドを組み合わせて使う場合は、何らかの対処が必要です。


(JavaScript)
var pos = document.getElementById('hoge').selectionStart;
var text = substr(0, pos);

//"substr"で抜き出す範囲に改行が含まれている場合、
//Operaでは"pos"の数値が改行の数だけ不当に増える。
//当然、"text"の内容が他のブラウザとは異なってしまう。
改行の数だけ"pos"が増えてしまうなら、
『pos - (改行の数)』
で、適正化できそうな気もします。
が、増えたことで本来は含まれない改行も含まれていたとしたら…?



私が採った解決策は下記です。

  1. "selectionStart"でキャレットの位置を取得。
  2. 元の文章に対して、改行の隣に1文字増やすという加工を施す。
  3. 加工文に対して"substr"を実行。
  4. 抜き出した文章の改行を数える。
    これが、本来のキャレット位置までの改行の数となる。
  5. キャレットの位置からその改行数を引いたものが、正常な値。
実際のコード

(JavaScript)
var pos = document.getElementById('hoge').selectionStart;
if (window.opera) {
//'a'に深い意味は無い。文字数を増やすためだけの処置。
var alltext = textarea_value.replace(/\n/g, '\na');
var range = alltext.substr(0, pos);
var arr_skip = range.match(/\n/g);
var len_skip = (arr_skip)
? arr_skip.length
: 0;
pos = pos - len_skip;
}

alert(pos);
//Opera, Firefox, GoogeChromeで同一の値となる。


"setSelectionRange"では、範囲内の改行の数をそのまま足すだけでいいので単純明快です。