hello
actb is a very good script, but I don't agree with a choice: when I press tab I do want the focus to change to the next control. having tab disabled forces the user to use the mouse...
also if I press tab maybe I just want to leave in the textbox only the text I wrote, not the full item selected in the actb table.
to solve it I changed the function that handles the keypress event:
in the switch just change the 09 keycode case to return true
I'm also working with some code I found in a javascript calendar (DHTML calendar) to hide selects and iframes when the actb table collides with them...
Firstly - great control. Just a couple of quick questions.
I've been using this in forms on internet explorer and IE then starts to turn use it's form autocompletion for putting in values. This means that IE's auto completion box appears instead over the top of the ACTB one. It's obviously possible to turn IE's autocomplete off for all forms... but is it possible to do it for just selected controls?
Also - I've got this control in a table and the row underneath has another control (a select box). The ACTB auto complete list then starts by appearing underneath the control. Is it possible to force it on top?
Hi guytp
switch msdn, you have an html attribute autocomplete, see
http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/autocomplete.asp
So you must add autocomplete="off" into the html input in order to disable IE autocomplete like this :
It seems works too with Firefox.
You can too disable autocomplete in Javascript. Add code at end in your HTML :
document.getElementById("cb").autocomplete="off";
But this code seems work just with IE and not with Firefox.
This is a great component.
Unfortunately with lots of values like I'm using it with 25000 Entries from the database it brings a big memory leak each time the browser is refreshed.
If you could look into that this would be great.
A very nice implementation of an autocomplete!
I also have this memory leak after each refresh, using 10000 elements.
The first time everything loads very fast, then slower & slower.
I guess the object isn't cleaned up after a refresh?
-> any events still open?
-> closures?
I was trying to make this into a web control, but I can't get it to work.
I just have all the script in my code as variables, which I emit to the page via RegisterClientScript. The end product looks correct, but does nothing. No errors are reported, either.
Anyone else do this, or have any suggestions or 'gotchas'?
i would just like to ask how you can disable the first option from being highlighted without the user choosing it? i mean when you type something and the autocomplete box appears, when you press the 'enter' button, you get the first value in the list. how can i make it in such a way that the user has to press the 'down' button first before an entry is highlighted and then the user presses the 'enter' button after a value has been chosen by the use of the 'down' or 'up' button.
I would like to see the autocomplete Control dissapear instead of staying there when the user has already typed in the complete word such as "elephant" and the only suggestion left is "elephant". Thank you
hiya..your widget is very much appreciated! Just wondering whether it is possible to make it work for IE Mac. I know not a lot of people don't have macs but still some people do (like me )..Any ideas? thanks
Hi, this is some great work !
The problem i have is when my item in the array contains two words. Such as an apple and i am typing "an ap" and hit the enter or tab key the word changes to an an apple. You can try this with the textbox within this page. Any help would be much appreciated.
Opps This result because a default delimiter of the demo control is a space ' '. I've since updated the article (with various other bug fixes) and re-submitted to CP.
Hi,
at first I would like congratulate zichun for his article and auto-complete control. I send you my ideas to improve functionnality of this control :
1. add second array (customarrayDesc) for display desciption in the list (ex => [an apple : it's an apple] instead of [an apple].
2. display bar on right which display ieme item/ total item. The best would be display a scrollbar on right.
I have realized this 2 ideas. I have download last version of actb.js and there where a bug (variable actb_curractb_bgColor was not defined). I have corriged it. When I update code I have write // code ADDED before.
<html>
<head>
<script language="javascript" type="text/javascript" src="actb.js"></script>
<script language="javascript" type="text/javascript" src="common.js"></script>
<script>
var customarray=new Array('an apple','alligator','elephant','pear','kingbird','kingbolt', 'kingcraft','kingcup','kingdom','kingfisher','kingpin');
// code ADDED : array which contains description of customarray
var customarrayDescription = new Array('this is an apple','this is alligator','this is elephant','this is pear','this is kingbird','this is kingbolt', 'this is kingcraft','this is kingcup','this is kingdom','this is kingfisher','this is kingpin');
</script>
</head>
function actb(obj,ca,caDesc){
// code ADDED : parametre caDesc is an array which contains description of first array ca
/* ---- Public Variables ---- */
this.actb_timeOut = -1; // Autocomplete Timeout in ms (-1: autocomplete never time out)
this.actb_lim = 4; // Number of elements autocomplete can show (-1: no limit)
this.actb_firstText = false; // should the auto complete be limited to the beginning of keyword?
this.actb_mouse = true; // Enable Mouse Support
this.actb_delimiter = new Array(' ',','); // Delimiter for multiple autocomplete. Set it to empty array for single autocomplete
this.actb_startcheck = 1; // Show widget only after this number of characters is typed in.
/* ---- Public Variables ---- */
/* ---- Private Variables ---- */
var actb_delimwords = new Array();
var actb_cdelimword = 0;
var actb_delimchar = new Array();
var actb_display = false;
var actb_pos = 0;
var actb_total = 0;
var actb_curr = null;
var actb_rangeu = 0;
var actb_ranged = 0;
var actb_bool = new Array();
var actb_pre = 0;
var actb_toid;
var actb_tomake = false;
var actb_getpre = "";
var actb_mouse_on_list = 1;
var actb_kwcount = 0;
var actb_caretmove = false;
this.actb_keywords = new Array();
/* ---- Private Variables---- */
this.actb_keywords = ca;
// code ADDED : array which contains description of first array ca
this.actb_keywordsDesc = caDesc;
// code ADDED : bar
this.actb_bar = null;
var actb_self = this;
actb_curr = obj;
addEvent(actb_curr,"focus",actb_setup);
// code ADDED : function which returns code with description
function actb_codedesc(code, desc) {
return code + " : " + "<font style='"+(actb_hStyleDesc)+"'>" + desc + "</font>";
}
// code ADDED : function which generate bar on right (ieme item/total item)
function actb_generate_bar(a) {
// generate bar if row > 1 and actb_lim >0
if (actb_lim >0) {
var nbRows = a.rows.length;
if (nbRows > 1) {
// Construct bar on right of table
bar = a.rows[0].insertCell(-1);
bar.id="actb_bar";
bar.style.fontSize = actb_fSize;
bar.style.backgroundColor = "#DDEEFF";
bar.style.color = "red";
bar.style.fontWeight = "bold";
bar.rowSpan=nbRows;
bar.style.verticalAlign= "bottom";
bar.height="100%";
this.actb_bar = bar;
actb_refresh_bar();
}
}
}
// code ADDED : function refresh bar on right (ieme item/total item)
function actb_refresh_bar() {
if (this.actb_bar != null)
this.actb_bar.innerHTML = actb_pos + "/" + actb_total;
}
function actb_setup(){
addEvent(document,"keydown",actb_checkkey);
addEvent(actb_curr,"blur",actb_clear);
addEvent(actb_curr,"keypress",actb_keypress);
}
function actb_clear(evt){
if (!evt) evt = event;
removeEvent(document,"keydown",actb_checkkey);
removeEvent(actb_curr,"blur",actb_clear);
removeEvent(actb,"keypress",actb_keypress);
actb_removedisp();
}
function actb_parse(n){
if (actb_self.actb_delimiter.length > 0){
var t = actb_delimwords[actb_cdelimword].trim().addslashes();
var plen = actb_delimwords[actb_cdelimword].trim().length;
}else{
var t = actb_curr.value.addslashes();
var plen = actb_curr.value.length;
}
var tobuild = '';
var i;
if (actb_self.actb_firstText){
var re = new RegExp("^" + t, "i");
}else{
var re = new RegExp(t, "i");
}
var p = n.search(re);
for (i=0;i<p;i++){
tobuild += n.substr(i,1);
}
tobuild += "<font style='"+(actb_self.actb_hStyle)+"'>"
for (i=p;i<plen+p;i++){
tobuild += n.substr(i,1);
}
tobuild += "</font>";
for (i=plen+p;i<n.length;i++){
tobuild += n.substr(i,1);
}
return tobuild;
}
function actb_generate(){
if (document.getElementById('tat_table')){ actb_display = false;document.body.removeChild(document.getElementById('tat_table')); }
if (actb_kwcount == 0){
actb_display = false;
return;
}
a = document.createElement('table');
a.cellSpacing='1px';
a.cellPadding='2px';
a.style.position='absolute';
a.style.top = eval(curTop(actb_curr) + actb_curr.offsetHeight) + "px";
a.style.left = curLeft(actb_curr) + "px";
a.style.backgroundColor=actb_self.actb_bgColor;
a.id = 'tat_table';
document.body.appendChild(a);
var i;
var first = true;
var j = 1;
if (actb_self.actb_mouse){
a.onmouseout = actb_table_unfocus;
a.onmouseover = actb_table_focus;
}
var counter = 0;
for (i=0;i<actb_self.actb_keywords.length;i++){
if (actb_bool[i]){
counter++;
r = a.insertRow(-1);
if (first && !actb_tomake){
r.style.backgroundColor = actb_self.actb_hColor;
first = false;
actb_pos = counter;
}else if(actb_pre == i){
r.style.backgroundColor = actb_self.actb_hColor;
first = false;
actb_pos = counter;
}else{
r.style.backgroundColor = actb_self.actb_bgColor;
}
r.id = 'tat_tr'+(j);
c = r.insertCell(-1);
c.style.color = actb_self.actb_textColor;
c.style.fontFamily = actb_self.actb_fFamily;
c.style.fontSize = actb_self.actb_fSize;
// code ADDED : for dispaly code and description
if (actb_keywordsDesc != null) {
// Get Code
var code = actb_parse(actb_self.actb_keywords[i])
// Get Description
var desc = actb_keywordsDesc[i];
c.innerHTML = actb_codedesc(code, desc);
}
else {
c.innerHTML = actb_parse(actb_self.actb_keywords[i]);
}
c.id = 'tat_td'+(j);
c.setAttribute('pos',j);
if (actb_self.actb_mouse){
c.style.cursor = 'pointer';
c.onclick=actb_mouseclick;
c.onmouseover = actb_table_highlight;
}
j++;
}
if (j - 1 == actb_self.actb_lim && j < actb_total){
r = a.insertRow(-1);
// Code Changed : BUG
r.style.backgroundColor = actb_self.actb_curractb_bgColor; //actb_self.actb_bgColor;
c = r.insertCell(-1);
c.style.color = actb_self.actb_textColor;
c.style.fontFamily = 'arial narrow';
c.style.fontSize = actb_self.actb_fSize;
c.align='center';
replaceHTML(c,'\\/');
if (actb_self.actb_mouse){
c.style.cursor = 'pointer';
c.onclick = actb_mouse_down;
}
break;
}
}
actb_rangeu = 1;
actb_ranged = j-1;
actb_display = true;
if (actb_pos <= 0) actb_pos = 1;
// generate bar on right (i eme item/total item)
actb_generate_bar(a);
}
function actb_remake(){
document.body.removeChild(document.getElementById('tat_table'));
a = document.createElement('table');
a.cellSpacing='1px';
a.cellPadding='2px';
a.style.position='absolute';
a.style.top = eval(curTop(actb_curr) + actb_curr.offsetHeight) + "px";
a.style.left = curLeft(actb_curr) + "px";
a.style.backgroundColor=actb_self.actb_bgColor;
a.id = 'tat_table';
if (actb_self.actb_mouse){
a.onmouseout= actb_table_unfocus;
a.onmouseover=actb_table_focus;
}
document.body.appendChild(a);
var i;
var first = true;
var j = 1;
if (actb_rangeu > 1){
r = a.insertRow(-1);
// Code Changed : BUG
r.style.backgroundColor = actb_self.actb_curractb_bgColor; //actb_self.actb_bgColor;
c = r.insertCell(-1);
c.style.color = actb_self.actb_textColor;
c.style.fontFamily = 'arial narrow';
c.style.fontSize = actb_self.actb_fSize;
c.align='center';
replaceHTML(c,'/\\');
if (actb_self.actb_mouse){
c.style.cursor = 'pointer';
c.onclick = actb_mouse_up;
}
}
for (i=0;i<actb_self.actb_keywords.length;i++){
if (actb_bool[i]){
if (j >= actb_rangeu && j <= actb_ranged){
r = a.insertRow(-1);
r.style.backgroundColor = actb_self.actb_bgColor;
r.id = 'tat_tr'+(j);
c = r.insertCell(-1);
c.style.color = actb_self.actb_textColor;
c.style.fontFamily = actb_self.actb_fFamily;
c.style.fontSize = actb_self.actb_fSize;
// code ADDED : for dispaly code and description
if (actb_keywordsDesc != null) {
// Get Code
var code = actb_parse(actb_self.actb_keywords[i])
// Get Description
var desc = actb_keywordsDesc[i];
c.innerHTML = actb_codedesc(code, desc);
}
else {
c.innerHTML = actb_parse(actb_self.actb_keywords[i]);
}
c.id = 'tat_td'+(j);
c.setAttribute('pos',j);
if (actb_self.actb_mouse){
c.style.cursor = 'pointer';
c.onclick=actb_mouseclick;
c.onmouseover = actb_table_highlight;
}
j++;
}else{
j++;
}
}
if (j > actb_ranged) break;
}
if (j-1 < actb_total){
r = a.insertRow(-1);
// Code Changed : BUG
r.style.backgroundColor = actb_self.actb_curractb_bgColor; //actb_self.actb_bgColor;
c = r.insertCell(-1);
c.style.color = actb_self.actb_textColor;
c.style.fontFamily = 'arial narrow';
c.style.fontSize = actb_self.actb_fSize;
c.align='center';
replaceHTML(c,'\\/');
if (actb_self.actb_mouse){
c.style.cursor = 'pointer';
c.onclick = actb_mouse_down;
}
}
// generate bar on right (i eme item/total item)
actb_generate_bar(a);
}
function actb_goup(){
if (!actb_display) return;
if (actb_pos == 1) return;
document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_bgColor;
actb_pos--;
if (actb_pos < actb_rangeu) actb_moveup();
document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_hColor;
if (actb_toid) clearTimeout(actb_toid);
if (actb_self.actb_timeOut > 0) actb_toid = setTimeout(function(){actb_mouse_on_list=0;actb_removedisp();},actb_self.actb_timeOut);
//code ADDED : refresh bar
actb_refresh_bar();
}
function actb_godown(){
if (!actb_display) return;
if (actb_pos == actb_total) return;
document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_bgColor;
actb_pos++;
if (actb_pos > actb_ranged) actb_movedown();
document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_hColor;
if (actb_toid) clearTimeout(actb_toid);
if (actb_self.actb_timeOut > 0) actb_toid = setTimeout(function(){actb_mouse_on_list=0;actb_removedisp();},actb_self.actb_timeOut);
//code ADDED : refresh bar
actb_refresh_bar();
}
function actb_movedown(){
actb_rangeu++;
actb_ranged++;
actb_remake();
}
function actb_moveup(){
actb_rangeu--;
actb_ranged--;
actb_remake();
}
/* Mouse */
function actb_mouse_down(){
document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_bgColor;
actb_pos++;
actb_movedown();
document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_hColor;
actb_curr.focus();
actb_mouse_on_list = 0;
if (actb_toid) clearTimeout(actb_toid);
if (actb_self.actb_timeOut > 0) actb_toid = setTimeout(function(){actb_mouse_on_list=0;actb_removedisp();},actb_self.actb_timeOut);
//code ADDED : refresh bar
actb_refresh_bar();
}
function actb_mouse_up(evt){
if (!evt) evt = event;
if (evt.stopPropagation){
evt.stopPropagation();
}else{
evt.cancelBubble = true;
}
document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_bgColor;
actb_pos--;
actb_moveup();
document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_hColor;
actb_curr.focus();
actb_mouse_on_list = 0;
if (actb_toid) clearTimeout(actb_toid);
if (actb_self.actb_timeOut > 0) actb_toid = setTimeout(function(){actb_mouse_on_list=0;actb_removedisp();},actb_self.actb_timeOut);
//code ADDED : refresh bar
actb_refresh_bar();
}
function actb_mouseclick(evt){
if (!evt) evt = event;
if (!actb_display) return;
actb_mouse_on_list = 0;
actb_pos = this.getAttribute('pos');
actb_penter();
}
function actb_table_focus(){
actb_mouse_on_list = 1;
}
function actb_table_unfocus(){
actb_mouse_on_list = 0;
if (actb_toid) clearTimeout(actb_toid);
if (actb_self.actb_timeOut > 0) actb_toid = setTimeout(function(){actb_mouse_on_list = 0;actb_removedisp();},actb_self.actb_timeOut);
}
function actb_table_highlight(){
actb_mouse_on_list = 1;
document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_bgColor;
actb_pos = this.getAttribute('pos');
while (actb_pos < actb_rangeu) actb_moveup();
while (actb_pos > actb_ranged) actb_movedown();
document.getElementById('tat_tr'+actb_pos).style.backgroundColor = actb_self.actb_hColor;
if (actb_toid) clearTimeout(actb_toid);
if (actb_self.actb_timeOut > 0) actb_toid = setTimeout(function(){actb_mouse_on_list = 0;actb_removedisp();},actb_self.actb_timeOut);
//code ADDED : refresh bar
actb_refresh_bar();
}
/* ---- */
function actb_insertword(a){
if (actb_self.actb_delimiter.length > 0){
str = '';
l=0;
for (i=0;i<actb_delimwords.length;i++){
if (actb_cdelimword == i){
str += a;
l = str.length;
}else{
str += actb_delimwords[i];
}
if (i != actb_delimwords.length - 1){
str += actb_delimchar[i];
}
}
actb_curr.value = str;
setCaret(actb_curr,l);
}else{
actb_curr.value = a;
}
actb_mouse_on_list = 0;
actb_removedisp();
}
function actb_penter(){
if (!actb_display) return;
actb_display = false;
var word = '';
var c = 0;
for (var i=0;i<=actb_self.actb_keywords.length;i++){
if (actb_bool[i]) c++;
if (c == actb_pos){
word = actb_self.actb_keywords[i];
break;
}
}
actb_insertword(word);
}
function actb_removedisp(){
if (actb_mouse_on_list==0){
actb_display = 0;
if (document.getElementById('tat_table')){ document.body.removeChild(document.getElementById('tat_table')); }
if (actb_toid) clearTimeout(actb_toid);
}
}
function actb_keypress(){
return !actb_caretmove;
}
function actb_checkkey(evt){
if (!evt) evt = event;
a = evt.keyCode;
caret_pos_start = getCaretStart(actb_curr);
actb_caretmove = 0;
switch (a){
case 38:
actb_goup();
actb_caretmove = 1;
return false;
break;
case 40:
actb_godown();
actb_caretmove = 1;
return false;
break;
case 13: case 9:
if (actb_display){
actb_caretmove = 1;
actb_penter();
return false;
}else{
return true;
}
break;
default:
setTimeout(function(){actb_tocomplete(a)},50);
break;
}
}
function actb_tocomplete(kc){
if (kc == 38 || kc == 40 || kc == 13) return;
var i;
if (actb_display){
var word = 0;
var c = 0;
for (var i=0;i<=actb_self.actb_keywords.length;i++){
if (actb_bool[i]) c++;
if (c == actb_pos){
word = i;
break;
}
}
actb_pre = word;
}else{ actb_pre = -1};
if (actb_curr.value == ''){
actb_mouse_on_list = 0;
actb_removedisp();
return;
}
if (actb_self.actb_delimiter.length > 0){
caret_pos_start = getCaretStart(actb_curr);
caret_pos_end = getCaretEnd(actb_curr);
delim_split = '';
for (i=0;i<actb_self.actb_delimiter.length;i++){
delim_split += actb_self.actb_delimiter[i];
}
delim_split = delim_split.addslashes();
delim_split_rx = new RegExp("(["+delim_split+"])");
c = 0;
actb_delimwords = new Array();
actb_delimwords[0] = '';
for (i=0,j=actb_curr.value.length;i<actb_curr.value.length;i++,j--){
if (actb_curr.value.substr(i,j).search(delim_split_rx) == 0){
ma = actb_curr.value.substr(i,j).match(delim_split_rx);
actb_delimchar[c] = ma[1];
c++;
actb_delimwords[c] = '';
}else{
actb_delimwords[c] += actb_curr.value.charAt(i);
}
}
var l = 0;
actb_cdelimword = -1;
for (i=0;i<actb_delimwords.length;i++){
if (caret_pos_end >= l && caret_pos_end <= l + actb_delimwords[i].length){
actb_cdelimword = i;
}
l+=actb_delimwords[i].length + 1;
}
var ot = actb_delimwords[actb_cdelimword].trim();
var t = actb_delimwords[actb_cdelimword].addslashes().trim();
}else{
var ot = actb_curr.value;
var t = actb_curr.value.addslashes();
}
if (ot.length == 0){
actb_mouse_on_list = 0;
actb_removedisp();
}
if (ot.length < actb_self.actb_startcheck) return this;
if (actb_self.actb_firstText){
var re = new RegExp("^" + t, "i");
}else{
var re = new RegExp(t, "i");
}
actb_total = 0;
actb_tomake = false;
actb_kwcount = 0;
for (i=0;i<actb_self.actb_keywords.length;i++){
actb_bool[i] = false;
if (re.test(actb_self.actb_keywords[i])){
actb_total++;
actb_bool[i] = true;
actb_kwcount++;
if (actb_pre == i) actb_tomake = true;
}
}
if (actb_toid) clearTimeout(actb_toid);
if (actb_self.actb_timeOut > 0) actb_toid = setTimeout(function(){actb_mouse_on_list = 0;actb_removedisp();},actb_self.actb_timeOut);
actb_generate();
}
return this;
}
A small bug found:
// code ADDED : function which generate bar on right (ieme item/total item)
function actb_generate_bar(a) {
// generate bar if row > 1 and actb_lim >0
if (actb_self.actb_lim >0) {
var nbRows = a.rows.length;
if (nbRows > 1) {
// Construct bar on right of table
bar = a.rows[0].insertCell(-1);
bar.id="actb_bar";
bar.style.fontSize = actb_self.actb_fSize;
bar.style.backgroundColor = "#DDEEFF";
bar.style.color = "red";
bar.style.fontWeight = "bold";
bar.rowSpan=nbRows;
bar.style.verticalAlign= "bottom";
bar.height="100%";
this.actb_bar = bar;
actb_refresh_bar();
}
my question was if the variables that define if the input text box will be limited to given options defined already is specific to input text box or it is defined per instance of actb Object
10x ahead,
BTW, is it function quickly will huge collection of options?
I'm not sure if I get your question but i believe you were asking if the variables for each actb object is unique to each definition. Well the answer is yes.
<br />
obj = new actb(document.getElementById('textbox_id'),customarray);<br />
obj.actb_mouse = false; // no mouse support<br />
obj2 = new actb(document.getElementById('textbox2_id'),customarray2);<br />
obj2.actb_startcheck = 2; // start actb only after 2nd character<br />
As above shows, you can have different settings for different textboxes. The first will have no mouse support whereas the second will have (default setting).
as for your 2nd question... well yes, the speed is pretty reasonable even for huge collection of options (more than 1000). Although by then there will be a noticable decrease in speed, but it will pass undecided for average users
I have defined two textboxes with separate lists and options, but it doesn't seem to work.. Both textboxes share the list and options of the last defined textbox.
Has some functionality changed when settings were made global?
And YES, the textboxes have different id's, and the arrays and objects has different names too, as in the example.
Testet on both Mozilla and IE with same result.