PageRenderTime 68ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/hudson-war/src/main/webapp/scripts/yui/autocomplete/autocomplete-debug.js

http://github.com/hudson/hudson
JavaScript | 2044 lines | 908 code | 188 blank | 948 comment | 241 complexity | 40510bf117c8ebd00118a409221196bf MD5 | raw file
Possible License(s): MIT, BSD-3-Clause
  1. /*
  2. Copyright (c) 2008, Yahoo! Inc. All rights reserved.
  3. Code licensed under the BSD License:
  4. http://developer.yahoo.net/yui/license.txt
  5. version: 2.5.1
  6. */
  7. /**
  8. * The AutoComplete control provides the front-end logic for text-entry suggestion and
  9. * completion functionality.
  10. *
  11. * @module autocomplete
  12. * @requires yahoo, dom, event, datasource
  13. * @optional animation, connection, get
  14. * @namespace YAHOO.widget
  15. * @title AutoComplete Widget
  16. */
  17. /****************************************************************************/
  18. /****************************************************************************/
  19. /****************************************************************************/
  20. /**
  21. * The AutoComplete class provides the customizable functionality of a plug-and-play DHTML
  22. * auto completion widget. Some key features:
  23. * <ul>
  24. * <li>Navigate with up/down arrow keys and/or mouse to pick a selection</li>
  25. * <li>The drop down container can "roll down" or "fly out" via configurable
  26. * animation</li>
  27. * <li>UI look-and-feel customizable through CSS, including container
  28. * attributes, borders, position, fonts, etc</li>
  29. * </ul>
  30. *
  31. * @class AutoComplete
  32. * @constructor
  33. * @param elInput {HTMLElement} DOM element reference of an input field.
  34. * @param elInput {String} String ID of an input field.
  35. * @param elContainer {HTMLElement} DOM element reference of an existing DIV.
  36. * @param elContainer {String} String ID of an existing DIV.
  37. * @param oDataSource {YAHOO.widget.DataSource} DataSource instance.
  38. * @param oConfigs {Object} (optional) Object literal of configuration params.
  39. */
  40. YAHOO.widget.AutoComplete = function(elInput,elContainer,oDataSource,oConfigs) {
  41. if(elInput && elContainer && oDataSource) {
  42. // Validate DataSource
  43. if(oDataSource instanceof YAHOO.widget.DataSource) {
  44. this.dataSource = oDataSource;
  45. }
  46. else {
  47. YAHOO.log("Could not instantiate AutoComplete due to an invalid DataSource", "error", this.toString());
  48. return;
  49. }
  50. // Validate input element
  51. if(YAHOO.util.Dom.inDocument(elInput)) {
  52. if(YAHOO.lang.isString(elInput)) {
  53. this._sName = "instance" + YAHOO.widget.AutoComplete._nIndex + " " + elInput;
  54. this._elTextbox = document.getElementById(elInput);
  55. }
  56. else {
  57. this._sName = (elInput.id) ?
  58. "instance" + YAHOO.widget.AutoComplete._nIndex + " " + elInput.id:
  59. "instance" + YAHOO.widget.AutoComplete._nIndex;
  60. this._elTextbox = elInput;
  61. }
  62. YAHOO.util.Dom.addClass(this._elTextbox, "yui-ac-input");
  63. }
  64. else {
  65. YAHOO.log("Could not instantiate AutoComplete due to an invalid input element", "error", this.toString());
  66. return;
  67. }
  68. // Validate container element
  69. if(YAHOO.util.Dom.inDocument(elContainer)) {
  70. if(YAHOO.lang.isString(elContainer)) {
  71. this._elContainer = document.getElementById(elContainer);
  72. }
  73. else {
  74. this._elContainer = elContainer;
  75. }
  76. if(this._elContainer.style.display == "none") {
  77. YAHOO.log("The container may not display properly if display is set to \"none\" in CSS", "warn", this.toString());
  78. }
  79. // For skinning
  80. var elParent = this._elContainer.parentNode;
  81. var elTag = elParent.tagName.toLowerCase();
  82. if(elTag == "div") {
  83. YAHOO.util.Dom.addClass(elParent, "yui-ac");
  84. }
  85. else {
  86. YAHOO.log("Could not find the wrapper element for skinning", "warn", this.toString());
  87. }
  88. }
  89. else {
  90. YAHOO.log("Could not instantiate AutoComplete due to an invalid container element", "error", this.toString());
  91. return;
  92. }
  93. // Set any config params passed in to override defaults
  94. if(oConfigs && (oConfigs.constructor == Object)) {
  95. for(var sConfig in oConfigs) {
  96. if(sConfig) {
  97. this[sConfig] = oConfigs[sConfig];
  98. }
  99. }
  100. }
  101. // Initialization sequence
  102. this._initContainer();
  103. this._initProps();
  104. this._initList();
  105. this._initContainerHelpers();
  106. // Set up events
  107. var oSelf = this;
  108. var elTextbox = this._elTextbox;
  109. // Events are actually for the content module within the container
  110. var elContent = this._elContent;
  111. // Dom events
  112. YAHOO.util.Event.addListener(elTextbox,"keyup",oSelf._onTextboxKeyUp,oSelf);
  113. YAHOO.util.Event.addListener(elTextbox,"keydown",oSelf._onTextboxKeyDown,oSelf);
  114. YAHOO.util.Event.addListener(elTextbox,"focus",oSelf._onTextboxFocus,oSelf);
  115. YAHOO.util.Event.addListener(elTextbox,"blur",oSelf._onTextboxBlur,oSelf);
  116. YAHOO.util.Event.addListener(elContent,"mouseover",oSelf._onContainerMouseover,oSelf);
  117. YAHOO.util.Event.addListener(elContent,"mouseout",oSelf._onContainerMouseout,oSelf);
  118. YAHOO.util.Event.addListener(elContent,"scroll",oSelf._onContainerScroll,oSelf);
  119. YAHOO.util.Event.addListener(elContent,"resize",oSelf._onContainerResize,oSelf);
  120. YAHOO.util.Event.addListener(elTextbox,"keypress",oSelf._onTextboxKeyPress,oSelf);
  121. YAHOO.util.Event.addListener(window,"unload",oSelf._onWindowUnload,oSelf);
  122. // Custom events
  123. this.textboxFocusEvent = new YAHOO.util.CustomEvent("textboxFocus", this);
  124. this.textboxKeyEvent = new YAHOO.util.CustomEvent("textboxKey", this);
  125. this.dataRequestEvent = new YAHOO.util.CustomEvent("dataRequest", this);
  126. this.dataReturnEvent = new YAHOO.util.CustomEvent("dataReturn", this);
  127. this.dataErrorEvent = new YAHOO.util.CustomEvent("dataError", this);
  128. this.containerExpandEvent = new YAHOO.util.CustomEvent("containerExpand", this);
  129. this.typeAheadEvent = new YAHOO.util.CustomEvent("typeAhead", this);
  130. this.itemMouseOverEvent = new YAHOO.util.CustomEvent("itemMouseOver", this);
  131. this.itemMouseOutEvent = new YAHOO.util.CustomEvent("itemMouseOut", this);
  132. this.itemArrowToEvent = new YAHOO.util.CustomEvent("itemArrowTo", this);
  133. this.itemArrowFromEvent = new YAHOO.util.CustomEvent("itemArrowFrom", this);
  134. this.itemSelectEvent = new YAHOO.util.CustomEvent("itemSelect", this);
  135. this.unmatchedItemSelectEvent = new YAHOO.util.CustomEvent("unmatchedItemSelect", this);
  136. this.selectionEnforceEvent = new YAHOO.util.CustomEvent("selectionEnforce", this);
  137. this.containerCollapseEvent = new YAHOO.util.CustomEvent("containerCollapse", this);
  138. this.textboxBlurEvent = new YAHOO.util.CustomEvent("textboxBlur", this);
  139. // Finish up
  140. elTextbox.setAttribute("autocomplete","off");
  141. YAHOO.widget.AutoComplete._nIndex++;
  142. YAHOO.log("AutoComplete initialized","info",this.toString());
  143. }
  144. // Required arguments were not found
  145. else {
  146. YAHOO.log("Could not instantiate AutoComplete due invalid arguments", "error", this.toString());
  147. }
  148. };
  149. /////////////////////////////////////////////////////////////////////////////
  150. //
  151. // Public member variables
  152. //
  153. /////////////////////////////////////////////////////////////////////////////
  154. /**
  155. * The DataSource object that encapsulates the data used for auto completion.
  156. * This object should be an inherited object from YAHOO.widget.DataSource.
  157. *
  158. * @property dataSource
  159. * @type YAHOO.widget.DataSource
  160. */
  161. YAHOO.widget.AutoComplete.prototype.dataSource = null;
  162. /**
  163. * Number of characters that must be entered before querying for results. A negative value
  164. * effectively turns off the widget. A value of 0 allows queries of null or empty string
  165. * values.
  166. *
  167. * @property minQueryLength
  168. * @type Number
  169. * @default 1
  170. */
  171. YAHOO.widget.AutoComplete.prototype.minQueryLength = 1;
  172. /**
  173. * Maximum number of results to display in results container.
  174. *
  175. * @property maxResultsDisplayed
  176. * @type Number
  177. * @default 10
  178. */
  179. YAHOO.widget.AutoComplete.prototype.maxResultsDisplayed = 10;
  180. /**
  181. * Number of seconds to delay before submitting a query request. If a query
  182. * request is received before a previous one has completed its delay, the
  183. * previous request is cancelled and the new request is set to the delay.
  184. * Implementers should take care when setting this value very low (i.e., less
  185. * than 0.2) with low latency DataSources and the typeAhead feature enabled, as
  186. * fast typers may see unexpected behavior.
  187. *
  188. * @property queryDelay
  189. * @type Number
  190. * @default 0.2
  191. */
  192. YAHOO.widget.AutoComplete.prototype.queryDelay = 0.2;
  193. /**
  194. * Class name of a highlighted item within results container.
  195. *
  196. * @property highlightClassName
  197. * @type String
  198. * @default "yui-ac-highlight"
  199. */
  200. YAHOO.widget.AutoComplete.prototype.highlightClassName = "yui-ac-highlight";
  201. /**
  202. * Class name of a pre-highlighted item within results container.
  203. *
  204. * @property prehighlightClassName
  205. * @type String
  206. */
  207. YAHOO.widget.AutoComplete.prototype.prehighlightClassName = null;
  208. /**
  209. * Query delimiter. A single character separator for multiple delimited
  210. * selections. Multiple delimiter characteres may be defined as an array of
  211. * strings. A null value or empty string indicates that query results cannot
  212. * be delimited. This feature is not recommended if you need forceSelection to
  213. * be true.
  214. *
  215. * @property delimChar
  216. * @type String | String[]
  217. */
  218. YAHOO.widget.AutoComplete.prototype.delimChar = null;
  219. /**
  220. * Whether or not the first item in results container should be automatically highlighted
  221. * on expand.
  222. *
  223. * @property autoHighlight
  224. * @type Boolean
  225. * @default true
  226. */
  227. YAHOO.widget.AutoComplete.prototype.autoHighlight = true;
  228. /**
  229. * Whether or not the input field should be automatically updated
  230. * with the first query result as the user types, auto-selecting the substring
  231. * that the user has not typed.
  232. *
  233. * @property typeAhead
  234. * @type Boolean
  235. * @default false
  236. */
  237. YAHOO.widget.AutoComplete.prototype.typeAhead = false;
  238. /**
  239. * Whether or not to animate the expansion/collapse of the results container in the
  240. * horizontal direction.
  241. *
  242. * @property animHoriz
  243. * @type Boolean
  244. * @default false
  245. */
  246. YAHOO.widget.AutoComplete.prototype.animHoriz = false;
  247. /**
  248. * Whether or not to animate the expansion/collapse of the results container in the
  249. * vertical direction.
  250. *
  251. * @property animVert
  252. * @type Boolean
  253. * @default true
  254. */
  255. YAHOO.widget.AutoComplete.prototype.animVert = true;
  256. /**
  257. * Speed of container expand/collapse animation, in seconds..
  258. *
  259. * @property animSpeed
  260. * @type Number
  261. * @default 0.3
  262. */
  263. YAHOO.widget.AutoComplete.prototype.animSpeed = 0.3;
  264. /**
  265. * Whether or not to force the user's selection to match one of the query
  266. * results. Enabling this feature essentially transforms the input field into a
  267. * &lt;select&gt; field. This feature is not recommended with delimiter character(s)
  268. * defined.
  269. *
  270. * @property forceSelection
  271. * @type Boolean
  272. * @default false
  273. */
  274. YAHOO.widget.AutoComplete.prototype.forceSelection = false;
  275. /**
  276. * Whether or not to allow browsers to cache user-typed input in the input
  277. * field. Disabling this feature will prevent the widget from setting the
  278. * autocomplete="off" on the input field. When autocomplete="off"
  279. * and users click the back button after form submission, user-typed input can
  280. * be prefilled by the browser from its cache. This caching of user input may
  281. * not be desired for sensitive data, such as credit card numbers, in which
  282. * case, implementers should consider setting allowBrowserAutocomplete to false.
  283. *
  284. * @property allowBrowserAutocomplete
  285. * @type Boolean
  286. * @default true
  287. */
  288. YAHOO.widget.AutoComplete.prototype.allowBrowserAutocomplete = true;
  289. /**
  290. * Whether or not the results container should always be displayed.
  291. * Enabling this feature displays the container when the widget is instantiated
  292. * and prevents the toggling of the container to a collapsed state.
  293. *
  294. * @property alwaysShowContainer
  295. * @type Boolean
  296. * @default false
  297. */
  298. YAHOO.widget.AutoComplete.prototype.alwaysShowContainer = false;
  299. /**
  300. * Whether or not to use an iFrame to layer over Windows form elements in
  301. * IE. Set to true only when the results container will be on top of a
  302. * &lt;select&gt; field in IE and thus exposed to the IE z-index bug (i.e.,
  303. * 5.5 < IE < 7).
  304. *
  305. * @property useIFrame
  306. * @type Boolean
  307. * @default false
  308. */
  309. YAHOO.widget.AutoComplete.prototype.useIFrame = false;
  310. /**
  311. * Whether or not the results container should have a shadow.
  312. *
  313. * @property useShadow
  314. * @type Boolean
  315. * @default false
  316. */
  317. YAHOO.widget.AutoComplete.prototype.useShadow = false;
  318. /////////////////////////////////////////////////////////////////////////////
  319. //
  320. // Public methods
  321. //
  322. /////////////////////////////////////////////////////////////////////////////
  323. /**
  324. * Public accessor to the unique name of the AutoComplete instance.
  325. *
  326. * @method toString
  327. * @return {String} Unique name of the AutoComplete instance.
  328. */
  329. YAHOO.widget.AutoComplete.prototype.toString = function() {
  330. return "AutoComplete " + this._sName;
  331. };
  332. /**
  333. * Returns true if container is in an expanded state, false otherwise.
  334. *
  335. * @method isContainerOpen
  336. * @return {Boolean} Returns true if container is in an expanded state, false otherwise.
  337. */
  338. YAHOO.widget.AutoComplete.prototype.isContainerOpen = function() {
  339. return this._bContainerOpen;
  340. };
  341. /**
  342. * Public accessor to the internal array of DOM &lt;li&gt; elements that
  343. * display query results within the results container.
  344. *
  345. * @method getListItems
  346. * @return {HTMLElement[]} Array of &lt;li&gt; elements within the results container.
  347. */
  348. YAHOO.widget.AutoComplete.prototype.getListItems = function() {
  349. return this._aListItems;
  350. };
  351. /**
  352. * Public accessor to the data held in an &lt;li&gt; element of the
  353. * results container.
  354. *
  355. * @method getListItemData
  356. * @return {Object | Object[]} Object or array of result data or null
  357. */
  358. YAHOO.widget.AutoComplete.prototype.getListItemData = function(oListItem) {
  359. if(oListItem._oResultData) {
  360. return oListItem._oResultData;
  361. }
  362. else {
  363. return false;
  364. }
  365. };
  366. /**
  367. * Sets HTML markup for the results container header. This markup will be
  368. * inserted within a &lt;div&gt; tag with a class of "yui-ac-hd".
  369. *
  370. * @method setHeader
  371. * @param sHeader {String} HTML markup for results container header.
  372. */
  373. YAHOO.widget.AutoComplete.prototype.setHeader = function(sHeader) {
  374. if(this._elHeader) {
  375. var elHeader = this._elHeader;
  376. if(sHeader) {
  377. elHeader.innerHTML = sHeader;
  378. elHeader.style.display = "block";
  379. }
  380. else {
  381. elHeader.innerHTML = "";
  382. elHeader.style.display = "none";
  383. }
  384. }
  385. };
  386. /**
  387. * Sets HTML markup for the results container footer. This markup will be
  388. * inserted within a &lt;div&gt; tag with a class of "yui-ac-ft".
  389. *
  390. * @method setFooter
  391. * @param sFooter {String} HTML markup for results container footer.
  392. */
  393. YAHOO.widget.AutoComplete.prototype.setFooter = function(sFooter) {
  394. if(this._elFooter) {
  395. var elFooter = this._elFooter;
  396. if(sFooter) {
  397. elFooter.innerHTML = sFooter;
  398. elFooter.style.display = "block";
  399. }
  400. else {
  401. elFooter.innerHTML = "";
  402. elFooter.style.display = "none";
  403. }
  404. }
  405. };
  406. /**
  407. * Sets HTML markup for the results container body. This markup will be
  408. * inserted within a &lt;div&gt; tag with a class of "yui-ac-bd".
  409. *
  410. * @method setBody
  411. * @param sBody {String} HTML markup for results container body.
  412. */
  413. YAHOO.widget.AutoComplete.prototype.setBody = function(sBody) {
  414. if(this._elBody) {
  415. var elBody = this._elBody;
  416. if(sBody) {
  417. elBody.innerHTML = sBody;
  418. elBody.style.display = "block";
  419. elBody.style.display = "block";
  420. }
  421. else {
  422. elBody.innerHTML = "";
  423. elBody.style.display = "none";
  424. }
  425. this._maxResultsDisplayed = 0;
  426. }
  427. };
  428. /**
  429. * Overridable method that converts a result item object into HTML markup
  430. * for display. Return data values are accessible via the oResultItem object,
  431. * and the key return value will always be oResultItem[0]. Markup will be
  432. * displayed within &lt;li&gt; element tags in the container.
  433. *
  434. * @method formatResult
  435. * @param oResultItem {Object} Result item representing one query result. Data is held in an array.
  436. * @param sQuery {String} The current query string.
  437. * @return {String} HTML markup of formatted result data.
  438. */
  439. YAHOO.widget.AutoComplete.prototype.formatResult = function(oResultItem, sQuery) {
  440. var sResult = oResultItem[0];
  441. if(sResult) {
  442. return sResult;
  443. }
  444. else {
  445. return "";
  446. }
  447. };
  448. /**
  449. * Overridable method called before container expands allows implementers to access data
  450. * and DOM elements.
  451. *
  452. * @method doBeforeExpandContainer
  453. * @param elTextbox {HTMLElement} The text input box.
  454. * @param elContainer {HTMLElement} The container element.
  455. * @param sQuery {String} The query string.
  456. * @param aResults {Object[]} An array of query results.
  457. * @return {Boolean} Return true to continue expanding container, false to cancel the expand.
  458. */
  459. YAHOO.widget.AutoComplete.prototype.doBeforeExpandContainer = function(elTextbox, elContainer, sQuery, aResults) {
  460. return true;
  461. };
  462. /**
  463. * Makes query request to the DataSource.
  464. *
  465. * @method sendQuery
  466. * @param sQuery {String} Query string.
  467. */
  468. YAHOO.widget.AutoComplete.prototype.sendQuery = function(sQuery) {
  469. this._sendQuery(sQuery);
  470. };
  471. /**
  472. * Overridable method gives implementers access to the query before it gets sent.
  473. *
  474. * @method doBeforeSendQuery
  475. * @param sQuery {String} Query string.
  476. * @return {String} Query string.
  477. */
  478. YAHOO.widget.AutoComplete.prototype.doBeforeSendQuery = function(sQuery) {
  479. return sQuery;
  480. };
  481. /**
  482. * Nulls out the entire AutoComplete instance and related objects, removes attached
  483. * event listeners, and clears out DOM elements inside the container. After
  484. * calling this method, the instance reference should be expliclitly nulled by
  485. * implementer, as in myDataTable = null. Use with caution!
  486. *
  487. * @method destroy
  488. */
  489. YAHOO.widget.AutoComplete.prototype.destroy = function() {
  490. var instanceName = this.toString();
  491. var elInput = this._elTextbox;
  492. var elContainer = this._elContainer;
  493. // Unhook custom events
  494. this.textboxFocusEvent.unsubscribeAll();
  495. this.textboxKeyEvent.unsubscribeAll();
  496. this.dataRequestEvent.unsubscribeAll();
  497. this.dataReturnEvent.unsubscribeAll();
  498. this.dataErrorEvent.unsubscribeAll();
  499. this.containerExpandEvent.unsubscribeAll();
  500. this.typeAheadEvent.unsubscribeAll();
  501. this.itemMouseOverEvent.unsubscribeAll();
  502. this.itemMouseOutEvent.unsubscribeAll();
  503. this.itemArrowToEvent.unsubscribeAll();
  504. this.itemArrowFromEvent.unsubscribeAll();
  505. this.itemSelectEvent.unsubscribeAll();
  506. this.unmatchedItemSelectEvent.unsubscribeAll();
  507. this.selectionEnforceEvent.unsubscribeAll();
  508. this.containerCollapseEvent.unsubscribeAll();
  509. this.textboxBlurEvent.unsubscribeAll();
  510. // Unhook DOM events
  511. YAHOO.util.Event.purgeElement(elInput, true);
  512. YAHOO.util.Event.purgeElement(elContainer, true);
  513. // Remove DOM elements
  514. elContainer.innerHTML = "";
  515. // Null out objects
  516. for(var key in this) {
  517. if(YAHOO.lang.hasOwnProperty(this, key)) {
  518. this[key] = null;
  519. }
  520. }
  521. YAHOO.log("AutoComplete instance destroyed: " + instanceName);
  522. };
  523. /////////////////////////////////////////////////////////////////////////////
  524. //
  525. // Public events
  526. //
  527. /////////////////////////////////////////////////////////////////////////////
  528. /**
  529. * Fired when the input field receives focus.
  530. *
  531. * @event textboxFocusEvent
  532. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  533. */
  534. YAHOO.widget.AutoComplete.prototype.textboxFocusEvent = null;
  535. /**
  536. * Fired when the input field receives key input.
  537. *
  538. * @event textboxKeyEvent
  539. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  540. * @param nKeycode {Number} The keycode number.
  541. */
  542. YAHOO.widget.AutoComplete.prototype.textboxKeyEvent = null;
  543. /**
  544. * Fired when the AutoComplete instance makes a query to the DataSource.
  545. *
  546. * @event dataRequestEvent
  547. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  548. * @param sQuery {String} The query string.
  549. */
  550. YAHOO.widget.AutoComplete.prototype.dataRequestEvent = null;
  551. /**
  552. * Fired when the AutoComplete instance receives query results from the data
  553. * source.
  554. *
  555. * @event dataReturnEvent
  556. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  557. * @param sQuery {String} The query string.
  558. * @param aResults {Object[]} Results array.
  559. */
  560. YAHOO.widget.AutoComplete.prototype.dataReturnEvent = null;
  561. /**
  562. * Fired when the AutoComplete instance does not receive query results from the
  563. * DataSource due to an error.
  564. *
  565. * @event dataErrorEvent
  566. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  567. * @param sQuery {String} The query string.
  568. */
  569. YAHOO.widget.AutoComplete.prototype.dataErrorEvent = null;
  570. /**
  571. * Fired when the results container is expanded.
  572. *
  573. * @event containerExpandEvent
  574. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  575. */
  576. YAHOO.widget.AutoComplete.prototype.containerExpandEvent = null;
  577. /**
  578. * Fired when the input field has been prefilled by the type-ahead
  579. * feature.
  580. *
  581. * @event typeAheadEvent
  582. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  583. * @param sQuery {String} The query string.
  584. * @param sPrefill {String} The prefill string.
  585. */
  586. YAHOO.widget.AutoComplete.prototype.typeAheadEvent = null;
  587. /**
  588. * Fired when result item has been moused over.
  589. *
  590. * @event itemMouseOverEvent
  591. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  592. * @param elItem {HTMLElement} The &lt;li&gt element item moused to.
  593. */
  594. YAHOO.widget.AutoComplete.prototype.itemMouseOverEvent = null;
  595. /**
  596. * Fired when result item has been moused out.
  597. *
  598. * @event itemMouseOutEvent
  599. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  600. * @param elItem {HTMLElement} The &lt;li&gt; element item moused from.
  601. */
  602. YAHOO.widget.AutoComplete.prototype.itemMouseOutEvent = null;
  603. /**
  604. * Fired when result item has been arrowed to.
  605. *
  606. * @event itemArrowToEvent
  607. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  608. * @param elItem {HTMLElement} The &lt;li&gt; element item arrowed to.
  609. */
  610. YAHOO.widget.AutoComplete.prototype.itemArrowToEvent = null;
  611. /**
  612. * Fired when result item has been arrowed away from.
  613. *
  614. * @event itemArrowFromEvent
  615. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  616. * @param elItem {HTMLElement} The &lt;li&gt; element item arrowed from.
  617. */
  618. YAHOO.widget.AutoComplete.prototype.itemArrowFromEvent = null;
  619. /**
  620. * Fired when an item is selected via mouse click, ENTER key, or TAB key.
  621. *
  622. * @event itemSelectEvent
  623. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  624. * @param elItem {HTMLElement} The selected &lt;li&gt; element item.
  625. * @param oData {Object} The data returned for the item, either as an object,
  626. * or mapped from the schema into an array.
  627. */
  628. YAHOO.widget.AutoComplete.prototype.itemSelectEvent = null;
  629. /**
  630. * Fired when a user selection does not match any of the displayed result items.
  631. *
  632. * @event unmatchedItemSelectEvent
  633. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  634. */
  635. YAHOO.widget.AutoComplete.prototype.unmatchedItemSelectEvent = null;
  636. /**
  637. * Fired if forceSelection is enabled and the user's input has been cleared
  638. * because it did not match one of the returned query results.
  639. *
  640. * @event selectionEnforceEvent
  641. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  642. */
  643. YAHOO.widget.AutoComplete.prototype.selectionEnforceEvent = null;
  644. /**
  645. * Fired when the results container is collapsed.
  646. *
  647. * @event containerCollapseEvent
  648. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  649. */
  650. YAHOO.widget.AutoComplete.prototype.containerCollapseEvent = null;
  651. /**
  652. * Fired when the input field loses focus.
  653. *
  654. * @event textboxBlurEvent
  655. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  656. */
  657. YAHOO.widget.AutoComplete.prototype.textboxBlurEvent = null;
  658. /////////////////////////////////////////////////////////////////////////////
  659. //
  660. // Private member variables
  661. //
  662. /////////////////////////////////////////////////////////////////////////////
  663. /**
  664. * Internal class variable to index multiple AutoComplete instances.
  665. *
  666. * @property _nIndex
  667. * @type Number
  668. * @default 0
  669. * @private
  670. */
  671. YAHOO.widget.AutoComplete._nIndex = 0;
  672. /**
  673. * Name of AutoComplete instance.
  674. *
  675. * @property _sName
  676. * @type String
  677. * @private
  678. */
  679. YAHOO.widget.AutoComplete.prototype._sName = null;
  680. /**
  681. * Text input field DOM element.
  682. *
  683. * @property _elTextbox
  684. * @type HTMLElement
  685. * @private
  686. */
  687. YAHOO.widget.AutoComplete.prototype._elTextbox = null;
  688. /**
  689. * Container DOM element.
  690. *
  691. * @property _elContainer
  692. * @type HTMLElement
  693. * @private
  694. */
  695. YAHOO.widget.AutoComplete.prototype._elContainer = null;
  696. /**
  697. * Reference to content element within container element.
  698. *
  699. * @property _elContent
  700. * @type HTMLElement
  701. * @private
  702. */
  703. YAHOO.widget.AutoComplete.prototype._elContent = null;
  704. /**
  705. * Reference to header element within content element.
  706. *
  707. * @property _elHeader
  708. * @type HTMLElement
  709. * @private
  710. */
  711. YAHOO.widget.AutoComplete.prototype._elHeader = null;
  712. /**
  713. * Reference to body element within content element.
  714. *
  715. * @property _elBody
  716. * @type HTMLElement
  717. * @private
  718. */
  719. YAHOO.widget.AutoComplete.prototype._elBody = null;
  720. /**
  721. * Reference to footer element within content element.
  722. *
  723. * @property _elFooter
  724. * @type HTMLElement
  725. * @private
  726. */
  727. YAHOO.widget.AutoComplete.prototype._elFooter = null;
  728. /**
  729. * Reference to shadow element within container element.
  730. *
  731. * @property _elShadow
  732. * @type HTMLElement
  733. * @private
  734. */
  735. YAHOO.widget.AutoComplete.prototype._elShadow = null;
  736. /**
  737. * Reference to iframe element within container element.
  738. *
  739. * @property _elIFrame
  740. * @type HTMLElement
  741. * @private
  742. */
  743. YAHOO.widget.AutoComplete.prototype._elIFrame = null;
  744. /**
  745. * Whether or not the input field is currently in focus. If query results come back
  746. * but the user has already moved on, do not proceed with auto complete behavior.
  747. *
  748. * @property _bFocused
  749. * @type Boolean
  750. * @private
  751. */
  752. YAHOO.widget.AutoComplete.prototype._bFocused = true;
  753. /**
  754. * Animation instance for container expand/collapse.
  755. *
  756. * @property _oAnim
  757. * @type Boolean
  758. * @private
  759. */
  760. YAHOO.widget.AutoComplete.prototype._oAnim = null;
  761. /**
  762. * Whether or not the results container is currently open.
  763. *
  764. * @property _bContainerOpen
  765. * @type Boolean
  766. * @private
  767. */
  768. YAHOO.widget.AutoComplete.prototype._bContainerOpen = false;
  769. /**
  770. * Whether or not the mouse is currently over the results
  771. * container. This is necessary in order to prevent clicks on container items
  772. * from being text input field blur events.
  773. *
  774. * @property _bOverContainer
  775. * @type Boolean
  776. * @private
  777. */
  778. YAHOO.widget.AutoComplete.prototype._bOverContainer = false;
  779. /**
  780. * Array of &lt;li&gt; elements references that contain query results within the
  781. * results container.
  782. *
  783. * @property _aListItems
  784. * @type HTMLElement[]
  785. * @private
  786. */
  787. YAHOO.widget.AutoComplete.prototype._aListItems = null;
  788. /**
  789. * Number of &lt;li&gt; elements currently displayed in results container.
  790. *
  791. * @property _nDisplayedItems
  792. * @type Number
  793. * @private
  794. */
  795. YAHOO.widget.AutoComplete.prototype._nDisplayedItems = 0;
  796. /**
  797. * Internal count of &lt;li&gt; elements displayed and hidden in results container.
  798. *
  799. * @property _maxResultsDisplayed
  800. * @type Number
  801. * @private
  802. */
  803. YAHOO.widget.AutoComplete.prototype._maxResultsDisplayed = 0;
  804. /**
  805. * Current query string
  806. *
  807. * @property _sCurQuery
  808. * @type String
  809. * @private
  810. */
  811. YAHOO.widget.AutoComplete.prototype._sCurQuery = null;
  812. /**
  813. * Past queries this session (for saving delimited queries).
  814. *
  815. * @property _sSavedQuery
  816. * @type String
  817. * @private
  818. */
  819. YAHOO.widget.AutoComplete.prototype._sSavedQuery = null;
  820. /**
  821. * Pointer to the currently highlighted &lt;li&gt; element in the container.
  822. *
  823. * @property _oCurItem
  824. * @type HTMLElement
  825. * @private
  826. */
  827. YAHOO.widget.AutoComplete.prototype._oCurItem = null;
  828. /**
  829. * Whether or not an item has been selected since the container was populated
  830. * with results. Reset to false by _populateList, and set to true when item is
  831. * selected.
  832. *
  833. * @property _bItemSelected
  834. * @type Boolean
  835. * @private
  836. */
  837. YAHOO.widget.AutoComplete.prototype._bItemSelected = false;
  838. /**
  839. * Key code of the last key pressed in textbox.
  840. *
  841. * @property _nKeyCode
  842. * @type Number
  843. * @private
  844. */
  845. YAHOO.widget.AutoComplete.prototype._nKeyCode = null;
  846. /**
  847. * Delay timeout ID.
  848. *
  849. * @property _nDelayID
  850. * @type Number
  851. * @private
  852. */
  853. YAHOO.widget.AutoComplete.prototype._nDelayID = -1;
  854. /**
  855. * Src to iFrame used when useIFrame = true. Supports implementations over SSL
  856. * as well.
  857. *
  858. * @property _iFrameSrc
  859. * @type String
  860. * @private
  861. */
  862. YAHOO.widget.AutoComplete.prototype._iFrameSrc = "javascript:false;";
  863. /**
  864. * For users typing via certain IMEs, queries must be triggered by intervals,
  865. * since key events yet supported across all browsers for all IMEs.
  866. *
  867. * @property _queryInterval
  868. * @type Object
  869. * @private
  870. */
  871. YAHOO.widget.AutoComplete.prototype._queryInterval = null;
  872. /**
  873. * Internal tracker to last known textbox value, used to determine whether or not
  874. * to trigger a query via interval for certain IME users.
  875. *
  876. * @event _sLastTextboxValue
  877. * @type String
  878. * @private
  879. */
  880. YAHOO.widget.AutoComplete.prototype._sLastTextboxValue = null;
  881. /////////////////////////////////////////////////////////////////////////////
  882. //
  883. // Private methods
  884. //
  885. /////////////////////////////////////////////////////////////////////////////
  886. /**
  887. * Updates and validates latest public config properties.
  888. *
  889. * @method __initProps
  890. * @private
  891. */
  892. YAHOO.widget.AutoComplete.prototype._initProps = function() {
  893. // Correct any invalid values
  894. var minQueryLength = this.minQueryLength;
  895. if(!YAHOO.lang.isNumber(minQueryLength)) {
  896. this.minQueryLength = 1;
  897. }
  898. var maxResultsDisplayed = this.maxResultsDisplayed;
  899. if(!YAHOO.lang.isNumber(maxResultsDisplayed) || (maxResultsDisplayed < 1)) {
  900. this.maxResultsDisplayed = 10;
  901. }
  902. var queryDelay = this.queryDelay;
  903. if(!YAHOO.lang.isNumber(queryDelay) || (queryDelay < 0)) {
  904. this.queryDelay = 0.2;
  905. }
  906. var delimChar = this.delimChar;
  907. if(YAHOO.lang.isString(delimChar) && (delimChar.length > 0)) {
  908. this.delimChar = [delimChar];
  909. }
  910. else if(!YAHOO.lang.isArray(delimChar)) {
  911. this.delimChar = null;
  912. }
  913. var animSpeed = this.animSpeed;
  914. if((this.animHoriz || this.animVert) && YAHOO.util.Anim) {
  915. if(!YAHOO.lang.isNumber(animSpeed) || (animSpeed < 0)) {
  916. this.animSpeed = 0.3;
  917. }
  918. if(!this._oAnim ) {
  919. this._oAnim = new YAHOO.util.Anim(this._elContent, {}, this.animSpeed);
  920. }
  921. else {
  922. this._oAnim.duration = this.animSpeed;
  923. }
  924. }
  925. if(this.forceSelection && delimChar) {
  926. YAHOO.log("The forceSelection feature has been enabled with delimChar defined.","warn", this.toString());
  927. }
  928. };
  929. /**
  930. * Initializes the results container helpers if they are enabled and do
  931. * not exist
  932. *
  933. * @method _initContainerHelpers
  934. * @private
  935. */
  936. YAHOO.widget.AutoComplete.prototype._initContainerHelpers = function() {
  937. if(this.useShadow && !this._elShadow) {
  938. var elShadow = document.createElement("div");
  939. elShadow.className = "yui-ac-shadow";
  940. this._elShadow = this._elContainer.appendChild(elShadow);
  941. }
  942. if(this.useIFrame && !this._elIFrame) {
  943. var elIFrame = document.createElement("iframe");
  944. elIFrame.src = this._iFrameSrc;
  945. elIFrame.frameBorder = 0;
  946. elIFrame.scrolling = "no";
  947. elIFrame.style.position = "absolute";
  948. elIFrame.style.width = "100%";
  949. elIFrame.style.height = "100%";
  950. elIFrame.tabIndex = -1;
  951. this._elIFrame = this._elContainer.appendChild(elIFrame);
  952. }
  953. };
  954. /**
  955. * Initializes the results container once at object creation
  956. *
  957. * @method _initContainer
  958. * @private
  959. */
  960. YAHOO.widget.AutoComplete.prototype._initContainer = function() {
  961. YAHOO.util.Dom.addClass(this._elContainer, "yui-ac-container");
  962. if(!this._elContent) {
  963. // The elContent div helps size the iframe and shadow properly
  964. var elContent = document.createElement("div");
  965. elContent.className = "yui-ac-content";
  966. elContent.style.display = "none";
  967. this._elContent = this._elContainer.appendChild(elContent);
  968. var elHeader = document.createElement("div");
  969. elHeader.className = "yui-ac-hd";
  970. elHeader.style.display = "none";
  971. this._elHeader = this._elContent.appendChild(elHeader);
  972. var elBody = document.createElement("div");
  973. elBody.className = "yui-ac-bd";
  974. this._elBody = this._elContent.appendChild(elBody);
  975. var elFooter = document.createElement("div");
  976. elFooter.className = "yui-ac-ft";
  977. elFooter.style.display = "none";
  978. this._elFooter = this._elContent.appendChild(elFooter);
  979. }
  980. else {
  981. YAHOO.log("Could not initialize the container","warn",this.toString());
  982. }
  983. };
  984. /**
  985. * Clears out contents of container body and creates up to
  986. * YAHOO.widget.AutoComplete#maxResultsDisplayed &lt;li&gt; elements in an
  987. * &lt;ul&gt; element.
  988. *
  989. * @method _initList
  990. * @private
  991. */
  992. YAHOO.widget.AutoComplete.prototype._initList = function() {
  993. this._aListItems = [];
  994. while(this._elBody.hasChildNodes()) {
  995. var oldListItems = this.getListItems();
  996. if(oldListItems) {
  997. for(var oldi = oldListItems.length-1; oldi >= 0; oldi--) {
  998. oldListItems[oldi] = null;
  999. }
  1000. }
  1001. this._elBody.innerHTML = "";
  1002. }
  1003. var oList = document.createElement("ul");
  1004. oList = this._elBody.appendChild(oList);
  1005. for(var i=0; i<this.maxResultsDisplayed; i++) {
  1006. var oItem = document.createElement("li");
  1007. oItem = oList.appendChild(oItem);
  1008. this._aListItems[i] = oItem;
  1009. this._initListItem(oItem, i);
  1010. }
  1011. this._maxResultsDisplayed = this.maxResultsDisplayed;
  1012. };
  1013. /**
  1014. * Initializes each &lt;li&gt; element in the container list.
  1015. *
  1016. * @method _initListItem
  1017. * @param oItem {HTMLElement} The &lt;li&gt; DOM element.
  1018. * @param nItemIndex {Number} The index of the element.
  1019. * @private
  1020. */
  1021. YAHOO.widget.AutoComplete.prototype._initListItem = function(oItem, nItemIndex) {
  1022. var oSelf = this;
  1023. oItem.style.display = "none";
  1024. oItem._nItemIndex = nItemIndex;
  1025. oItem.mouseover = oItem.mouseout = oItem.onclick = null;
  1026. YAHOO.util.Event.addListener(oItem,"mouseover",oSelf._onItemMouseover,oSelf);
  1027. YAHOO.util.Event.addListener(oItem,"mouseout",oSelf._onItemMouseout,oSelf);
  1028. YAHOO.util.Event.addListener(oItem,"click",oSelf._onItemMouseclick,oSelf);
  1029. };
  1030. /**
  1031. * Enables interval detection for Korean IME support.
  1032. *
  1033. * @method _onIMEDetected
  1034. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  1035. * @private
  1036. */
  1037. YAHOO.widget.AutoComplete.prototype._onIMEDetected = function(oSelf) {
  1038. oSelf._enableIntervalDetection();
  1039. };
  1040. /**
  1041. * Enables query triggers based on text input detection by intervals (rather
  1042. * than by key events).
  1043. *
  1044. * @method _enableIntervalDetection
  1045. * @private
  1046. */
  1047. YAHOO.widget.AutoComplete.prototype._enableIntervalDetection = function() {
  1048. var currValue = this._elTextbox.value;
  1049. var lastValue = this._sLastTextboxValue;
  1050. if(currValue != lastValue) {
  1051. this._sLastTextboxValue = currValue;
  1052. this._sendQuery(currValue);
  1053. }
  1054. };
  1055. /**
  1056. * Cancels text input detection by intervals.
  1057. *
  1058. * @method _cancelIntervalDetection
  1059. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  1060. * @private
  1061. */
  1062. YAHOO.widget.AutoComplete.prototype._cancelIntervalDetection = function(oSelf) {
  1063. if(oSelf._queryInterval) {
  1064. clearInterval(oSelf._queryInterval);
  1065. }
  1066. };
  1067. /**
  1068. * Whether or not key is functional or should be ignored. Note that the right
  1069. * arrow key is NOT an ignored key since it triggers queries for certain intl
  1070. * charsets.
  1071. *
  1072. * @method _isIgnoreKey
  1073. * @param nKeycode {Number} Code of key pressed.
  1074. * @return {Boolean} True if key should be ignored, false otherwise.
  1075. * @private
  1076. */
  1077. YAHOO.widget.AutoComplete.prototype._isIgnoreKey = function(nKeyCode) {
  1078. if((nKeyCode == 9) || (nKeyCode == 13) || // tab, enter
  1079. (nKeyCode == 16) || (nKeyCode == 17) || // shift, ctl
  1080. (nKeyCode >= 18 && nKeyCode <= 20) || // alt,pause/break,caps lock
  1081. (nKeyCode == 27) || // esc
  1082. (nKeyCode >= 33 && nKeyCode <= 35) || // page up,page down,end
  1083. /*(nKeyCode >= 36 && nKeyCode <= 38) || // home,left,up
  1084. (nKeyCode == 40) || // down*/
  1085. (nKeyCode >= 36 && nKeyCode <= 40) || // home,left,up, right, down
  1086. (nKeyCode >= 44 && nKeyCode <= 45)) { // print screen,insert
  1087. return true;
  1088. }
  1089. return false;
  1090. };
  1091. /**
  1092. * Makes query request to the DataSource.
  1093. *
  1094. * @method _sendQuery
  1095. * @param sQuery {String} Query string.
  1096. * @private
  1097. */
  1098. YAHOO.widget.AutoComplete.prototype._sendQuery = function(sQuery) {
  1099. // Widget has been effectively turned off
  1100. if(this.minQueryLength == -1) {
  1101. this._toggleContainer(false);
  1102. YAHOO.log("Property minQueryLength is set to -1", "info", this.toString());
  1103. return;
  1104. }
  1105. // Delimiter has been enabled
  1106. var aDelimChar = (this.delimChar) ? this.delimChar : null;
  1107. if(aDelimChar) {
  1108. // Loop through all possible delimiters and find the latest one
  1109. // A " " may be a false positive if they are defined as delimiters AND
  1110. // are used to separate delimited queries
  1111. var nDelimIndex = -1;
  1112. for(var i = aDelimChar.length-1; i >= 0; i--) {
  1113. var nNewIndex = sQuery.lastIndexOf(aDelimChar[i]);
  1114. if(nNewIndex > nDelimIndex) {
  1115. nDelimIndex = nNewIndex;
  1116. }
  1117. }
  1118. // If we think the last delimiter is a space (" "), make sure it is NOT
  1119. // a false positive by also checking the char directly before it
  1120. if(aDelimChar[i] == " ") {
  1121. for (var j = aDelimChar.length-1; j >= 0; j--) {
  1122. if(sQuery[nDelimIndex - 1] == aDelimChar[j]) {
  1123. nDelimIndex--;
  1124. break;
  1125. }
  1126. }
  1127. }
  1128. // A delimiter has been found so extract the latest query
  1129. if(nDelimIndex > -1) {
  1130. var nQueryStart = nDelimIndex + 1;
  1131. // Trim any white space from the beginning...
  1132. while(sQuery.charAt(nQueryStart) == " ") {
  1133. nQueryStart += 1;
  1134. }
  1135. // ...and save the rest of the string for later
  1136. this._sSavedQuery = sQuery.substring(0,nQueryStart);
  1137. // Here is the query itself
  1138. sQuery = sQuery.substr(nQueryStart);
  1139. }
  1140. else if(sQuery.indexOf(this._sSavedQuery) < 0){
  1141. this._sSavedQuery = null;
  1142. }
  1143. }
  1144. // Don't search queries that are too short
  1145. if((sQuery && (sQuery.length < this.minQueryLength)) || (!sQuery && this.minQueryLength > 0)) {
  1146. if(this._nDelayID != -1) {
  1147. clearTimeout(this._nDelayID);
  1148. }
  1149. this._toggleContainer(false);
  1150. YAHOO.log("Query \"" + sQuery + "\" is too short", "info", this.toString());
  1151. return;
  1152. }
  1153. sQuery = encodeURIComponent(sQuery);
  1154. this._nDelayID = -1; // Reset timeout ID because request has been made
  1155. sQuery = this.doBeforeSendQuery(sQuery);
  1156. this.dataRequestEvent.fire(this, sQuery);
  1157. YAHOO.log("Sending query \"" + sQuery + "\"", "info", this.toString());
  1158. this.dataSource.getResults(this._populateList, sQuery, this);
  1159. };
  1160. /**
  1161. * Populates the array of &lt;li&gt; elements in the container with query
  1162. * results. This method is passed to YAHOO.widget.DataSource#getResults as a
  1163. * callback function so results from the DataSource instance are returned to the
  1164. * AutoComplete instance.
  1165. *
  1166. * @method _populateList
  1167. * @param sQuery {String} The query string.
  1168. * @param aResults {Object[]} An array of query result objects from the DataSource.
  1169. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  1170. * @private
  1171. */
  1172. YAHOO.widget.AutoComplete.prototype._populateList = function(sQuery, aResults, oSelf) {
  1173. if(aResults === null) {
  1174. oSelf.dataErrorEvent.fire(oSelf, sQuery);
  1175. }
  1176. if(!oSelf._bFocused || !aResults) {
  1177. YAHOO.log("Could not populate list", "info", oSelf.toString());
  1178. return;
  1179. }
  1180. var isOpera = (navigator.userAgent.toLowerCase().indexOf("opera") != -1);
  1181. var contentStyle = oSelf._elContent.style;
  1182. contentStyle.width = (!isOpera) ? null : "";
  1183. contentStyle.height = (!isOpera) ? null : "";
  1184. var sCurQuery = decodeURIComponent(sQuery);
  1185. oSelf._sCurQuery = sCurQuery;
  1186. oSelf._bItemSelected = false;
  1187. if(oSelf._maxResultsDisplayed != oSelf.maxResultsDisplayed) {
  1188. oSelf._initList();
  1189. }
  1190. var nItems = Math.min(aResults.length,oSelf.maxResultsDisplayed);
  1191. oSelf._nDisplayedItems = nItems;
  1192. if(nItems > 0) {
  1193. oSelf._initContainerHelpers();
  1194. var aItems = oSelf._aListItems;
  1195. // Fill items with data
  1196. for(var i = nItems-1; i >= 0; i--) {
  1197. var oItemi = aItems[i];
  1198. var oResultItemi = aResults[i];
  1199. oItemi.innerHTML = oSelf.formatResult(oResultItemi, sCurQuery);
  1200. oItemi.style.display = "list-item";
  1201. oItemi._sResultKey = oResultItemi[0];
  1202. oItemi._oResultData = oResultItemi;
  1203. }
  1204. // Empty out remaining items if any
  1205. for(var j = aItems.length-1; j >= nItems ; j--) {
  1206. var oItemj = aItems[j];
  1207. oItemj.innerHTML = null;
  1208. oItemj.style.display = "none";
  1209. oItemj._sResultKey = null;
  1210. oItemj._oResultData = null;
  1211. }
  1212. // Expand the container
  1213. var ok = oSelf.doBeforeExpandContainer(oSelf._elTextbox, oSelf._elContainer, sQuery, aResults);
  1214. oSelf._toggleContainer(ok);
  1215. if(oSelf.autoHighlight) {
  1216. // Go to the first item
  1217. var oFirstItem = aItems[0];
  1218. oSelf._toggleHighlight(oFirstItem,"to");
  1219. oSelf.itemArrowToEvent.fire(oSelf, oFirstItem);
  1220. YAHOO.log("Arrowed to first item", "info", oSelf.toString());
  1221. oSelf._typeAhead(oFirstItem,sQuery);
  1222. }
  1223. else {
  1224. oSelf._oCurItem = null;
  1225. }
  1226. }
  1227. else {
  1228. oSelf._toggleContainer(false);
  1229. }
  1230. oSelf.dataReturnEvent.fire(oSelf, sQuery, aResults);
  1231. YAHOO.log("Container populated with list items", "info", oSelf.toString());
  1232. };
  1233. /**
  1234. * When forceSelection is true and the user attempts
  1235. * leave the text input box without selecting an item from the query results,
  1236. * the user selection is cleared.
  1237. *
  1238. * @method _clearSelection
  1239. * @private
  1240. */
  1241. YAHOO.widget.AutoComplete.prototype._clearSelection = function() {
  1242. var sValue = this._elTextbox.value;
  1243. var sChar = (this.delimChar) ? this.delimChar[0] : null;
  1244. var nIndex = (sChar) ? sValue.lastIndexOf(sChar, sValue.length-2) : -1;
  1245. if(nIndex > -1) {
  1246. this._elTextbox.value = sValue.substring(0,nIndex);
  1247. }
  1248. else {
  1249. this._elTextbox.value = "";
  1250. }
  1251. this._sSavedQuery = this._elTextbox.value;
  1252. // Fire custom event
  1253. this.selectionEnforceEvent.fire(this);
  1254. YAHOO.log("Selection enforced", "info", this.toString());
  1255. };
  1256. /**
  1257. * Whether or not user-typed value in the text input box matches any of the
  1258. * query results.
  1259. *
  1260. * @method _textMatchesOption
  1261. * @return {HTMLElement} Matching list item element if user-input text matches
  1262. * a result, null otherwise.
  1263. * @private
  1264. */
  1265. YAHOO.widget.AutoComplete.prototype._textMatchesOption = function() {
  1266. var foundMatch = null;
  1267. for(var i = this._nDisplayedItems-1; i >= 0 ; i--) {
  1268. var oItem = this._aListItems[i];
  1269. var sMatch = oItem._sResultKey.toLowerCase();
  1270. if(sMatch == this._sCurQuery.toLowerCase()) {
  1271. foundMatch = oItem;
  1272. break;
  1273. }
  1274. }
  1275. return(foundMatch);
  1276. };
  1277. /**
  1278. * Updates in the text input box with the first query result as the user types,
  1279. * selecting the substring that the user has not typed.
  1280. *
  1281. * @method _typeAhead
  1282. * @param oItem {HTMLElement} The &lt;li&gt; element item whose data populates the input field.
  1283. * @param sQuery {String} Query string.
  1284. * @private
  1285. */
  1286. YAHOO.widget.AutoComplete.prototype._typeAhead = function(oItem, sQuery) {
  1287. // Don't update if turned off
  1288. if(!this.typeAhead || (this._nKeyCode == 8)) {
  1289. return;
  1290. }
  1291. var elTextbox = this._elTextbox;
  1292. var sValue = this._elTextbox.value; // any saved queries plus what user has typed
  1293. // Don't update with type-ahead if text selection is not supported
  1294. if(!elTextbox.setSelectionRange && !elTextbox.createTextRange) {
  1295. return;
  1296. }
  1297. // Select the portion of text that the user has not typed
  1298. var nStart = sValue.length;
  1299. this._updateValue(oItem);
  1300. var nEnd = elTextbox.value.length;
  1301. this._selectText(elTextbox,nStart,nEnd);
  1302. var sPrefill = elTextbox.value.substr(nStart,nEnd);
  1303. this.typeAheadEvent.fire(this,sQuery,sPrefill);
  1304. YAHOO.log("Typeahead occured with prefill string \"" + sPrefill + "\"", "info", this.toString());
  1305. };
  1306. /**
  1307. * Selects text in the input field.
  1308. *
  1309. * @method _selectText
  1310. * @param elTextbox {HTMLElement} Text input box element in which to select text.
  1311. * @param nStart {Number} Starting index of text string to select.
  1312. * @param nEnd {Number} Ending index of text selection.
  1313. * @private
  1314. */
  1315. YAHOO.widget.AutoComplete.prototype._selectText = function(elTextbox, nStart, nEnd) {
  1316. if(elTextbox.setSelectionRange) { // For Mozilla
  1317. elTextbox.setSelectionRange(nStart,nEnd);
  1318. }
  1319. else if(elTextbox.createTextRange) { // For IE
  1320. var oTextRange = elTextbox.createTextRange();
  1321. oTextRange.moveStart("character", nStart);
  1322. oTextRange.moveEnd("character", nEnd-elTextbox.value.length);
  1323. oTextRange.select();
  1324. }
  1325. else {
  1326. elTextbox.select();
  1327. }
  1328. };
  1329. /**
  1330. * Syncs results container with its helpers.
  1331. *
  1332. * @method _toggleContainerHelpers
  1333. * @param bShow {Boolean} True if container is expanded, false if collapsed
  1334. * @private
  1335. */
  1336. YAHOO.widget.AutoComplete.prototype._toggleContainerHelpers = function(bShow) {
  1337. var bFireEvent = false;
  1338. var width = this._elContent.offsetWidth + "px";
  1339. var height = this._elContent.offsetHeight + "px";
  1340. if(this.useIFrame && this._elIFrame) {
  1341. bFireEvent = true;
  1342. if(bShow) {
  1343. this._elIFrame.style.width = width;
  1344. this._elIFrame.style.height = height;
  1345. }
  1346. else {
  1347. this._elIFrame.style.width = 0;
  1348. this._elIFrame.style.height = 0;
  1349. }
  1350. }
  1351. if(this.useShadow && this._elShadow) {
  1352. bFireEvent = true;
  1353. if(bShow) {
  1354. this._elShadow.style.width = width;
  1355. this._elShadow.style.height = height;
  1356. }
  1357. else {
  1358. this._elShadow.style.width = 0;
  1359. this._elShadow.style.height = 0;
  1360. }
  1361. }
  1362. };
  1363. /**
  1364. * Animates expansion or collapse of the container.
  1365. *
  1366. * @method _toggleContainer
  1367. * @param bShow {Boolean} True if container should be expanded, false if container should be collapsed
  1368. * @private
  1369. */
  1370. YAHOO.widget.AutoComplete.prototype._toggleContainer = function(bShow) {
  1371. var elContainer = this._elContainer;
  1372. // Implementer has container always open so don't mess with it
  1373. if(this.alwaysShowContainer && this._bContainerOpen) {
  1374. return;
  1375. }
  1376. // Clear contents of container
  1377. if(!bShow) {
  1378. this._elContent.scrollTop = 0;
  1379. var aItems = this._aListItems;
  1380. if(aItems && (aItems.length > 0)) {
  1381. for(var i = aItems.length-1; i >= 0 ; i--) {
  1382. aItems[i].style.display = "none";
  1383. }
  1384. }
  1385. if(this._oCurItem) {
  1386. this._toggleHighlight(this._oCurItem,"from");
  1387. }
  1388. this._oCurItem = null;
  1389. this._nDisplayedItems = 0;
  1390. this._sCurQuery = null;
  1391. }
  1392. // Container is already closed
  1393. if(!bShow && !this._bContainerOpen) {
  1394. this._elContent.style.display = "none";
  1395. return;
  1396. }
  1397. // If animation is enabled...
  1398. var oAnim = this._oAnim;
  1399. if(oAnim && oAnim.getEl() && (this.animHoriz || this.animVert)) {
  1400. // If helpers need to be collapsed, do it right away...
  1401. // but if helpers need to be expanded, wait until after the container expands
  1402. if(!bShow) {
  1403. this._toggleContainerHelpers(bShow);
  1404. }
  1405. if(oAnim.isAnimated()) {
  1406. oAnim.stop();
  1407. }
  1408. // Clone container to grab current size offscreen
  1409. var oClone = this._elContent.cloneNode(true);
  1410. elContainer.appendChild(oClone);
  1411. oClone.style.top = "-9000px";
  1412. oClone.style.display = "block";
  1413. // Current size of the container is the EXPANDED size
  1414. var wExp = oClone.offsetWidth;
  1415. var hExp = oClone.offsetHeight;
  1416. // Calculate COLLAPSED sizes based on horiz and vert anim
  1417. var wColl = (this.animHoriz) ? 0 : wExp;
  1418. var hColl = (this.animVert) ? 0 : hExp;
  1419. // Set animation sizes
  1420. oAnim.attributes = (bShow) ?
  1421. {width: { to: wExp }, height: { to: hExp }} :
  1422. {width: { to: wColl}, height: { to: hColl }};
  1423. // If opening anew, set to a collapsed size...
  1424. if(bShow && !this._bContainerOpen) {
  1425. this._elContent.style.width = wColl+"px";
  1426. this._elContent.style.height = hColl+"px";
  1427. }
  1428. // Else, set it to its last known size.
  1429. else {
  1430. this._elContent.style.width = wExp+"px";
  1431. this._elContent.style.height = hExp+"px";
  1432. }
  1433. elContainer.removeChild(oClone);
  1434. oClone = null;
  1435. var oSelf = this;
  1436. var onAnimComplete = function() {
  1437. // Finish the collapse
  1438. oAnim.onComplete.unsubscribeAll();
  1439. if(bShow) {
  1440. oSelf.containerExpandEvent.fire(oSelf);
  1441. YAHOO.log("Container expanded", "info", oSelf.toString());
  1442. }
  1443. else {
  1444. oSelf._elContent.style.display = "none";
  1445. oSelf.containerCollapseEvent.fire(oSelf);
  1446. YAHOO.log("Container collapsed", "info", oSelf.toString());
  1447. }
  1448. oSelf._toggleContainerHelpers(bShow);
  1449. };
  1450. // Display container and animate it
  1451. this._elContent.style.display = "block";
  1452. oAnim.onComplete.subscribe(onAnimComplete);
  1453. oAnim.animate();
  1454. this._bContainerOpen = bShow;
  1455. }
  1456. // Else don't animate, just show or hide
  1457. else {
  1458. if(bShow) {
  1459. this._elContent.style.display = "block";
  1460. this.containerExpandEvent.fire(this);
  1461. YAHOO.log("Container expanded", "info", this.toString());
  1462. }
  1463. else {
  1464. this._elContent.style.display = "none";
  1465. this.containerCollapseEvent.fire(this);
  1466. YAHOO.log("Container collapsed", "info", this.toString());
  1467. }
  1468. this._toggleContainerHelpers(bShow);
  1469. this._bContainerOpen = bShow;
  1470. }
  1471. };
  1472. /**
  1473. * Toggles the highlight on or off for an item in the container, and also cleans
  1474. * up highlighting of any previous item.
  1475. *
  1476. * @method _toggleHighlight
  1477. * @param oNewItem {HTMLElement} The &lt;li&gt; element item to receive highlight behavior.
  1478. * @param sType {String} Type "mouseover" will toggle highlight on, and "mouseout" will toggle highlight off.
  1479. * @private
  1480. */
  1481. YAHOO.widget.AutoComplete.prototype._toggleHighlight = function(oNewItem, sType) {
  1482. var sHighlight = this.highlightClassName;
  1483. if(this._oCurItem) {
  1484. // Remove highlight from old item
  1485. YAHOO.util.Dom.removeClass(this._oCurItem, sHighlight);
  1486. }
  1487. if((sType == "to") && sHighlight) {
  1488. // Apply highlight to new item
  1489. YAHOO.util.Dom.addClass(oNewItem, sHighlight);
  1490. this._oCurItem = oNewItem;
  1491. }
  1492. };
  1493. /**
  1494. * Toggles the pre-highlight on or off for an item in the container.
  1495. *
  1496. * @method _togglePrehighlight
  1497. * @param oNewItem {HTMLElement} The &lt;li&gt; element item to receive highlight behavior.
  1498. * @param sType {String} Type "mouseover" will toggle highlight on, and "mouseout" will toggle highlight off.
  1499. * @private
  1500. */
  1501. YAHOO.widget.AutoComplete.prototype._togglePrehighlight = function(oNewItem, sType) {
  1502. if(oNewItem == this._oCurItem) {
  1503. return;
  1504. }
  1505. var sPrehighlight = this.prehighlightClassName;
  1506. if((sType == "mouseover") && sPrehighlight) {
  1507. // Apply prehighlight to new item
  1508. YAHOO.util.Dom.addClass(oNewItem, sPrehighlight);
  1509. }
  1510. else {
  1511. // Remove prehighlight from old item
  1512. YAHOO.util.Dom.removeClass(oNewItem, sPrehighlight);
  1513. }
  1514. };
  1515. /**
  1516. * Updates the text input box value with selected query result. If a delimiter
  1517. * has been defined, then the value gets appended with the delimiter.
  1518. *
  1519. * @method _updateValue
  1520. * @param oItem {HTMLElement} The &lt;li&gt; element item with which to update the value.
  1521. * @private
  1522. */
  1523. YAHOO.widget.AutoComplete.prototype._updateValue = function(oItem) {
  1524. var elTextbox = this._elTextbox;
  1525. var sDelimChar = (this.delimChar) ? (this.delimChar[0] || this.delimChar) : null;
  1526. var sSavedQuery = this._sSavedQuery;
  1527. var sResultKey = oItem._sResultKey;
  1528. elTextbox.focus();
  1529. // First clear text field
  1530. elTextbox.value = "";
  1531. // Grab data to put into text field
  1532. if(sDelimChar) {
  1533. if(sSavedQuery) {
  1534. elTextbox.value = sSavedQuery;
  1535. }
  1536. elTextbox.value += sResultKey + sDelimChar;
  1537. if(sDelimChar != " ") {
  1538. elTextbox.value += " ";
  1539. }
  1540. }
  1541. else { elTextbox.value = sResultKey; }
  1542. // scroll to bottom of textarea if necessary
  1543. if(elTextbox.type == "textarea") {
  1544. elTextbox.scrollTop = elTextbox.scrollHeight;
  1545. }
  1546. // move cursor to end
  1547. var end = elTextbox.value.length;
  1548. this._selectText(elTextbox,end,end);
  1549. this._oCurItem = oItem;
  1550. };
  1551. /**
  1552. * Selects a result item from the container
  1553. *
  1554. * @method _selectItem
  1555. * @param oItem {HTMLElement} The selected &lt;li&gt; element item.
  1556. * @private
  1557. */
  1558. YAHOO.widget.AutoComplete.prototype._selectItem = function(oItem) {
  1559. this._bItemSelected = true;
  1560. this._updateValue(oItem);
  1561. this._cancelIntervalDetection(this);
  1562. this.itemSelectEvent.fire(this, oItem, oItem._oResultData);
  1563. YAHOO.log("Item selected: " + YAHOO.lang.dump(oItem._oResultData), "info", this.toString());
  1564. this._toggleContainer(false);
  1565. };
  1566. /**
  1567. * If an item is highlighted in the container, the right arrow key jumps to the
  1568. * end of the textbox and selects the highlighted item, otherwise the container
  1569. * is closed.
  1570. *
  1571. * @method _jumpSelection
  1572. * @private
  1573. */
  1574. YAHOO.widget.AutoComplete.prototype._jumpSelection = function() {
  1575. if(this._oCurItem) {
  1576. this._selectItem(this._oCurItem);
  1577. }
  1578. else {
  1579. this._toggleContainer(false);
  1580. }
  1581. };
  1582. /**
  1583. * Triggered by up and down arrow keys, changes the current highlighted
  1584. * &lt;li&gt; element item. Scrolls container if necessary.
  1585. *
  1586. * @method _moveSelection
  1587. * @param nKeyCode {Number} Code of key pressed.
  1588. * @private
  1589. */
  1590. YAHOO.widget.AutoComplete.prototype._moveSelection = function(nKeyCode) {
  1591. if(this._bContainerOpen) {
  1592. // Determine current item's id number
  1593. var oCurItem = this._oCurItem;
  1594. var nCurItemIndex = -1;
  1595. if(oCurItem) {
  1596. nCurItemIndex = oCurItem._nItemIndex;
  1597. }
  1598. var nNewItemIndex = (nKeyCode == 40) ?
  1599. (nCurItemIndex + 1) : (nCurItemIndex - 1);
  1600. // Out of bounds
  1601. if(nNewItemIndex < -2 || nNewItemIndex >= this._nDisplayedItems) {
  1602. return;
  1603. }
  1604. if(oCurItem) {
  1605. // Unhighlight current item
  1606. this._toggleHighlight(oCurItem, "from");
  1607. this.itemArrowFromEvent.fire(this, oCurItem);
  1608. YAHOO.log("Item arrowed from", "info", this.toString());
  1609. }
  1610. if(nNewItemIndex == -1) {
  1611. // Go back to query (remove type-ahead string)
  1612. if(this.delimChar && this._sSavedQuery) {
  1613. if(!this._textMatchesOption()) {
  1614. this._elTextbox.value = this._sSavedQuery;
  1615. }
  1616. else {
  1617. this._elTextbox.value = this._sSavedQuery + this._sCurQuery;
  1618. }
  1619. }
  1620. else {
  1621. this._elTextbox.value = this._sCurQuery;
  1622. }
  1623. this._oCurItem = null;
  1624. return;
  1625. }
  1626. if(nNewItemIndex == -2) {
  1627. // Close container
  1628. this._toggleContainer(false);
  1629. return;
  1630. }
  1631. var oNewItem = this._aListItems[nNewItemIndex];
  1632. // Scroll the container if necessary
  1633. var elContent = this._elContent;
  1634. var scrollOn = ((YAHOO.util.Dom.getStyle(elContent,"overflow") == "auto") ||
  1635. (YAHOO.util.Dom.getStyle(elContent,"overflowY") == "auto"));
  1636. if(scrollOn && (nNewItemIndex > -1) &&
  1637. (nNewItemIndex < this._nDisplayedItems)) {
  1638. // User is keying down
  1639. if(nKeyCode == 40) {
  1640. // Bottom of selected item is below scroll area...
  1641. if((oNewItem.offsetTop+oNewItem.offsetHeight) > (elContent.scrollTop + elContent.offsetHeight)) {
  1642. // Set bottom of scroll area to bottom of selected item
  1643. elContent.scrollTop = (oNewItem.offsetTop+oNewItem.offsetHeight) - elContent.offsetHeight;
  1644. }
  1645. // Bottom of selected item is above scroll area...
  1646. else if((oNewItem.offsetTop+oNewItem.offsetHeight) < elContent.scrollTop) {
  1647. // Set top of selected item to top of scroll area
  1648. elContent.scrollTop = oNewItem.offsetTop;
  1649. }
  1650. }
  1651. // User is keying up
  1652. else {
  1653. // Top of selected item is above scroll area
  1654. if(oNewItem.offsetTop < elContent.scrollTop) {
  1655. // Set top of scroll area to top of selected item
  1656. this._elContent.scrollTop = oNewItem.offsetTop;
  1657. }
  1658. // Top of selected item is below scroll area
  1659. else if(oNewItem.offsetTop > (elContent.scrollTop + elContent.offsetHeight)) {
  1660. // Set bottom of selected item to bottom of scroll area
  1661. this._elContent.scrollTop = (oNewItem.offsetTop+oNewItem.offsetHeight) - elContent.offsetHeight;
  1662. }
  1663. }
  1664. }
  1665. this._toggleHighlight(oNewItem, "to");
  1666. this.itemArrowToEvent.fire(this, oNewItem);
  1667. YAHOO.log("Item arrowed to", "info", this.toString());
  1668. if(this.typeAhead) {
  1669. this._updateValue(oNewItem);
  1670. }
  1671. }
  1672. };
  1673. /////////////////////////////////////////////////////////////////////////////
  1674. //
  1675. // Private event handlers
  1676. //
  1677. /////////////////////////////////////////////////////////////////////////////
  1678. /**
  1679. * Handles &lt;li&gt; element mouseover events in the container.
  1680. *
  1681. * @method _onItemMouseover
  1682. * @param v {HTMLEvent} The mouseover event.
  1683. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  1684. * @private
  1685. */
  1686. YAHOO.widget.AutoComplete.prototype._onItemMouseover = function(v,oSelf) {
  1687. if(oSelf.prehighlightClassName) {
  1688. oSelf._togglePrehighlight(this,"mouseover");
  1689. }
  1690. else {
  1691. oSelf._toggleHighlight(this,"to");
  1692. }
  1693. oSelf.itemMouseOverEvent.fire(oSelf, this);
  1694. YAHOO.log("Item moused over", "info", oSelf.toString());
  1695. };
  1696. /**
  1697. * Handles &lt;li&gt; element mouseout events in the container.
  1698. *
  1699. * @method _onItemMouseout
  1700. * @param v {HTMLEvent} The mouseout event.
  1701. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  1702. * @private
  1703. */
  1704. YAHOO.widget.AutoComplete.prototype._onItemMouseout = function(v,oSelf) {
  1705. if(oSelf.prehighlightClassName) {
  1706. oSelf._togglePrehighlight(this,"mouseout");
  1707. }
  1708. else {
  1709. oSelf._toggleHighlight(this,"from");
  1710. }
  1711. oSelf.itemMouseOutEvent.fire(oSelf, this);
  1712. YAHOO.log("Item moused out", "info", oSelf.toString());
  1713. };
  1714. /**
  1715. * Handles &lt;li&gt; element click events in the container.
  1716. *
  1717. * @method _onItemMouseclick
  1718. * @param v {HTMLEvent} The click event.
  1719. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  1720. * @private
  1721. */
  1722. YAHOO.widget.AutoComplete.prototype._onItemMouseclick = function(v,oSelf) {
  1723. // In case item has not been moused over
  1724. oSelf._toggleHighlight(this,"to");
  1725. oSelf._selectItem(this);
  1726. };
  1727. /**
  1728. * Handles container mouseover events.
  1729. *
  1730. * @method _onContainerMouseover
  1731. * @param v {HTMLEvent} The mouseover event.
  1732. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  1733. * @private
  1734. */
  1735. YAHOO.widget.AutoComplete.prototype._onContainerMouseover = function(v,oSelf) {
  1736. oSelf._bOverContainer = true;
  1737. };
  1738. /**
  1739. * Handles container mouseout events.
  1740. *
  1741. * @method _onContainerMouseout
  1742. * @param v {HTMLEvent} The mouseout event.
  1743. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  1744. * @private
  1745. */
  1746. YAHOO.widget.AutoComplete.prototype._onContainerMouseout = function(v,oSelf) {
  1747. oSelf._bOverContainer = false;
  1748. // If container is still active
  1749. if(oSelf._oCurItem) {
  1750. oSelf._toggleHighlight(oSelf._oCurItem,"to");
  1751. }
  1752. };
  1753. /**
  1754. * Handles container scroll events.
  1755. *
  1756. * @method _onContainerScroll
  1757. * @param v {HTMLEvent} The scroll event.
  1758. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  1759. * @private
  1760. */
  1761. YAHOO.widget.AutoComplete.prototype._onContainerScroll = function(v,oSelf) {
  1762. oSelf._elTextbox.focus();
  1763. };
  1764. /**
  1765. * Handles container resize events.
  1766. *
  1767. * @method _onContainerResize
  1768. * @param v {HTMLEvent} The resize event.
  1769. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  1770. * @private
  1771. */
  1772. YAHOO.widget.AutoComplete.prototype._onContainerResize = function(v,oSelf) {
  1773. oSelf._toggleContainerHelpers(oSelf._bContainerOpen);
  1774. };
  1775. /**
  1776. * Handles textbox keydown events of functional keys, mainly for UI behavior.
  1777. *
  1778. * @method _onTextboxKeyDown
  1779. * @param v {HTMLEvent} The keydown event.
  1780. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  1781. * @private
  1782. */
  1783. YAHOO.widget.AutoComplete.prototype._onTextboxKeyDown = function(v,oSelf) {
  1784. var nKeyCode = v.keyCode;
  1785. switch (nKeyCode) {
  1786. case 9: // tab
  1787. // select an item or clear out
  1788. if(oSelf._oCurItem) {
  1789. if(oSelf.delimChar && (oSelf._nKeyCode != nKeyCode)) {
  1790. if(oSelf._bContainerOpen) {
  1791. YAHOO.util.Event.stopEvent(v);
  1792. }
  1793. }
  1794. oSelf._selectItem(oSelf._oCurItem);
  1795. }
  1796. else {
  1797. oSelf._toggleContainer(false);
  1798. }
  1799. break;
  1800. case 13: // enter
  1801. if(!YAHOO.env.ua.webkit) {
  1802. if(oSelf._oCurItem) {
  1803. if(oSelf._nKeyCode != nKeyCode) {
  1804. if(oSelf._bContainerOpen) {
  1805. YAHOO.util.Event.stopEvent(v);
  1806. }
  1807. }
  1808. oSelf._selectItem(oSelf._oCurItem);
  1809. }
  1810. else {
  1811. oSelf._toggleContainer(false);
  1812. }
  1813. }
  1814. break;
  1815. case 27: // esc
  1816. oSelf._toggleContainer(false);
  1817. return;
  1818. case 39: // right
  1819. oSelf._jumpSelection();
  1820. break;
  1821. case 38: // up
  1822. YAHOO.util.Event.stopEvent(v);
  1823. oSelf._moveSelection(nKeyCode);
  1824. break;
  1825. case 40: // down
  1826. YAHOO.util.Event.stopEvent(v);
  1827. oSelf._moveSelection(nKeyCode);
  1828. break;
  1829. default:
  1830. break;
  1831. }
  1832. };
  1833. /**
  1834. * Handles textbox keypress events.
  1835. * @method _onTextboxKeyPress
  1836. * @param v {HTMLEvent} The keypress event.
  1837. * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance.
  1838. * @private
  1839. */
  1840. YAHOO.widget.AutoComplete.prototype._onTextboxKeyPress = function(v,oSelf) {
  1841. var nKeyCode = v.keyCode;
  1842. //Expose only to Mac browsers, where stopEvent is ineffective on keydown events (bug 790337)
  1843. if(YAHOO.env.ua.webkit) {
  1844. switch (nKeyCode) {
  1845. case 9: // tab
  1846. if(oSelf._oCurItem) {
  1847. if(oSelf.delimChar && (oSelf._nKeyCode != nKeyCode)) {
  1848. YAHOO.util.Event.stopEvent(v);
  1849. }
  1850. }
  1851. break;
  1852. case 13: // enter
  1853. if(oSelf._oCurItem) {
  1854. if(oSelf._nKeyCode != nKeyCode) {
  1855. if(oSelf._bContainerOpen) {
  1856. YAHOO.util.Event.stopEvent