jim wrote:
Hi Jim,
I have a form that accepts free text from users in a single textarea
field. I would like for a select list of words (15 or so) to
autopopulate as the user types. For example, instead of typing
"customer" the user could type "cu" and the form finish it for him/
her.
The following script should work decently on IE5+ and Firefox 2.0, and
is close to working in Opera 9 (I have encountered a problem with
setSelectionRange, which unfortunately does not seem to work when the
length is zero).
The script uses DOM Ranges extensively, which are, if I remember
correctly, not well-supported across user agents. As a result, I am
afraid this script will not work outside a very limited set of browsers
(though it should not harm navigators deprived from DOM Ranges
functionalities).
Regards,
Elegie.
---
<form action="#">
<textarea
rows="5"
cols="50"
onkeypress="return autocomplete(this, event)"
onkeyup="return autocomplete(this, event)"
onclick="return autocomplete(this, event)"
></textarea>
</form>
<script type="text/javascript">
var autocomplete=(function(){
// here, define the start chars and their word
var values={ // min 2 chars
"cu" : "customer",
"he" : "hello",
"wo" : "world"
};
// do not edit the code below
(function(){
var v;
for (var k in values) {
v=values[k];
for(var ii=k.length+1; ii<v.length; ii++) {
values[v.substr(0,ii)]=v;
}
}
})();
var finishAndComplete=0;
var getCaretPos=function(el) {
var rng, ii=-1;
if(typeof el.selectionStart=="number") {
ii=el.selectionStart;
} else if (document.selection && el.createTextRange){
rng=document.selection.createRange();
rng.collapse(true);
rng.moveStart("character", -el.value.length);
ii=rng.text.length;
}
return ii;
}
var highlight=function(el, start, length) {
var rng;
// set the selection
if(el.setSelectionRange) {
el.setSelectionRange(start, start+length);
} else if(el.createTextRange){
rng=el.createTextRange();
rng.moveStart("character", start);
rng.collapse(true);
rng.moveEnd("character", length);
rng.select();
}
}
return function (el, evt) {
var ii=getCaretPos(el), txt, complete;
//1) check if there's some opportunity to autocomplete
if(ii!=-1) {
// validate that there's some word boundary *after*
if(ii==el.value.length ||
/^.\b.$/.test(el.value.substring(ii-1,ii+1))
){
// validate that the started word matches
txt=/\b(.(\B.)+)$/.exec(el.value.substr(0, ii));
if(txt) {
complete=values[txt[1].toLowerCase()];
if(complete) complete=complete.substring(txt[1].length);
}
}
}
// 2) manage the entry
if(finishAndComplete && evt.keyCode==13) {
// validate the entry with [RETURN]
if(evt.type=="keyup") {
highlight(el, ii+finishAndComplete, 0); // fails in Opera :'(
finishAndComplete=0;
}
return false;
} else {
// propose the entry
if(complete) {
// only autocomplete if the user is not deleting
if(evt.keyCode &&
evt.keyCode!=8 &&
evt.keyCode!=46
){
el.value=el.value.substr(0,ii)+
complete+
el.value.substring(ii);
highlight(el, ii, finishAndComplete=complete.length);
} else {
// selection deleted
finishAndComplete=0;
}
} else {
finishAndComplete=0;
}
}
}
})();
</script>