tcrosen/twitter-bootstrap-typeahead — pull request #30 by tgirardi (2012-12-04 01:27:47+00:00)
Title: Issue #19: added support for scrollbar on dropdown menu

Originally, using CSS, you could force the menu to have a max-height and use a scroll (overflow:auto or overflow-y:auto) to reach the list items that where outside the visual area. However, clicking on the scrollbar that could appear would not work (you could only scroll using the mouse wheel, trackpad gesture or similar). The reason was that any click on it would fire a blur event that would close the menu.

This commit solves this issue by making a difference between clicks on a list item (
) or clicks anywhere else inside the menu (including the scrollbar). The first case will produce the original behavior (item is selected and then the menu is closed). The second one will not select an item and will avoid the closing of the menu (also it will reposition the focus on the input element).

The second part of this enhancement is related with navigation using up and down arrows: now that we have a "hidden" area, we must assure that any selected item is kept away from that area by forcing the menu to scroll (vertically) accordingly.

In order to achieve this:

* When going up: prev() method now checks if the top border of the newly selectes
element is inside the visible area or not. If not, the menu is scrolled (using jQuery's scrollTop method) to the exact position of that top border (leaving the mentioned element fully visible).
* When going down: next() method does something similar to the previous case but taking in consideration the bottom border of the selected
element

It was also necessary to take care of the mouseenter event that could be triggered when we scroll programmatically (the mouse is not moved, but the elements behind the mouse - the menu items - do move because of the scrolling movement). The solution for that was setting a variable that tells the next mouseenter method invocation to avoid changing the active element, after prev() or next() is called (if the user moves the mouse after prev() or next() the mouseenter can start changing the active element again... this is done in order to avoid messing the expected behavior of mouseenter in cases where prev() or next() makes the menu scroll but the mouse never leaves the element it is currently over, which could happen for small scrolling distances).