autocomplete-list.js revision 766ecb8023c2374bba052ae9e11d25c5c5e8305b
3f3aa287185afb5d48d7ef0717054a154c372dc9Adam Moore * Traditional autocomplete dropdown list widget, just like Mom used to make.
3f3aa287185afb5d48d7ef0717054a154c372dc9Adam Moore * @module autocomplete
3f3aa287185afb5d48d7ef0717054a154c372dc9Adam Moore * @submodule autocomplete-list
3f3aa287185afb5d48d7ef0717054a154c372dc9Adam Moore * @class AutoCompleteList
d408aa66c7199d6b6a133c20c2116414dc70fa0aAdam Moore * @extends Widget
73cf5b20418beae941f34ec39a8d87035ae01711Luke Smith * @uses AutoCompleteBase
73cf5b20418beae941f34ec39a8d87035ae01711Luke Smith * @uses WidgetPosition
73cf5b20418beae941f34ec39a8d87035ae01711Luke Smith * @uses WidgetPositionAlign
030b855bbf1937a46e1e2b88025d61e72a205469Luke Smith * @uses WidgetStack
030b855bbf1937a46e1e2b88025d61e72a205469Luke Smith * @constructor
73cf5b20418beae941f34ec39a8d87035ae01711Luke Smith * @param {Object} config Configuration object.
fb83a09fe023a741781ee955f4e9538d3cbe21a2Luke Smith // keyCode constants.
fb83a09fe023a741781ee955f4e9538d3cbe21a2Luke Smith // String shorthand.
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith // Event names.
680f13616a493c7bf3a794982e07d10abd9763b3Luke SmithList = Y.Base.create('autocompleteList', Y.Widget, [
f60d4516da25663a6679c02654d8c2da2701657bLuke Smith // -- Prototype Properties -------------------------------------------------
73cf5b20418beae941f34ec39a8d87035ae01711Luke Smith // -- Lifecycle Prototype Methods ------------------------------------------
73cf5b20418beae941f34ec39a8d87035ae01711Luke Smith initializer: function () {
030b855bbf1937a46e1e2b88025d61e72a205469Luke Smith * Fires when an autocomplete suggestion is selected from the list by
d9462785fbdde2766d901cb36d19c9d6810c7954Ryan Grove * a keyboard action or mouse click.
030b855bbf1937a46e1e2b88025d61e72a205469Luke Smith * @event select
030b855bbf1937a46e1e2b88025d61e72a205469Luke Smith * @param {EventFacade} e Event facade with the following additional
030b855bbf1937a46e1e2b88025d61e72a205469Luke Smith * properties:
030b855bbf1937a46e1e2b88025d61e72a205469Luke Smith * <dt>result (Object)</dt>
030b855bbf1937a46e1e2b88025d61e72a205469Luke Smith * AutoComplete result object.
030b855bbf1937a46e1e2b88025d61e72a205469Luke Smith * @preventable _defResultsFn
030b855bbf1937a46e1e2b88025d61e72a205469Luke Smith // Cache commonly used classnames and selectors for performance.
030b855bbf1937a46e1e2b88025d61e72a205469Luke Smith this[_CLASS_ITEM_ACTIVE] = this.getClassName(ITEM, 'active');
030b855bbf1937a46e1e2b88025d61e72a205469Luke Smith this[_CLASS_ITEM_HOVER] = this.getClassName(ITEM, 'hover');
73cf5b20418beae941f34ec39a8d87035ae01711Luke Smith this.set(WIDTH, this._inputNode.get('offsetWidth'));
73cf5b20418beae941f34ec39a8d87035ae01711Luke Smith destructor: function () {
73cf5b20418beae941f34ec39a8d87035ae01711Luke Smith bindUI: function () {
73cf5b20418beae941f34ec39a8d87035ae01711Luke Smith renderUI: function () {
73cf5b20418beae941f34ec39a8d87035ae01711Luke Smith // See http://www.w3.org/WAI/PF/aria/roles#combobox for ARIA details.
7a925457f765fe5ea2507b4629476fa3e100e4eeTodd Kloots this._contentBox = this.get('contentBox').set('role', 'listbox');
fb83a09fe023a741781ee955f4e9538d3cbe21a2Luke Smith this._inputNode.addClass(this.getClassName('input')).setAttrs({
73cf5b20418beae941f34ec39a8d87035ae01711Luke Smith syncUI: function () {
7a925457f765fe5ea2507b4629476fa3e100e4eeTodd Kloots // -- Public Prototype Methods ---------------------------------------------
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith * Hides the list.
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith * @method hide
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith * @chainable
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith hide: function () {
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith * Selects the specified <i>itemNode</i>, or the current
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith * <code>activeItem</code> if <i>itemNode</i> is not specified.
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith * @method selectItem
7b4d1363155303b5bfb852e5639b851bbd4dc255Luke Smith * @param {Node} itemNode (optional) Item node to select.
7b4d1363155303b5bfb852e5639b851bbd4dc255Luke Smith * @chainable
7a925457f765fe5ea2507b4629476fa3e100e4eeTodd Kloots return this;
669975fc1822c49f2f84c92ac2b7809df46b1093Luke Smith * Shows the list.
669975fc1822c49f2f84c92ac2b7809df46b1093Luke Smith * @method show
0c4bb3413c8172f27fcebdf7242f5798d026064bLuke Smith * @chainable
14017741ef334485c65013d129608513161db7c2Luke Smith show: function () {
14017741ef334485c65013d129608513161db7c2Luke Smith // -- Protected Prototype Methods ------------------------------------------
680f13616a493c7bf3a794982e07d10abd9763b3Luke Smith * Activates the next item after the currently active item. If there is no
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith * next item and the <code>circular</code> attribute is <code>true</code>,
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith * the first item in the list will be activated.
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith * @method _activateNextItem
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith * @protected
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith // Get the next item. If there isn't a next item, circle back around
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith // and get the first item.
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith (this.get(CIRCULAR) && item.get('parentNode').one(selector));
fb83a09fe023a741781ee955f4e9538d3cbe21a2Luke Smith return this;
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith * Activates the item previous to the currently active item. If there is no
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith * previous item and the <code>circular</code> attribute is
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith * <code>true</code>, the last item in the list will be activated.
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith * @method _activatePrevItem
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith * @protected
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith // Get the previous item. If there isn't a previous item, circle
10d8bafc5c24f3a4285cf6060a1935ba5cfc4b85Luke Smith // back around and get the last item.
fb83a09fe023a741781ee955f4e9538d3cbe21a2Luke Smith (this.get(CIRCULAR) && item.get('parentNode').one(selector + ':last-child'));
669975fc1822c49f2f84c92ac2b7809df46b1093Luke Smith return this;
fb83a09fe023a741781ee955f4e9538d3cbe21a2Luke Smith * Appends the specified result <i>items</i> to the list inside a new item
fb83a09fe023a741781ee955f4e9538d3cbe21a2Luke Smith * @method _add
fb83a09fe023a741781ee955f4e9538d3cbe21a2Luke Smith * @param {Array|Node|HTMLElement|String} items Result item or array of
669975fc1822c49f2f84c92ac2b7809df46b1093Luke Smith * result items.
3e72e854188ef0c1927857102f15b449dc598fafLuke Smith * @returns {NodeList} Added nodes.
3e72e854188ef0c1927857102f15b449dc598fafLuke Smith * @protected
3e72e854188ef0c1927857102f15b449dc598fafLuke Smith YArray.each(Y.Lang.isArray(items) ? items : [items], function (item) {
3e72e854188ef0c1927857102f15b449dc598fafLuke Smith itemNodes.push(this._createItemNode(item.display).setData('result', item));
3e72e854188ef0c1927857102f15b449dc598fafLuke Smith * Binds <code>inputNode</code> events, in addition to those already bound
669975fc1822c49f2f84c92ac2b7809df46b1093Luke Smith * by <code>AutoCompleteBase</code>'s public <code>bindInput()</code>
669975fc1822c49f2f84c92ac2b7809df46b1093Luke Smith * @method _bindInput
3e72e854188ef0c1927857102f15b449dc598fafLuke Smith * @protected
3e72e854188ef0c1927857102f15b449dc598fafLuke Smith _bindInput: function () {
669975fc1822c49f2f84c92ac2b7809df46b1093Luke Smith // Call AutoCompleteBase's bind method first.
14017741ef334485c65013d129608513161db7c2Luke Smith inputNode.on(Y.UA.gecko ? 'keypress' : 'keydown', this._onInputKey, this)
fb83a09fe023a741781ee955f4e9538d3cbe21a2Luke Smith * Binds list events.
fb83a09fe023a741781ee955f4e9538d3cbe21a2Luke Smith * @method _bindList
fb83a09fe023a741781ee955f4e9538d3cbe21a2Luke Smith * @protected
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore _bindList: function () {
67d8986c26b16b1d9ea6e5b62e753c55af9a4f52Todd Kloots this.after('mouseover', this._afterMouseOver, this),
7b4d1363155303b5bfb852e5639b851bbd4dc255Luke Smith this.after('mouseout', this._afterMouseOut, this),
7b4d1363155303b5bfb852e5639b851bbd4dc255Luke Smith this.after('activeItemChange', this._afterActiveItemChange, this),
67d8986c26b16b1d9ea6e5b62e753c55af9a4f52Todd Kloots this.after('hoveredItemChange', this._afterHoveredItemChange, this),
67d8986c26b16b1d9ea6e5b62e753c55af9a4f52Todd Kloots this.after('resultsChange', this._afterResultsChange, this),
67d8986c26b16b1d9ea6e5b62e753c55af9a4f52Todd Kloots this.after('visibleChange', this._afterVisibleChange, this),
7b4d1363155303b5bfb852e5639b851bbd4dc255Luke Smith this._contentBox.delegate('click', this._onItemClick, this[_SELECTOR_ITEM], this)
7b4d1363155303b5bfb852e5639b851bbd4dc255Luke Smith * Clears the contents of the tray.
7b4d1363155303b5bfb852e5639b851bbd4dc255Luke Smith * @method _clear
7b4d1363155303b5bfb852e5639b851bbd4dc255Luke Smith * @protected
67d8986c26b16b1d9ea6e5b62e753c55af9a4f52Todd Kloots _clear: function () {
67d8986c26b16b1d9ea6e5b62e753c55af9a4f52Todd Kloots * Creates an item node with the specified <i>content</i>.
67d8986c26b16b1d9ea6e5b62e753c55af9a4f52Todd Kloots * @method _createItemNode
67d8986c26b16b1d9ea6e5b62e753c55af9a4f52Todd Kloots * @param {Node|HTMLElement|String} content
67d8986c26b16b1d9ea6e5b62e753c55af9a4f52Todd Kloots * @protected
7b4d1363155303b5bfb852e5639b851bbd4dc255Luke Smith * @returns {Node} Item node.
var items;
if (!results) {
this._clear();
if (!visible) {
_afterActiveItemChange: function (e) {
if (e.prevVal) {
if (e.newVal) {
_afterHoveredItemChange: function (e) {
if (e.prevVal) {
if (e.newVal) {
_afterMouseOver: function (e) {
this._mouseOverList = true;
if (itemNode) {
_afterMouseOut: function () {
this._mouseOverList = false;
_afterResultsChange: function (e) {
_afterVisibleChange: function (e) {
_onInputBlur: function (e) {
this.hide();
_onInputKey: function (e) {
switch (keyCode) {
case KEY_DOWN:
this._activateNextItem();
case KEY_ENTER:
this.selectItem();
case KEY_ESC:
this.hide();
case KEY_UP:
this._activatePrevItem();
e.preventDefault();
_onItemClick: function (e) {
e.preventDefault();
_defSelectFn: function (e) {
this.hide();
ATTRS: {
activeItem: {
readOnly: true,
value: null
align: {
value: {
circular: {
value: true
hoveredItem: {
readOnly: true,
value: null
visible: {
value: false
* Alias for <a href="AutoCompleteList.html"><code>AutoCompleteList</code></a>.