Enhance autocomplete feature
kkaefer - March 6, 2007 - 14:55
| Project: | Drupal |
| Version: | 7.x-dev |
| Component: | javascript |
| Category: | feature request |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | patch (code needs work) |
Description
The attached patch enhances the autocomplete list in serveral ways:
- It improves the code quality of the
autocomplete.jsand moves all JS objects to theDrupal.autocompletenamespace. - The cursor is now moved to the end of the textfield in Safari when a user selects an autocomplete item.
- It allows modules to provide more than just one string for an autocomplete entry, allowing “rich” items. For example, you can use bold formatting, links and even images (e.g. avatars when autocompleting users). This allows modules to give more context when selecting an item. E.g. when a node should be selected, it’s often hard to tell from the title of the node if it’s the correct one. Additional information are often useful.
Also, there is a new theme functiontheme_autocomplete_itemthat allows themes to modify the structure of an autocomplete item. - There is a new field
infoin the autocomplete JSON object which can contain general information about the autocompletion. In the patch it is for example used to display the user who many items in addition to the 10 displayed were found. This is a freeform HTML field that is not selectable (as opposed to regular items).
| Attachment | Size |
|---|---|
| autocomplete_3_0.patch | 18.92 KB |

#1
It allows modules to provide more than just one string for an autocomplete entry
Isn't this possible already ?
the autocomplete widget for CCK nodereference fields can currently be set to return stylable Views-generated HTML.
#2
This looks good, thanks for giving autocomplete some needed attention. I've given the code only a quick initial review. The namespace introduction is a good simple improvement. I like the move to pass autocomplete data in settings rather than the current awkward encoding in a form field.
There are various other issues with the autocomplete implementation. Likely they should be left for separate patches. I'll mention them, though, in case you're inspired to tackle one or more along with these improvements.
_element_info(). Here, like many other places (notably our form element theme functions), we've rather crudely hacked js behaviours into core. The yardstick should be, can this same approach be applied by contrib modules (where we don't have the option of hacking core)? If not, then we're not doing it correctly. In this case, we should look at registering a #process callback to the textfield form element insystem_elements()to handle the processing.Drupal.ACDB.prototype.searchfunction. It would be nice to leave an opening for contrib behaviours to respond to a 'no matches' return.A comment and question or two:
exit();at the end ofdrupal_autcomplete().this.popup =to a jquery result set is an interesting approach. The subsequentthis.popup[0].ownerseemed awkward the first time I looked at it, but I see the power of returning a jquery reference rather than a direct object reference.$(this.input.form).submit(Drupal.autocomplete.submit);Why submit the autocomplete when the form is being submitted?#3
Does core take advantages of any of the new features? Could it take advantage of them? It's always nice to set good examples.
Update: looks like the user and taxonomy code takes advantage of this. Care to share a screenshot? It would save many of us time to setup such a large list of taxonomy terms. :-)
The taxonomy and user module changes needs more work. It's not a good idea to use the pager, and then to read out internal pager variables by setting them global. That's a hack, IMO.
This patch has great potential, but needs a little bit more work. ;)
#4
Yes, this is possible at the moment, but not officially supported. The implementation for this is not really bullet-proof at the moment. Currently, it’s done using
.html('<div>'+ matches[key] +'</div>')withmatches[key]being the “string” returned from autocomplete. However, I could imagine that there are some weird combinations of HTML tags that confuse jQuery and break the autocompletion. Therefore, I changed that to the “correcter” way.html(matches.matches[key]). Using HTML in the autocomplete string is now recommended and “officially allowed”.Yeah, forgot to mention that. I think killes once had some issues with differing IDs in the hidden form field and the actual autocomplete field.
nedjo’s first point is so true: Currently, we add the autocomplete JS files in a theme function instead of adding them programmatically somewhere during the build process. The second point is also a logical step.
Drupal.autocomplete.fieldis completely independent ofDrupal.autocomplete.handlerand can be used separately. In fact, I’ve even used to do non-AJAX autocompletion.We had
exit;calls there before, but I removed them on purpose. Just exiting in the middle of a script makes it impossible for other modules do perform actions inhook_exit(). And if everything is correctly implemented (like it is atm), everything works fine and we don’t get JavaScript errors. If we do, we made something wrong (e.g. not checking for the Content-type when outputting something). So this can be understood as a kind of “indicator” for the exitting system working correctly.You misunderstood something here. There is no submit handler called in this line. However, a new submit handler (the function
Drupal.autocomplete.submit) is added as submit handler to the current form. This submit function (which has been present before) checks if the autocomplete popup is open. So when the user hits enter for the first time, the popup closed instead of the form being submitted right away.Yes, it could be considered a hack and could be refactored. Any suggestions?
#5
It has always been possible to use HTML in the autocomplete matches. There was nothing hackish or unofficial about this, and this is why check_plain() was needed for autocomplete matches. I don't see what the presence of a wrapper div would do to change that. It just ensures the items stack vertically and automatically have a block-level enclosing. PS:
<code>tags on Drupal.org escape for you.While I applaud moving towards clean settings rather than hidden form items, and cleaning up the JS code, I'm not sure about some of the other bits though:
form_autocomplete()is a weird function. It adds the JS headers, but not the CSS class... so it is useless for re-use. Either rename it and document it as an internal helper, or just move it back in. It's only two lines after all.I also think we should do more useful things with these in core, for example by displaying avatars in user results and displaying the number of nodes that have a certain tag in brackets (and grayed out) behind the tag name.
#6
This looks very interesting, as I'm currently dealing with dynamically altered autocomplete fields. By using a global storage (
Drupal.autocomplete.handlers) it'd be finally possible to alter the autocomplete uri on the fly, ie. extend it with a dynamic value from another form field.The only question that arises for me is: could the code by changed to store the handlers by id instead of uri? That is, change
Drupal.autocomplete.attach()toif (!handlers[id]) {handlers[id] = new Drupal.autocomplete.handler(url);
}
instead of assigning to handlers[uri]? I'm primarily asking if this would have any negative consequences. The use should be obvious: the autocomplete uri could be much easier updated, because I can access the storage by a static id instead of an ever changing uri.
#7
Couldn't we even go beyond the above said and make the two central handlers dealing with the autocomplete results –
Drupal.autocomplete.field.found()andDrupal.autocomplete.field.select()– user-definable? Placing the handlers in the very same Drupal.settings object and falling back to the default if nothing has been overridden would allow a 3rd party module to reuse 90+% of the existing code. It would just have to provide said functions and set them via a new forms api element#autocomplete_handler, for example. Of course, refactoring common stuff out of Drupal.autocomplete.field.found() would make such "add-ons" even shorter, probably leaving only the block commented// Prepare matchesin.#8
Any updates?
#9
Please update or re-roll the patch..
I'll give this a proper review when the code is updated or the patch is rerolled.
(While i'm not a jQuery guru, I can not test the patch right now)
#10
@Steven:
theme_autocomplete_item()anymore.form_autocomplete()back into every single autocomplete function.@smk-ka: The reason we use url here is that we can have multiple autocomplete fields with the same url per page. Now, if you type “ab” in one field, the results are cached. If you type “ab” in the other field with the same AJAX callback but another ID, it requeries the server instead of obtaining the results from the cache. Do you have a use case where you want to change autocomplete callbacks? Wouldn’t it be easier to negiocate that on the server side?
By the way, it is already possible to override every single autocomplete function: Just create a new object and overwrite the function (yes, JavaScript is that flexible!):
var x = new Drupal.autocomplete.field($('#' + id)[0], handlers[url]);x.search = function(searchString) {
// Do your stuff here
this.owner.found(...);
}
There are still no avatars in user autocompletion as I think that the popup could grow too big (10 * 85 pixels = 850 pixels at least). Maybe we can look into resizing them, but afaik, we don’t have small avatars in core as of now.
Now, the title is not bold anymore in its entirety. Instead, the parts of the text the user entered is highlighted. If the user enters “ue”, the last two characters of “Blue” are now bold.
Also, it is now possible to search for any parts of user names instead of just from the beginning. Searching for “kaefer” will now also return “kkaefer”. with all but the first character highlighted.
#11
No longer applies. This is usability so leaving in D6.
#12
I'd just like to add on and say that this is a necessary update to autocomplete functionality.
There are countless situations like http://drupal.org/node/52568 where you would want the autocomplete display value (even in the textfield) to be different than the returned value from the form.
This will happen anytime there is a non-unique display item (like node title or a user's name) and a non-displayable unique ID (like uid or nid). It presents information that is useless to the user. While it may be acceptable for entering such data, going back and editing a field like that means you just see a meaningless number.
I will be trying this code but it probably still needs work...
The user avatar problem can be solved with imagecache. We can create a module for enhanced user autocomplete with a dependency or optional extension if imagecache is enabled.
#13
Moving feature requests to D7 queue.
#14
Just bumping, because we had a discussion at FosDem about autocomplete in core, what people are looking for is something like this
http://jquery.bassistance.de/autocomplete/ ans since we're using jquery 1.2.3, I guess it can't be that hard to do :p
For the moment I don't have the time to do this myself, but ...
Cheers,
Peter
#15
Subscribing.
#16
I'm gonna bring this up at MIT Codesprint after Drupalcon. I guess we'll see if we do it!
#17
subscribing...
#18
Subscribing...
I had conversations with several people about this in Boston. I've been working on an add-on module for a Drupal 5x client that adds the unique key behavior described above. It's not currently a one-size-fits-all solution. In addition, I've done some client-focused autocomplete work for taxonomy that routes through a theme function. In Boston we updated my 5x module to a proof of concept for D6 but it needs a JS overhaul.
So I think all of these things are possible. The problem I anticipate with the unique key situation is usability. What happens for screen readers or JS-disabled situations? I propose gathering the possible responses with a user-supplied function that returns a structured array. Then upon validation error (indicating that JS may not have been enabled) we display a select list of the possible matches. Some modules like nodequeue append the unique ID to the displayed string like:
Node Title [nid0234]
This works to a point, but no human being should be expected to conform to this format.
Quicksketch suggested gathering the autocomplete parameters using the JS settings array. I think this is a great idea. He also encouraged me to work on the HEAD branch rather than a contrib module for D6.
I'd also like to see a client-side API for clearing the autocomplete cache or manually adding items. This is something that I worked around in my 5x solution.
#19
sub'ing
#20
subscribing, and second #14