IDEATION OF THE CODE
|
|
What the script does and how it got envisaged
|
Time ago I read online an extremely cool code for producing autocompletion hints for a typing user. That code was (is) a very good one (indeed), and the file with its documentation was called Make Life Easy With Autocomplete Textboxes, by Nicholas C. Zakas.
I found that script so well done that i felt I had nothing to add to it.
Yet recently I noticed a new yahoo.com mail feature, namely a drop down menu that appears upon typing a mail address, drawing potential auto completion data from more than just the mere email addresses agenda records, but also from the agenda nickname and name records.
 A Tom Wesselmann painting |
Though I do not implement here a version where a relational link (for that it is) among more than just one array of auto completion suggestions is involved, the reason I devised this script is exactly to allow for hint menus that can be combined together from a plurality of input arrays; therefore the script is potentially ready to lend itself to that usage too.
Anyway what truly interested me was to introduce the power of a binary search in the construction of an auto complete drop down menu.
I developed long ago a binary search tool (do not refer to the so called " multiple binary search" that is in that file too, but to the "standard" binary search code featured after the "multiple" one), and that binary search is one of the scripts, slightly rearranged, that entered this class.
Anyway a binary search approach can really improve an auto completion tool in case it has to draw from an input array of possible completions of, say, thousands and thousands of possibilities (an agenda with 1000 entries is not inconceivable, especially at a time when Google plans to provide 1 giga of storage to each email account).
What you need prior to this script is:
- An array listing all the terms that you consider plausible completions for the type of most common texts you are expecting.
- This array must absolutely be (this is imperative, this is mandatory, this is paramount) sorted, that is: arranged alphabetically.
To sort properly an array you can use this snippet, whereas arrayX is the placeholder name of your array:
arrayX.sort(
function (a,b){
if(a.toLowerCase() < b.toLowerCase()){return -1;}
else if (a.toLowerCase() == b.toLowerCase()){return 0;}
else if(a.toLowerCase() > b.toLowerCase()){return 1;}
}
);
Like that, the only thing you must change in that snippet is the arrayXplaceholder.
By the way if your array to be sorted is an array whose each entry is an array itself, and you want to be sure that the whole is sorted out only taking in as comparison parameter one specific index of each branched array, the snippet is:
var sortIndex=;
arrayX.sort(
function (a,b){
if(a[sortIndex].toLowerCase() < b[sortIndex].toLowerCase()){return -1;}
else if (a[sortIndex].toLowerCase() == b[sortIndex].toLowerCase()){return 0;}
else if(a[sortIndex].toLowerCase() > b[sortIndex].toLowerCase()){return 1;}
}
);
Once again, there you change only the arrayXplaceholder and you can custom the number zero assigned to the variable sortIndex.
In our examples here I will use for auto-completion an array of nation names imagining for illustration purposes that the form field(s) mostly needs to be filled with nation names; the array is already sorted out, and spans throughout over 240 entries thus providing a non entirely trivial example:
THE CODES
|
|
Codes and Initialization
|
First of all the codes, then in the next section I will explain to you how to use them (extremely easy) and I will document better the inner workings of the class.
 A Allan Banks painting |
HOW IT WORKS
|
|
How to initialize the script, what it does
|
Let me repeat, the prerequisite is that you have in your script an array of strings meant for your auto completions, and that it is sorted properly, whereas by properly it means that your sorting javascript routine must have as its argument one of the anonymous functions I suggested in the snippets above to sort arrays. Such argument is necessary for otherwise the default sorting is not a natural case insensitive sorting. To understand it better let me quote:
«If you sort (8, 9, 10, 11, 12), how do you want them to be output? "In the order you've just listed, Graham", you'll probably say. But if they're strings and you sort them, then you'll get the order 10, 11, 12, 8, 9 output if you just use a default sort, because the character "1" comes before the character "8" in the alphabet.
Original
0 .. 12 Drummers Drumming
1 .. 7 Swans a'Swimming
2 .. 11 Pipers Piping
3 .. 9 Ladies Dancing
4 .. 10 Lords a'Leaping
5 .. 8 Maid a'Milking
Default Sort
0 .. 10 Lords a'Leaping
1 .. 11 Pipers Piping
2 .. 12 Drummers Drumming
3 .. 7 Swans a'Swimming
4 .. 8 Maid a'Milking
5 .. 9 Ladies Dancing
Natural Sort
1 .. 7 Swans a'Swimming
5 .. 8 Maid a'Milking
3 .. 9 Ladies Dancing
4 .. 10 Lords a'Leaping
2 .. 11 Pipers Piping
0 .. 12 Drummers Drumming
» [from: PHP and natural sorting]
In javascript you achieve the natural sorting by passing to the sort method an anonymous function in the way I showed in the snippets above.
Then the initialization of your menus is very simple.
Provided you have a form input field whatever, let's say in our case a textarea, you wrap it within a tag, preferably a SPAN tag which has assigned an id:
As far as html is concerned, that's truly all!
If you then want to add properties to your form tag, that's up to you (like for instance cols and rows to the textarea tag).
Anyway the reason you need such wrapper (the SPAN tag) and you need to assign an id to it (in our case id=" foo") is that the script will append to these form fields a layer, and no layer can be appended if the field is not composed by a set of two tags, the opening one and the closing one. Not all form fields meet this requirement, for instance <INPUT> tags do not have a closing tag, and anyway a menu cannot be appended inside a textarea. So a wrapper tag with an id is needed to dispatch the menu properly.
After you have written down your form field and its wrapper with an id, you can add after it ( not before it!) a script where you initialize an instance of our class (the name of the class is ).
The variable name initialized as such instance must be the same as the id assigned to the wrapper, and you pass at least two arguments:
- A String carrying the id once again
- Your sorted array
So it all boils down to this simple thing:
<span id="" style="width:300"><textarea></textarea></span>
<script>
var =new completion("", your_SORTED_array);
</script>
I strongly recommend to you to set also a style property in the wrapper tag and to determine in it its width. Since the tag is a wrapper, be sure such width declaration fully accomodates the wrapped form field - a bit of excess won't cause problems but a width less than the contained form field may result in drop down auto completion menus a bit eccentrically placed.
As you see it is extremely simple and all you need to pay care of is that the placeholder name foo is repeated in as many as three locations.
I now describe the full range of arguments you can pass to the constructor so to achieve different behaviours.
- id: the first argument is mandatory, a String with the id which must be the same as the initialized variable name.
The script will append a menu to such tag identified by such id, and will assign to the latter newly appended menu field an id of its own which will be
id+""
- array: mandatory, your sorted array.
- progressive: though optional; I suggest to always pass it as number 1.
Defaults to zero. The default behaviour is that when picked an auto completion option, the whole contents of the form field is replaced with it, and that only the text from the beginning of the form field till its end is considered.
If you pass it as number 1, only the last word in the typing will be considered and also replaced upon clicking an auto completion suggestion. This makes your menus much more dynamical.
This behaviour is to my eyes the most consistent one.
Also, arranging the script so that it would have suggested to you words accordingly to where you place the cursor could have resulted being extremely annoying and useless, for it would have suggested auto completions also if you would place your mouse cursor in the middle of a word, and anyway you would have kept seeing suggestions that you need not popping out wherever you place the cursor.
You can test these two different progressive behaviours in the test form further on.
- mouseOver: optional, defaults to zero. If passed as number 1, it will enact a behaviour such that whenever the mouse is placed on the form field, the menu, if some text is present in the field, reappears (whereas by default it appears only upon typing) with auto completion suggestions (if any) for the last word in the building within the menu.
- height: optional, defaults to 200; it is the max height you want your suggestion menu must have. If the height of the contents exceeds the whole height, a scrollbar will be provided.
The script will assign a few class names to the menu, so that you can affect them via css:
- menuWrapper is the css class name assigned to the whole menu(s) (case sensitive).
- menu is the css class name assigned to the menu(s) single options.
- closeMenu is the css class name assigned to a tiny text on top of each menu where it is written: "close"
I may suggest to you as a starting set of these classes the following css rule declarations for your default auto completion menus, rules that of course you can custom:
- arrayCheckThisIndex: optional. If your input sorted array is a matrix, you must pass this as the index of each matrix entry which hosts the auto completion string.
The class has only one public method, named . You pass to it two arguments, the css property of the menu you want to change, then the value. It is immaterial whether the property is passed in the css notation or in the javascript notation: you do not worry about that, the script will look after that:
foo.set("height", 500);
Note: the script will generate, to help itself with its internal workings, a window scope array named: autocompleters.
This array will store a few properties (included your input sorted array, but by reference) because it is necessary to have globally defined a few class parameters that the event handlers enabled by the script need (an event can not rely any longer on scripting class references made by the keyword this, thence the need of a global scope structure that can store a few details).
Be sure no other variable with such name ( autocompleters) may overwrite that name in your script, ok?
Remember, initialize your instance after the html tags, and have a sorted array ready.
Known Issues: the script works on IE5+, Netscape 5+, Mozilla, Opera. ON Mozilla and Netscape 5 and above, if you switch onto the drop down menu too quickly with your mouse the menu may disappear (apparently a Netscape "sluggish" thing): it would reappear only upon typing again (no errors get generated, obviously: I do not post scripts with popping up errors).
THE TEST FORM
|
|
Try it
|
Type In Below
-progressive (it's the best solution)-
var foo = new completion('foo', array, 1);
Type In Below
-not progressive-
var foo2 = new completion('foo2', array);
Type In Below
-progressive and mouseOver-
var foo3 = new completion('foo3', array, 1, 1);
 A Timothy Tyler painting, The Juggler It is like playing with scripts and pages, isn't it? |
|