PageRenderTime 67ms CodeModel.GetById 13ms app.highlight 43ms RepoModel.GetById 1ms app.codeStats 1ms

/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

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file