カーソルがどこにあるのか分かり易くするために、カーソルに水平線を追従させるサンプルを作成してみました。
追従している様子

ソース
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 style="line-height:16px"></textarea></td></tr> | |
<tr height=1><td>行:<input id=inp行> 列:<input id=inp列></td></tr> | |
</table> | |
<hr id=hr style="position:absolute"> | |
</body> | |
<script> | |
resizeTo(400,400) | |
ta.onfocus=ta.onclick=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 | |
カーソル追従() | |
} | |
sumOffset=function(elem, p){ | |
var n=elem[p], PA='parentNode', n0 | |
while(elem[PA]){ n0=(elem=elem[PA])[p], n += isFinite(n0) ? n0 : 0 } | |
return n | |
} | |
カーソル追従=function(){ | |
var lh=getLineHeight(ta), s=hr.style | |
s.top = sumOffset(ta,'offsetTop') + lh * inp行.value - ta.scrollTop | |
s.left = sumOffset(ta,'offsetLeft') | |
s.width = ta.clientWidth | |
} | |
getLineHeight=function(ta){ | |
var c=document.body.insertBefore(ta.cloneNode(true)), h='scrollHeight', v=c.value='', h0=c[h], v=c.value='A\n', h1=c[h] | |
return c.removeNode(true), h1-h0 | |
} | |
ta.onkeydown=function(){ | |
var obj={9:タブキー操作, 13:エンターキー操作}, kc=event.keyCode | |
return obj[kc] ? obj[kc](this) : 0 | |
} | |
エンターキー操作=function(elem){ | |
var obj=getテキストカーソル位置(elem), res=elem.value.slice(0,obj.start).match(/(\r?\n?)([\t ]*)[^\r\n]*$/), rng=document.selection.createRange() | |
rng.text = (res[1] || '\r\n')+res[2] | |
rng.select() | |
return false | |
} | |
タブキー操作=function(elem){ | |
event.cancelBubble = true | |
var obj=getテキストカーソル位置(elem), rng=document.selection.createRange(), v=elem.value, L=v.length, str=v.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 < L){ | |
var 文字数=Math.min(4,L-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} | |
} | |
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> |
昨日の記事で「lineHeightが未定義でも取得する!」とか言ってましたが今回のサンプルにそれを使ってみたら微妙に値が小さくて改行するたびに水平線が徐々にカーソルの↑へ行ってしまったのでやむなくlineHeightを設定しました。
解像度が高くなくても液晶画面のバックライトが控えめだとかコントラストが低いとか目が疲れてるとか色々要因はありますが…。
0 件のコメント:
コメントを投稿