Floyd
06-13-2003, 05:50 AM
I've got a bit of weirdness about an object's properties not being visible to any of its methods. The intention is to override IE's handling of keystrokes for <select> dropdowns so that it behaves more like Mozilla (so the code that follows is IE-specific); FYI, IE's behaviour is to take you to the first element in the selection whose first character matches the key you just hit, while Mozilla retains a memory of the last few keys you hit (so that you can type more than just one character of the selection). In the sample list below, hitting "JS" would in IE find you selecting "superguy", while in Mozilla you'd select "jsmith".
You'll note that the entire object has four (user-defined) properties and a method. The method itself is the actual event handler, while the properties supply the object with the "more than one thing at a time" memory that it needs to perform.
I have non-OO code that does work - it uses global variables instead of properties, the search function has to have the <select> object passed to it as a parameter, and the handler is specified in an "onkeyup" attribute, but it's otherwise the same code. I can fall back on that in a pinch, but I want to be using this behaviour multiple times on multiple pages, and encapsulating seems desirable.
<script type="text/javascript" language="javascript">
function TypistDropdown(select, usevalue)
{ this.select = select; // The <select> element this binds to.
this.usevalue = usevalue || false; // Search value or text?
this.elapsed = (new Date()).valueOf(); // # of milliseconds since last keystroke
this.buffer = ''; // The most recent keystrokes in this dropdown
};
TypistDropdown.prototype.search = function()
{ var key = String.fromCharCode(event.keyCode);
if(key<'A' || key>'Z') return false; // Nothing to do with us (XXX other character ranges?)
var right_now = (new Date()).valueOf();
if(right_now-this.elapsed > 500) // milliseconds (XXX configurable?)
this.buffer = ''; // Been so long - flush the buffer
this.buffer += key; // Add this keystroke to the buffer
this.elapsed = right_now; // Reset the timer
var buffer_length = this.buffer.length;
var select_length = this.select.options.length;
var option;
for(var i=0; i<select_length; i++)
{ option = this.select.options[j];
option = this.usevalue ? option.value : option.text;
option = option.substr(0,buffer_length).toUpperCase();
if(option==this.buffer) // We have a match
{ this.select.selectedIndex = j;
break;
}
}
document.getElementById('mybuffer').innerHTML = this.buffer;
return true;
};
</script>
.......
<SELECT name='username' id="username" size="4">
<OPTION value="alienface">alienface</option>
<OPTION value="barry">barry</option>
<OPTION value="fredh">fredh</option>
<OPTION value="fredt">fredt</option>
<OPTION value="jblair">jblair</option>
<OPTION value="jsmith">jsmith</option>
<OPTION value="ppolly">ppolly</option>
<OPTION value="superguy">superguy</option>
<OPTION value="ttt">ttt</option>
</select>
<script type="text/javascript" language="javascript">
var username_handler = new TypistDropdown(document.getElementById('username'));
document.getElementById('username').onkeyup = username_handler.search;
</script><span id='mybuffer'></span>
To make things clear right now, the event handling itself appears to work - that is to say, key gets the value it should, and so forth. Problems begin the moment I start using the object's properties (select, usevalue and the rest). They are all (according to judicious alert()s dotted about) undefined. I've tried various alternate idioms ("this.buffer=''; this.search = function(){...}", etc.) but all fail in the same way: "right_now-this.elapsed" is meaningless because "this.elapsed" is undefined (and before you ask, yes I did check to see what this.buffer and other properties contained, including a few ("this.foo") created for the purpose; they were all undefined in the scope of the search method).
Judging from other Javascript code I've read all about the place, I really can't see what's so different about my code that makes it not work. STFW, RTFM, UTSL - I can't see the difference. If I've missed a thread in my searching that does deal with this, I'd appreciate it being pointed out. Ditto if I'm missing some much more elegant solution.
Oh yeah, mybuffer is a debugging instrument - its function should be obvious (don't see why having it would make a difference: and, surprisingly, taking it out doesn't magically make things work). (Anyone suspect I'm getting just a little peeved?)
You'll note that the entire object has four (user-defined) properties and a method. The method itself is the actual event handler, while the properties supply the object with the "more than one thing at a time" memory that it needs to perform.
I have non-OO code that does work - it uses global variables instead of properties, the search function has to have the <select> object passed to it as a parameter, and the handler is specified in an "onkeyup" attribute, but it's otherwise the same code. I can fall back on that in a pinch, but I want to be using this behaviour multiple times on multiple pages, and encapsulating seems desirable.
<script type="text/javascript" language="javascript">
function TypistDropdown(select, usevalue)
{ this.select = select; // The <select> element this binds to.
this.usevalue = usevalue || false; // Search value or text?
this.elapsed = (new Date()).valueOf(); // # of milliseconds since last keystroke
this.buffer = ''; // The most recent keystrokes in this dropdown
};
TypistDropdown.prototype.search = function()
{ var key = String.fromCharCode(event.keyCode);
if(key<'A' || key>'Z') return false; // Nothing to do with us (XXX other character ranges?)
var right_now = (new Date()).valueOf();
if(right_now-this.elapsed > 500) // milliseconds (XXX configurable?)
this.buffer = ''; // Been so long - flush the buffer
this.buffer += key; // Add this keystroke to the buffer
this.elapsed = right_now; // Reset the timer
var buffer_length = this.buffer.length;
var select_length = this.select.options.length;
var option;
for(var i=0; i<select_length; i++)
{ option = this.select.options[j];
option = this.usevalue ? option.value : option.text;
option = option.substr(0,buffer_length).toUpperCase();
if(option==this.buffer) // We have a match
{ this.select.selectedIndex = j;
break;
}
}
document.getElementById('mybuffer').innerHTML = this.buffer;
return true;
};
</script>
.......
<SELECT name='username' id="username" size="4">
<OPTION value="alienface">alienface</option>
<OPTION value="barry">barry</option>
<OPTION value="fredh">fredh</option>
<OPTION value="fredt">fredt</option>
<OPTION value="jblair">jblair</option>
<OPTION value="jsmith">jsmith</option>
<OPTION value="ppolly">ppolly</option>
<OPTION value="superguy">superguy</option>
<OPTION value="ttt">ttt</option>
</select>
<script type="text/javascript" language="javascript">
var username_handler = new TypistDropdown(document.getElementById('username'));
document.getElementById('username').onkeyup = username_handler.search;
</script><span id='mybuffer'></span>
To make things clear right now, the event handling itself appears to work - that is to say, key gets the value it should, and so forth. Problems begin the moment I start using the object's properties (select, usevalue and the rest). They are all (according to judicious alert()s dotted about) undefined. I've tried various alternate idioms ("this.buffer=''; this.search = function(){...}", etc.) but all fail in the same way: "right_now-this.elapsed" is meaningless because "this.elapsed" is undefined (and before you ask, yes I did check to see what this.buffer and other properties contained, including a few ("this.foo") created for the purpose; they were all undefined in the scope of the search method).
Judging from other Javascript code I've read all about the place, I really can't see what's so different about my code that makes it not work. STFW, RTFM, UTSL - I can't see the difference. If I've missed a thread in my searching that does deal with this, I'd appreciate it being pointed out. Ditto if I'm missing some much more elegant solution.
Oh yeah, mybuffer is a debugging instrument - its function should be obvious (don't see why having it would make a difference: and, surprisingly, taking it out doesn't magically make things work). (Anyone suspect I'm getting just a little peeved?)