2008年12月27日土曜日

今さらながら入力補完JavaScript(8)

【段取り】
(4)テキストボックスに入力された文字列にマッチする補完候補をリスト表示する。

【詳細】
今は変数に入った値全部を表示していますが、これを入力された文字列にマッチするものだけ表示するようにします。

今まで便宜的にfocusで候補リストを表示していましたが、ここを全て書き換えて(うわああぁぁぁ!)、キーボードから文字列が入力されたタイミングで候補リストを出力するように変更します。

【結論】
ダメですね。onkeypressイベントでテキストボックスの値を見ても、最後に入力された文字列が入らない。
かなり直感に反する動きになっています。文字を入力した後、右矢印キーなど無害なキーを押さないと、入力した文字を使ってくれません。

余裕があったらキーイベントに依存するのではなく、suggest.jsみたいにtimerで定期的に検索する形に変えてみたいと思います。

ソースを見ていただければバレバレですが、もう付け刃に付け刃してって感じで大変でした。やっぱりJavaScriptはツラい・・・

ディレクトリ構造は変更なしです。
WebContent
- js/prototype.js
- js/my.js
- a.html
- my.css

■my.js
// 外出しです。
var div1 = null;
var cursor_pos = -1;
var element_len = 0;

Event.observe(window, 'load', function(event) {
// イベントを登録します。
var keyevent = 'keydown';
if (window.opera || (navigator.userAgent.indexOf('Gecko') <= 0
&& navigator.userAgent.indexOf('KHTML') == -1)) {
keyevent = 'keypress';
}
Event.observe($('hoge'), keyevent, function(event) {
if (event.keyCode == Event.KEY_DOWN) {
if (element_len < cursor_pos) {
cursor_pos++;
}
var hogeTmp = $('div1'+cursor_pos);
initiateListColors();
hogeTmp.style.backgroundColor = '#00FF00';
} else /* elseをつけましたよ */
if (event.keyCode == Event.KEY_UP) {
if (cursor_pos > 0) {
cursor_pos--;
}
var hogeTmp = $('div1'+cursor_pos);
initiateListColors();
hogeTmp.style.backgroundColor = '#00FF00';
} else
if (event.keyCode == Event.KEY_TAB
|| event.keyCode == Event.KEY_RETURN) {
if (cursor_pos >= 0) {
var hogeTmp = $('div1'+cursor_pos);
$('hoge').value = hogeTmp.innerHTML;
}
$('candidate').style.visibility = "hidden";
} else {
// クリアします
$('candidate').innerHTML = "";
$('candidate').style.visibility = "visible";
cursor_pos = -1;

var i;
var size = -1; // <- 当たり前ですが重要です。
var rObj = new RegExp($('hoge').value);
for (i = 0; i < week.length; i++) {
// 入力された文字が一致していた候補を表示します。
var tmpSearch = week[i];
if (tmpSearch.match(rObj) != null) {
size++; // <- iではなくてsizeをincreしながら使います
// 文字列がマッチしていたらappendします。
var tmpId = 'div1'+size;
div1 = new Element('div', {'id' : tmpId });
div1.innerHTML = week[i];
div1.style.backgroundColor = "#FF0000";
div1.style.width = "100px";
$('candidate').appendChild(div1);
Event.observe(tmpId, 'mouseover', function(event) {
this.style.backgroundColor = "#00FF00";
});
Event.observe(tmpId, 'mouseout', function(event) {
this.style.backgroundColor = "#FF0000";
});
Event.observe(tmpId, 'mousedown', function(event) {
$('hoge').value = this.innerHTML;
$('candidate').style.visibility = "hidden";
});
}
}
element_len = size;
}
});
// onBlur イベントを登録します。
Event.observe('hoge', 'blur', function(event) {
if (div1) {
// div1がnullでない場合はhiddenにします。
$('candidate').style.visibility = "hidden";
// ポジションを初期化します。
cursor_pos = -1;
}
});
});

function initiateListColors() {
var tmpElems = $('candidate').childElements();
for (var j = 0; j < tmpElems.length; j++) {
tmpElems[j].style.backgroundColor = "#FF0000";
}
}

■a.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-31j">
<script type="text/css" src="my.css"></script>
<!-- 変数をmy.jsより先に読み込む必要があります。 -->
<script type="text/javascript">
var week = new Array("hokkaido","aomori","akita",
"yamagata","miyagi","niigata","fukushima",
"ikkei", "komori", "higata");
</script>
<script type="text/javascript" src="js/prototype.js"></script>
<script type="text/javascript" src="js/my.js"></script>
<title>Ajax tutorial - a</title>
</head>
<body>
<input type="text" id="hoge" name="hoge" />
<div id="candidate"></div>
</body>
</html>

■my.css

@CHARSET "UTF-8";
/* CSSは表示と関係ありません */
#div1 {
visibility:hidden;
}

.

0 件のコメント: