ブラウザーでも表計算みたいに入力したい
…とかいう要望が出ることがありますね。
やってみましょう。
テキストボックスをたくさん並べて…、じゃないですよ。
worksheet.html
<style>
*{
word-break:break-all;
word-wrap:break-word;
overflow-wrap:break-word;
box-sizing:border-box;
}
#worksheet{width:100%;border-collapse:collapse;}
#worksheet th{background-color:gainsboro;border-right:solid 1px gray;border-bottom:solid 1px gray;}
#worksheet thead tr th{}
#tbody tr th{width:64px;}
#tbody tr td{border:solid 1px gray;font-size:16px;font-family:sans-serif;white-space:pre;}
#textarea{position:absolute;background-color:lemonchiffon;font-size:16px;font-family:sans-serif;}
</style>
<table id="worksheet">
<thead id="thead">
<tr>
<th></th>
<th>A</th>
<th>B</th>
<th>C</th>
</tr>
</thead>
<tbody id="tbody">
<tr>
<th>1</th>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<th>2</th>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<th>3</th>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<th>4</th>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
<table>
<textarea id="textarea"></textarea>
テキストボックスはひとつだけです。入力する位置へ動かすのです。
表は、動的に生成しても良いですね。
機能部分
これで各セルに入力できるようになります。
あとは、ファイルに保存とか、データベースから…とか、計算式を…とか、好きにやってください。
カラム幅の指定とか、行固定のスクロールとか、凝り始めたらキリがないですね。
行の追加・削除くらいは欲しいかな。
worksheet.js
var pos;
var textarea;
var table;
var thead;
var tr;
var tbody;
window.addEventListener('DOMContentLoaded',function(event)
{
table=document.getElementById('worksheet');
thead=document.getElementById('thead');
// セルサイズの固定化
tr=document.getElementById('thead').children[0];
for(i=0;i<tr.children.length;i++){
tr.children[i].style.width=tr.children[i].offsetWidth+'px';
tr.children[i].style.height=tr.children[i].offsetHeight+'px';
}
// 編集位置の初期設定
tbody=document.getElementById('tbody');
td=tbody.children[0].children[1];
textarea=document.getElementById('textarea');
pos=setpos(textarea,td,table);
// クリックした位置に移動
table.addEventListener('click',
function(event){
pos=setpos(textarea,event.srcElement,table);
td=event.srcElement;
},
false);
// リサイズに合わせてリサイズ
window.addEventListener('resize',
function(event){
pos=setpos(textarea,pos['td'],table);
},
false);
// 矢印キーで移動
document.addEventListener('keydown',onkeydown,false);
},false);
function setpos(textarea,td,table)
{
if(textarea && pos){
if(pos['td']){
pos['td'].innerHTML=textarea.value;
}
}
if(td && table){
pos={
"top" :td.offsetTop+table.offsetTop+1,
"left" :td.offsetLeft+table.offsetLeft+1,
"width" :td.offsetWidth-1,
"height":td.offsetHeight-1,
"col" :td.cellIndex,
"row" :td.parentNode.rowIndex,
"td" :td };
if(navigator.userAgent.match(/Firefox/)){
pos.top-=2;
pos.left-=1;
}
}
if(textarea){
if(td){
textarea.value=td.innerHTML;
textarea.style.top =pos['top']+"px";
textarea.style.left =pos['left']+"px";
textarea.style.width =pos['width']+"px";
textarea.style.height =pos['height']+"px";
}
}
return pos;
}
function onkeydown(event)
{
if(event.target==textarea){
switch(event.keyCode){
case 10: // return
break;
case 13: // enter
if(event.ctrlKey
|| event.shiftKey
|| event.altKey){ // 改行を入力させる
break;
}else{
textarea.blur();
}
break;
}
}else{
switch(event.keyCode){
case 38:
case 40:
case 37:
case 39:
if(event.keyCode==38){ // ↑
pos['row']--;
if(pos['row']<1){
pos['row']=1;
}
}else if(event.keyCode==40){ // ↓
pos['row']++;
if(tbody.children.length<pos['row']){
pos['row']=tbody.children.length;
}
}else if(event.keyCode==37){ // ←
pos['col']--;
if(pos['col']<=0){
pos['col']=1;
}
}else if(event.keyCode==39){ // →
pos['col']++
if(tr.children.length<=pos['col']){
pos['col']=tr.children.length-1;
}
}
newtd=tbody.children[ pos['row']-1 ].children[ pos['col'] ];
pos=setpos(textarea,newtd,table);
break;
case 10: // return
break;
case 13: // enter
textarea.focus();
event.preventDefault(); // 改行を入力させない
event.returnValue = false; // ie
default:
break;
}
}
}