その後、そのサンプルを使っていたら「選択範囲末尾の改行がうまく制御できていない!」ということに気が付きました。
末尾の改行にも対応するサンプルを作成しました。
改行がうまく制御できないとはどういうことかというと、単純なサンプルは以下。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<title>textRange</title> | |
<body> | |
<textarea id=ta0 style="width:100%;height:50%;">123456 | |
1 | |
</textarea> | |
<textarea id=ta1 style="width:100%;height:50%;"></textarea> | |
</body> | |
<script> | |
resizeTo(200,300) | |
onload=function(){ | |
ta0.select() | |
ta1.value = '['+document.selection.createRange().text+']' | |
} | |
</script> | |
</html> |
サンプルの実行画面

「123456」から「1」までの改行は取得できていますが「1」より後ろの改行はtextプロパティには含まれていません。ただし末尾の改行はRangeオブジェクトの対象にはなっているのでtextプロパティを書き換えると、その変更は末尾の改行に対しても影響を及ぼします。
上記を考慮しないでtextプロパティを書き換えると末尾の改行が失われます。
その問題を解決してタブキーによるインデントの増減を可能にしたサンプルが以下です。
以下ソース
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<title>行番号</title> | |
<style type="text/css"> | |
.max{width:100%;height:100%} | |
.bc{border-collapse:collapse} | |
.of-hidden{overflow:hidden} | |
</style> | |
</head> | |
<body class="of-hidden"> | |
<table class="bc max"> | |
<tr><td><textarea id=ta class=max wrap=off></textarea></td></tr> | |
<tr height=1><td>行:<input id=inp行> 列:<input id=inp列></td></tr> | |
</table> | |
</body> | |
<script> | |
resizeTo(400,400) | |
ta.onkeyup=ta.onkeydown=function(){ | |
var obj=getテキストカーソル位置(this), str=this.value.slice(0,obj.start), arr=str.split('\n') | |
inp行.value = arr.length | |
inp列.value = arr[arr.length-1].length + 1 | |
} | |
ta.onkeydown=function(){ | |
if(event.keyCode!=9){return} | |
event.cancelBubble = true | |
var obj=getテキストカーソル位置(this), rng=document.selection.createRange(), str=this.value.slice(obj.start, obj.end) | |
if(event.shiftKey){ | |
if(str){ | |
rng.text = str.replace(/\n\t|\n {4}/g,'\n').replace(/^\t|^ {4}/g,'') | |
}else if(obj.end < this.value.length){ | |
var 文字数=Math.min(4,this.value.length-obj.end), reg=/^\t|^ {1,4}/, res | |
rng.moveEnd('character', 文字数) | |
if(res=rng.text.match(reg)){}else{ return false } | |
rng.text = rng.text.replace(reg,'') | |
rng.moveEnd('character', -(4-res[0].length)) | |
rng.select() | |
} | |
}else{ | |
rng.text = '\t' + str.replace(/\n/g,'\n\t') | |
} | |
return false | |
} | |
getテキストカーソル位置=function(elem){ | |
// 左記URLのページを参照させていただきました。 http://d.hatena.ne.jp/nakazawaken1/20100125/p1 | |
var rngSel=document.selection.createRange(), rngElem=document.body.createTextRange() | |
rngElem.moveToElementText(elem) | |
// rngSelより前の範囲を選択する(rngElemのEndをrngSelのStart位置に合わせる) | |
rngElem.setEndPoint('EndToStart', rngSel) | |
var f=function(rng){ | |
var str=rng.text, str0=str | |
// 選択文字数が0でない間(前の範囲) | |
while(rng.compareEndPoints('StartToEnd', rng) != 0){ | |
// 一文字ずつ範囲終了位置を前にずらしていく | |
rng.moveEnd('character', -1) | |
// ずらす前と後の文字列が異なる状態ならbreak | |
if(str0 != rng.text){break} | |
// ずらす前と後の値が同じ状態の間は改行を付け足していく。 | |
str += '\r\n' | |
} | |
return str | |
} | |
var str前=f(rngElem), str選択=f(rngSel), start=str前.length, end=start + str選択.length | |
return {start:start, end:end} | |
// 以下の方法では選択範囲の末尾に改行文字がある場合、意図した通りの動作にならない。 | |
/* | |
rngSel.moveStart('character', -this.value.length) | |
rngSel.moveEnd ('character', 1) | |
var reg=/\n/g, res=rSel.text.match(reg), 行, 列 | |
if(res){ | |
行 = res.length | |
列 = RegExp.rightContext.length - 1 | |
}else{ | |
行 = 0 | |
列 = rSel.text.length - 1 | |
} | |
inp行.value = 行 | |
inp列.value = 列 | |
*/ | |
} | |
inp行.onchange = inp列.onchange = function(){ setカーソル位置(ta, inp行.value, inp列.value) } | |
setカーソル位置=function(elem, 行,列){ | |
var arr=ta.value.split('\r\n'), rng=document.body.createTextRange() | |
行 = isFinite(行) ? 行 : 1 | |
列 = isFinite(列) ? 列 : 1 | |
rng.moveToElementText(elem) | |
rng.moveStart('character', arr.slice(0,行).join('\r\n').length - (行-1)) | |
rng.moveStart('character', 列 - arr[行-1].length - 1) | |
while(rng.compareEndPoints('StartToEnd', rng) != 0){ rng.moveEnd('character',-1) } | |
rng.select() | |
} | |
</script> | |
</html> |
0 件のコメント:
コメントを投稿