From 3fe3fdbab1dc113bcaf1e50a17ab793941aef0ef Mon Sep 17 00:00:00 2001 From: Owen Leonard Date: Fri, 1 Jun 2012 10:09:30 -0400 Subject: [PATCH] [SIGNED-OFF] Bug 7747 [FOLLOW-UP] Replace YUI autocomplete with jQueryUI This patch removes the template calls to the now-obsolete YUI JS dependencies and removes the relevant YUI files themselves. First two work perfectly, circulation search header and overdues patron authorized value. Authorities search does not seem to work, old yui file are still referenced in auth_finder.tt. The jquery works, but data set is not found, or I messed up my authority record. Signed-off-by: Koha --- .../prog/en/includes/doc-head-close.inc | 4 - .../yui/autocomplete/assets/autocomplete-core.css | 7 - .../assets/skins/sam/autocomplete-skin.css | 57 - .../autocomplete/assets/skins/sam/autocomplete.css | 7 - .../en/lib/yui/autocomplete/autocomplete-debug.js | 3009 ------------------- .../en/lib/yui/autocomplete/autocomplete-min.js | 12 - .../prog/en/lib/yui/autocomplete/autocomplete.js | 2966 ------------------- .../prog/en/lib/yui/datasource/datasource-debug.js | 3067 -------------------- .../prog/en/lib/yui/datasource/datasource-min.js | 12 - .../prog/en/lib/yui/datasource/datasource.js | 2996 ------------------- 10 files changed, 0 insertions(+), 12137 deletions(-) delete mode 100644 koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/assets/autocomplete-core.css delete mode 100644 koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/assets/skins/sam/autocomplete-skin.css delete mode 100644 koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/assets/skins/sam/autocomplete.css delete mode 100644 koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/autocomplete-debug.js delete mode 100644 koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/autocomplete-min.js delete mode 100644 koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/autocomplete.js delete mode 100644 koha-tmpl/intranet-tmpl/prog/en/lib/yui/datasource/datasource-debug.js delete mode 100644 koha-tmpl/intranet-tmpl/prog/en/lib/yui/datasource/datasource-min.js delete mode 100644 koha-tmpl/intranet-tmpl/prog/en/lib/yui/datasource/datasource.js diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/doc-head-close.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/doc-head-close.inc index 4d83a5b..5db90b9 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/doc-head-close.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/doc-head-close.inc @@ -29,10 +29,6 @@ - -[% IF ( CircAutocompl ) %] - -[% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/assets/autocomplete-core.css b/koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/assets/autocomplete-core.css deleted file mode 100644 index 8143532..0000000 --- a/koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/assets/autocomplete-core.css +++ /dev/null @@ -1,7 +0,0 @@ -/* -Copyright (c) 2009, Yahoo! Inc. All rights reserved. -Code licensed under the BSD License: -http://developer.yahoo.net/yui/license.txt -version: 2.8.0r4 -*/ -/* This file intentionally left blank */ diff --git a/koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/assets/skins/sam/autocomplete-skin.css b/koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/assets/skins/sam/autocomplete-skin.css deleted file mode 100644 index 805530e..0000000 --- a/koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/assets/skins/sam/autocomplete-skin.css +++ /dev/null @@ -1,57 +0,0 @@ -/* -Copyright (c) 2009, Yahoo! Inc. All rights reserved. -Code licensed under the BSD License: -http://developer.yahoo.net/yui/license.txt -version: 2.8.0r4 -*/ -/* styles for entire widget */ -.yui-skin-sam .yui-ac { - position:relative;font-family:arial;font-size:100%; -} - -/* styles for input field */ -.yui-skin-sam .yui-ac-input { - position:absolute;width:100%; -} - -/* styles for results container */ -.yui-skin-sam .yui-ac-container { - position:absolute;top:1.6em;width:100%; -} - -/* styles for header/body/footer wrapper within container */ -.yui-skin-sam .yui-ac-content { - position:absolute;width:100%;border:1px solid #808080;background:#fff;overflow:hidden;z-index:9050; -} - -/* styles for container shadow */ -.yui-skin-sam .yui-ac-shadow { - position:absolute;margin:.3em;width:100%;background:#000;-moz-opacity: 0.10;opacity:.10;filter:alpha(opacity=10);z-index:9049; -} - -/* styles for container iframe */ -.yui-skin-sam .yui-ac iframe { - opacity:0;filter: alpha(opacity=0); - padding-right:.3em; padding-bottom:.3em; /* Bug 2026798: extend iframe to shim the shadow */ -} - -/* styles for results list */ -.yui-skin-sam .yui-ac-content ul{ - margin:0;padding:0;width:100%; -} - -/* styles for result item */ -.yui-skin-sam .yui-ac-content li { - margin:0;padding:2px 5px;cursor:default;white-space:nowrap;list-style:none; - zoom:1; /* For IE to trigger mouse events on LI */ -} - -/* styles for prehighlighted result item */ -.yui-skin-sam .yui-ac-content li.yui-ac-prehighlight { - background:#B3D4FF; -} - -/* styles for highlighted result item */ -.yui-skin-sam .yui-ac-content li.yui-ac-highlight { - background:#426FD9;color:#FFF; -} diff --git a/koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/assets/skins/sam/autocomplete.css b/koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/assets/skins/sam/autocomplete.css deleted file mode 100644 index 07fc030..0000000 --- a/koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/assets/skins/sam/autocomplete.css +++ /dev/null @@ -1,7 +0,0 @@ -/* -Copyright (c) 2009, Yahoo! Inc. All rights reserved. -Code licensed under the BSD License: -http://developer.yahoo.net/yui/license.txt -version: 2.8.0r4 -*/ -.yui-skin-sam .yui-ac{position:relative;font-family:arial;font-size:100%;}.yui-skin-sam .yui-ac-input{position:absolute;width:100%;}.yui-skin-sam .yui-ac-container{position:absolute;top:1.6em;width:100%;}.yui-skin-sam .yui-ac-content{position:absolute;width:100%;border:1px solid #808080;background:#fff;overflow:hidden;z-index:9050;}.yui-skin-sam .yui-ac-shadow{position:absolute;margin:.3em;width:100%;background:#000;-moz-opacity:.10;opacity:.10;filter:alpha(opacity=10);z-index:9049;}.yui-skin-sam .yui-ac iframe{opacity:0;filter:alpha(opacity=0);padding-right:.3em;padding-bottom:.3em;}.yui-skin-sam .yui-ac-content ul{margin:0;padding:0;width:100%;}.yui-skin-sam .yui-ac-content li{margin:0;padding:2px 5px;cursor:default;white-space:nowrap;list-style:none;zoom:1;}.yui-skin-sam .yui-ac-content li.yui-ac-prehighlight{background:#B3D4FF;}.yui-skin-sam .yui-ac-content li.yui-ac-highlight{background:#426FD9;color:#FFF;} diff --git a/koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/autocomplete-debug.js b/koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/autocomplete-debug.js deleted file mode 100644 index 8910282..0000000 --- a/koha-tmpl/intranet-tmpl/prog/en/lib/yui/autocomplete/autocomplete-debug.js +++ /dev/null @@ -1,3009 +0,0 @@ -/* -Copyright (c) 2009, Yahoo! Inc. All rights reserved. -Code licensed under the BSD License: -http://developer.yahoo.net/yui/license.txt -version: 2.8.0r4 -*/ -///////////////////////////////////////////////////////////////////////////// -// -// YAHOO.widget.DataSource Backwards Compatibility -// -///////////////////////////////////////////////////////////////////////////// - -YAHOO.widget.DS_JSArray = YAHOO.util.LocalDataSource; - -YAHOO.widget.DS_JSFunction = YAHOO.util.FunctionDataSource; - -YAHOO.widget.DS_XHR = function(sScriptURI, aSchema, oConfigs) { - var DS = new YAHOO.util.XHRDataSource(sScriptURI, oConfigs); - DS._aDeprecatedSchema = aSchema; - return DS; -}; - -YAHOO.widget.DS_ScriptNode = function(sScriptURI, aSchema, oConfigs) { - var DS = new YAHOO.util.ScriptNodeDataSource(sScriptURI, oConfigs); - DS._aDeprecatedSchema = aSchema; - return DS; -}; - -YAHOO.widget.DS_XHR.TYPE_JSON = YAHOO.util.DataSourceBase.TYPE_JSON; -YAHOO.widget.DS_XHR.TYPE_XML = YAHOO.util.DataSourceBase.TYPE_XML; -YAHOO.widget.DS_XHR.TYPE_FLAT = YAHOO.util.DataSourceBase.TYPE_TEXT; - -// TODO: widget.DS_ScriptNode.scriptCallbackParam - - - - /** - * The AutoComplete control provides the front-end logic for text-entry suggestion and - * completion functionality. - * - * @module autocomplete - * @requires yahoo, dom, event, datasource - * @optional animation - * @namespace YAHOO.widget - * @title AutoComplete Widget - */ - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -/** - * The AutoComplete class provides the customizable functionality of a plug-and-play DHTML - * auto completion widget. Some key features: - * - * - * @class AutoComplete - * @constructor - * @param elInput {HTMLElement} DOM element reference of an input field. - * @param elInput {String} String ID of an input field. - * @param elContainer {HTMLElement} DOM element reference of an existing DIV. - * @param elContainer {String} String ID of an existing DIV. - * @param oDataSource {YAHOO.widget.DataSource} DataSource instance. - * @param oConfigs {Object} (optional) Object literal of configuration params. - */ -YAHOO.widget.AutoComplete = function(elInput,elContainer,oDataSource,oConfigs) { - if(elInput && elContainer && oDataSource) { - // Validate DataSource - if(oDataSource && YAHOO.lang.isFunction(oDataSource.sendRequest)) { - this.dataSource = oDataSource; - } - else { - YAHOO.log("Could not instantiate AutoComplete due to an invalid DataSource", "error", this.toString()); - return; - } - - // YAHOO.widget.DataSource schema backwards compatibility - // Converted deprecated schema into supported schema - // First assume key data is held in position 0 of results array - this.key = 0; - var schema = oDataSource.responseSchema; - // An old school schema has been defined in the deprecated DataSource constructor - if(oDataSource._aDeprecatedSchema) { - var aDeprecatedSchema = oDataSource._aDeprecatedSchema; - if(YAHOO.lang.isArray(aDeprecatedSchema)) { - - if((oDataSource.responseType === YAHOO.util.DataSourceBase.TYPE_JSON) || - (oDataSource.responseType === YAHOO.util.DataSourceBase.TYPE_UNKNOWN)) { // Used to default to unknown - // Store the resultsList - schema.resultsList = aDeprecatedSchema[0]; - // Store the key - this.key = aDeprecatedSchema[1]; - // Only resultsList and key are defined, so grab all the data - schema.fields = (aDeprecatedSchema.length < 3) ? null : aDeprecatedSchema.slice(1); - } - else if(oDataSource.responseType === YAHOO.util.DataSourceBase.TYPE_XML) { - schema.resultNode = aDeprecatedSchema[0]; - this.key = aDeprecatedSchema[1]; - schema.fields = aDeprecatedSchema.slice(1); - } - else if(oDataSource.responseType === YAHOO.util.DataSourceBase.TYPE_TEXT) { - schema.recordDelim = aDeprecatedSchema[0]; - schema.fieldDelim = aDeprecatedSchema[1]; - } - oDataSource.responseSchema = schema; - } - } - - // Validate input element - if(YAHOO.util.Dom.inDocument(elInput)) { - if(YAHOO.lang.isString(elInput)) { - this._sName = "instance" + YAHOO.widget.AutoComplete._nIndex + " " + elInput; - this._elTextbox = document.getElementById(elInput); - } - else { - this._sName = (elInput.id) ? - "instance" + YAHOO.widget.AutoComplete._nIndex + " " + elInput.id: - "instance" + YAHOO.widget.AutoComplete._nIndex; - this._elTextbox = elInput; - } - YAHOO.util.Dom.addClass(this._elTextbox, "yui-ac-input"); - } - else { - YAHOO.log("Could not instantiate AutoComplete due to an invalid input element", "error", this.toString()); - return; - } - - // Validate container element - if(YAHOO.util.Dom.inDocument(elContainer)) { - if(YAHOO.lang.isString(elContainer)) { - this._elContainer = document.getElementById(elContainer); - } - else { - this._elContainer = elContainer; - } - if(this._elContainer.style.display == "none") { - YAHOO.log("The container may not display properly if display is set to \"none\" in CSS", "warn", this.toString()); - } - - // For skinning - var elParent = this._elContainer.parentNode; - var elTag = elParent.tagName.toLowerCase(); - if(elTag == "div") { - YAHOO.util.Dom.addClass(elParent, "yui-ac"); - } - else { - YAHOO.log("Could not find the wrapper element for skinning", "warn", this.toString()); - } - } - else { - YAHOO.log("Could not instantiate AutoComplete due to an invalid container element", "error", this.toString()); - return; - } - - // Default applyLocalFilter setting is to enable for local sources - if(this.dataSource.dataType === YAHOO.util.DataSourceBase.TYPE_LOCAL) { - this.applyLocalFilter = true; - } - - // Set any config params passed in to override defaults - if(oConfigs && (oConfigs.constructor == Object)) { - for(var sConfig in oConfigs) { - if(sConfig) { - this[sConfig] = oConfigs[sConfig]; - } - } - } - - // Initialization sequence - this._initContainerEl(); - this._initProps(); - this._initListEl(); - this._initContainerHelperEls(); - - // Set up events - var oSelf = this; - var elTextbox = this._elTextbox; - - // Dom events - YAHOO.util.Event.addListener(elTextbox,"keyup",oSelf._onTextboxKeyUp,oSelf); - YAHOO.util.Event.addListener(elTextbox,"keydown",oSelf._onTextboxKeyDown,oSelf); - YAHOO.util.Event.addListener(elTextbox,"focus",oSelf._onTextboxFocus,oSelf); - YAHOO.util.Event.addListener(elTextbox,"blur",oSelf._onTextboxBlur,oSelf); - YAHOO.util.Event.addListener(elContainer,"mouseover",oSelf._onContainerMouseover,oSelf); - YAHOO.util.Event.addListener(elContainer,"mouseout",oSelf._onContainerMouseout,oSelf); - YAHOO.util.Event.addListener(elContainer,"click",oSelf._onContainerClick,oSelf); - YAHOO.util.Event.addListener(elContainer,"scroll",oSelf._onContainerScroll,oSelf); - YAHOO.util.Event.addListener(elContainer,"resize",oSelf._onContainerResize,oSelf); - YAHOO.util.Event.addListener(elTextbox,"keypress",oSelf._onTextboxKeyPress,oSelf); - YAHOO.util.Event.addListener(window,"unload",oSelf._onWindowUnload,oSelf); - - // Custom events - this.textboxFocusEvent = new YAHOO.util.CustomEvent("textboxFocus", this); - this.textboxKeyEvent = new YAHOO.util.CustomEvent("textboxKey", this); - this.dataRequestEvent = new YAHOO.util.CustomEvent("dataRequest", this); - this.dataReturnEvent = new YAHOO.util.CustomEvent("dataReturn", this); - this.dataErrorEvent = new YAHOO.util.CustomEvent("dataError", this); - this.containerPopulateEvent = new YAHOO.util.CustomEvent("containerPopulate", this); - this.containerExpandEvent = new YAHOO.util.CustomEvent("containerExpand", this); - this.typeAheadEvent = new YAHOO.util.CustomEvent("typeAhead", this); - this.itemMouseOverEvent = new YAHOO.util.CustomEvent("itemMouseOver", this); - this.itemMouseOutEvent = new YAHOO.util.CustomEvent("itemMouseOut", this); - this.itemArrowToEvent = new YAHOO.util.CustomEvent("itemArrowTo", this); - this.itemArrowFromEvent = new YAHOO.util.CustomEvent("itemArrowFrom", this); - this.itemSelectEvent = new YAHOO.util.CustomEvent("itemSelect", this); - this.unmatchedItemSelectEvent = new YAHOO.util.CustomEvent("unmatchedItemSelect", this); - this.selectionEnforceEvent = new YAHOO.util.CustomEvent("selectionEnforce", this); - this.containerCollapseEvent = new YAHOO.util.CustomEvent("containerCollapse", this); - this.textboxBlurEvent = new YAHOO.util.CustomEvent("textboxBlur", this); - this.textboxChangeEvent = new YAHOO.util.CustomEvent("textboxChange", this); - - // Finish up - elTextbox.setAttribute("autocomplete","off"); - YAHOO.widget.AutoComplete._nIndex++; - YAHOO.log("AutoComplete initialized","info",this.toString()); - } - // Required arguments were not found - else { - YAHOO.log("Could not instantiate AutoComplete due invalid arguments", "error", this.toString()); - } -}; - -///////////////////////////////////////////////////////////////////////////// -// -// Public member variables -// -///////////////////////////////////////////////////////////////////////////// - -/** - * The DataSource object that encapsulates the data used for auto completion. - * This object should be an inherited object from YAHOO.widget.DataSource. - * - * @property dataSource - * @type YAHOO.widget.DataSource - */ -YAHOO.widget.AutoComplete.prototype.dataSource = null; - -/** - * By default, results from local DataSources will pass through the filterResults - * method to apply a client-side matching algorithm. - * - * @property applyLocalFilter - * @type Boolean - * @default true for local arrays and json, otherwise false - */ -YAHOO.widget.AutoComplete.prototype.applyLocalFilter = null; - -/** - * When applyLocalFilter is true, the local filtering algorthim can have case sensitivity - * enabled. - * - * @property queryMatchCase - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.queryMatchCase = false; - -/** - * When applyLocalFilter is true, results can be locally filtered to return - * matching strings that "contain" the query string rather than simply "start with" - * the query string. - * - * @property queryMatchContains - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.queryMatchContains = false; - -/** - * Enables query subset matching. When the DataSource's cache is enabled and queryMatchSubset is - * true, substrings of queries will return matching cached results. For - * instance, if the first query is for "abc" susequent queries that start with - * "abc", like "abcd", will be queried against the cache, and not the live data - * source. Recommended only for DataSources that return comprehensive results - * for queries with very few characters. - * - * @property queryMatchSubset - * @type Boolean - * @default false - * - */ -YAHOO.widget.AutoComplete.prototype.queryMatchSubset = false; - -/** - * Number of characters that must be entered before querying for results. A negative value - * effectively turns off the widget. A value of 0 allows queries of null or empty string - * values. - * - * @property minQueryLength - * @type Number - * @default 1 - */ -YAHOO.widget.AutoComplete.prototype.minQueryLength = 1; - -/** - * Maximum number of results to display in results container. - * - * @property maxResultsDisplayed - * @type Number - * @default 10 - */ -YAHOO.widget.AutoComplete.prototype.maxResultsDisplayed = 10; - -/** - * Number of seconds to delay before submitting a query request. If a query - * request is received before a previous one has completed its delay, the - * previous request is cancelled and the new request is set to the delay. If - * typeAhead is also enabled, this value must always be less than the typeAheadDelay - * in order to avoid certain race conditions. - * - * @property queryDelay - * @type Number - * @default 0.2 - */ -YAHOO.widget.AutoComplete.prototype.queryDelay = 0.2; - -/** - * If typeAhead is true, number of seconds to delay before updating input with - * typeAhead value. In order to prevent certain race conditions, this value must - * always be greater than the queryDelay. - * - * @property typeAheadDelay - * @type Number - * @default 0.5 - */ -YAHOO.widget.AutoComplete.prototype.typeAheadDelay = 0.5; - -/** - * When IME usage is detected or interval detection is explicitly enabled, - * AutoComplete will detect the input value at the given interval and send a - * query if the value has changed. - * - * @property queryInterval - * @type Number - * @default 500 - */ -YAHOO.widget.AutoComplete.prototype.queryInterval = 500; - -/** - * Class name of a highlighted item within results container. - * - * @property highlightClassName - * @type String - * @default "yui-ac-highlight" - */ -YAHOO.widget.AutoComplete.prototype.highlightClassName = "yui-ac-highlight"; - -/** - * Class name of a pre-highlighted item within results container. - * - * @property prehighlightClassName - * @type String - */ -YAHOO.widget.AutoComplete.prototype.prehighlightClassName = null; - -/** - * Query delimiter. A single character separator for multiple delimited - * selections. Multiple delimiter characteres may be defined as an array of - * strings. A null value or empty string indicates that query results cannot - * be delimited. This feature is not recommended if you need forceSelection to - * be true. - * - * @property delimChar - * @type String | String[] - */ -YAHOO.widget.AutoComplete.prototype.delimChar = null; - -/** - * Whether or not the first item in results container should be automatically highlighted - * on expand. - * - * @property autoHighlight - * @type Boolean - * @default true - */ -YAHOO.widget.AutoComplete.prototype.autoHighlight = true; - -/** - * If autohighlight is enabled, whether or not the input field should be automatically updated - * with the first query result as the user types, auto-selecting the substring portion - * of the first result that the user has not yet typed. - * - * @property typeAhead - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.typeAhead = false; - -/** - * Whether or not to animate the expansion/collapse of the results container in the - * horizontal direction. - * - * @property animHoriz - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.animHoriz = false; - -/** - * Whether or not to animate the expansion/collapse of the results container in the - * vertical direction. - * - * @property animVert - * @type Boolean - * @default true - */ -YAHOO.widget.AutoComplete.prototype.animVert = true; - -/** - * Speed of container expand/collapse animation, in seconds.. - * - * @property animSpeed - * @type Number - * @default 0.3 - */ -YAHOO.widget.AutoComplete.prototype.animSpeed = 0.3; - -/** - * Whether or not to force the user's selection to match one of the query - * results. Enabling this feature essentially transforms the input field into a - * <select> field. This feature is not recommended with delimiter character(s) - * defined. - * - * @property forceSelection - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.forceSelection = false; - -/** - * Whether or not to allow browsers to cache user-typed input in the input - * field. Disabling this feature will prevent the widget from setting the - * autocomplete="off" on the input field. When autocomplete="off" - * and users click the back button after form submission, user-typed input can - * be prefilled by the browser from its cache. This caching of user input may - * not be desired for sensitive data, such as credit card numbers, in which - * case, implementers should consider setting allowBrowserAutocomplete to false. - * - * @property allowBrowserAutocomplete - * @type Boolean - * @default true - */ -YAHOO.widget.AutoComplete.prototype.allowBrowserAutocomplete = true; - -/** - * Enabling this feature prevents the toggling of the container to a collapsed state. - * Setting to true does not automatically trigger the opening of the container. - * Implementers are advised to pre-load the container with an explicit "sendQuery()" call. - * - * @property alwaysShowContainer - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.alwaysShowContainer = false; - -/** - * Whether or not to use an iFrame to layer over Windows form elements in - * IE. Set to true only when the results container will be on top of a - * <select> field in IE and thus exposed to the IE z-index bug (i.e., - * 5.5 < IE < 7). - * - * @property useIFrame - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.useIFrame = false; - -/** - * Whether or not the results container should have a shadow. - * - * @property useShadow - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.useShadow = false; - -/** - * Whether or not the input field should be updated with selections. - * - * @property suppressInputUpdate - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.suppressInputUpdate = false; - -/** - * For backward compatibility to pre-2.6.0 formatResults() signatures, setting - * resultsTypeList to true will take each object literal result returned by - * DataSource and flatten into an array. - * - * @property resultTypeList - * @type Boolean - * @default true - */ -YAHOO.widget.AutoComplete.prototype.resultTypeList = true; - -/** - * For XHR DataSources, AutoComplete will automatically insert a "?" between the server URI and - * the "query" param/value pair. To prevent this behavior, implementers should - * set this value to false. To more fully customize the query syntax, implementers - * should override the generateRequest() method. - * - * @property queryQuestionMark - * @type Boolean - * @default true - */ -YAHOO.widget.AutoComplete.prototype.queryQuestionMark = true; - -/** - * If true, before each time the container expands, the container element will be - * positioned to snap to the bottom-left corner of the input element. If - * autoSnapContainer is set to false, this positioning will not be done. - * - * @property autoSnapContainer - * @type Boolean - * @default true - */ -YAHOO.widget.AutoComplete.prototype.autoSnapContainer = true; - -///////////////////////////////////////////////////////////////////////////// -// -// Public methods -// -///////////////////////////////////////////////////////////////////////////// - - /** - * Public accessor to the unique name of the AutoComplete instance. - * - * @method toString - * @return {String} Unique name of the AutoComplete instance. - */ -YAHOO.widget.AutoComplete.prototype.toString = function() { - return "AutoComplete " + this._sName; -}; - - /** - * Returns DOM reference to input element. - * - * @method getInputEl - * @return {HTMLELement} DOM reference to input element. - */ -YAHOO.widget.AutoComplete.prototype.getInputEl = function() { - return this._elTextbox; -}; - - /** - * Returns DOM reference to container element. - * - * @method getContainerEl - * @return {HTMLELement} DOM reference to container element. - */ -YAHOO.widget.AutoComplete.prototype.getContainerEl = function() { - return this._elContainer; -}; - - /** - * Returns true if widget instance is currently active. - * - * @method isFocused - * @return {Boolean} Returns true if widget instance is currently active. - */ -YAHOO.widget.AutoComplete.prototype.isFocused = function() { - return this._bFocused; -}; - - /** - * Returns true if container is in an expanded state, false otherwise. - * - * @method isContainerOpen - * @return {Boolean} Returns true if container is in an expanded state, false otherwise. - */ -YAHOO.widget.AutoComplete.prototype.isContainerOpen = function() { - return this._bContainerOpen; -}; - -/** - * Public accessor to the <ul> element that displays query results within the results container. - * - * @method getListEl - * @return {HTMLElement[]} Reference to <ul> element within the results container. - */ -YAHOO.widget.AutoComplete.prototype.getListEl = function() { - return this._elList; -}; - -/** - * Public accessor to the matching string associated with a given <li> result. - * - * @method getListItemMatch - * @param elListItem {HTMLElement} Reference to <LI> element. - * @return {String} Matching string. - */ -YAHOO.widget.AutoComplete.prototype.getListItemMatch = function(elListItem) { - if(elListItem._sResultMatch) { - return elListItem._sResultMatch; - } - else { - return null; - } -}; - -/** - * Public accessor to the result data associated with a given <li> result. - * - * @method getListItemData - * @param elListItem {HTMLElement} Reference to <LI> element. - * @return {Object} Result data. - */ -YAHOO.widget.AutoComplete.prototype.getListItemData = function(elListItem) { - if(elListItem._oResultData) { - return elListItem._oResultData; - } - else { - return null; - } -}; - -/** - * Public accessor to the index of the associated with a given <li> result. - * - * @method getListItemIndex - * @param elListItem {HTMLElement} Reference to <LI> element. - * @return {Number} Index. - */ -YAHOO.widget.AutoComplete.prototype.getListItemIndex = function(elListItem) { - if(YAHOO.lang.isNumber(elListItem._nItemIndex)) { - return elListItem._nItemIndex; - } - else { - return null; - } -}; - -/** - * Sets HTML markup for the results container header. This markup will be - * inserted within a <div> tag with a class of "yui-ac-hd". - * - * @method setHeader - * @param sHeader {String} HTML markup for results container header. - */ -YAHOO.widget.AutoComplete.prototype.setHeader = function(sHeader) { - if(this._elHeader) { - var elHeader = this._elHeader; - if(sHeader) { - elHeader.innerHTML = sHeader; - elHeader.style.display = ""; - } - else { - elHeader.innerHTML = ""; - elHeader.style.display = "none"; - } - } -}; - -/** - * Sets HTML markup for the results container footer. This markup will be - * inserted within a <div> tag with a class of "yui-ac-ft". - * - * @method setFooter - * @param sFooter {String} HTML markup for results container footer. - */ -YAHOO.widget.AutoComplete.prototype.setFooter = function(sFooter) { - if(this._elFooter) { - var elFooter = this._elFooter; - if(sFooter) { - elFooter.innerHTML = sFooter; - elFooter.style.display = ""; - } - else { - elFooter.innerHTML = ""; - elFooter.style.display = "none"; - } - } -}; - -/** - * Sets HTML markup for the results container body. This markup will be - * inserted within a <div> tag with a class of "yui-ac-bd". - * - * @method setBody - * @param sBody {String} HTML markup for results container body. - */ -YAHOO.widget.AutoComplete.prototype.setBody = function(sBody) { - if(this._elBody) { - var elBody = this._elBody; - YAHOO.util.Event.purgeElement(elBody, true); - if(sBody) { - elBody.innerHTML = sBody; - elBody.style.display = ""; - } - else { - elBody.innerHTML = ""; - elBody.style.display = "none"; - } - this._elList = null; - } -}; - -/** -* A function that converts an AutoComplete query into a request value which is then -* passed to the DataSource's sendRequest method in order to retrieve data for -* the query. By default, returns a String with the syntax: "query={query}" -* Implementers can customize this method for custom request syntaxes. -* -* @method generateRequest -* @param sQuery {String} Query string -* @return {MIXED} Request -*/ -YAHOO.widget.AutoComplete.prototype.generateRequest = function(sQuery) { - var dataType = this.dataSource.dataType; - - // Transform query string in to a request for remote data - // By default, local data doesn't need a transformation, just passes along the query as is. - if(dataType === YAHOO.util.DataSourceBase.TYPE_XHR) { - // By default, XHR GET requests look like "{scriptURI}?{scriptQueryParam}={sQuery}&{scriptQueryAppend}" - if(!this.dataSource.connMethodPost) { - sQuery = (this.queryQuestionMark ? "?" : "") + (this.dataSource.scriptQueryParam || "query") + "=" + sQuery + - (this.dataSource.scriptQueryAppend ? ("&" + this.dataSource.scriptQueryAppend) : ""); - } - // By default, XHR POST bodies are sent to the {scriptURI} like "{scriptQueryParam}={sQuery}&{scriptQueryAppend}" - else { - sQuery = (this.dataSource.scriptQueryParam || "query") + "=" + sQuery + - (this.dataSource.scriptQueryAppend ? ("&" + this.dataSource.scriptQueryAppend) : ""); - } - } - // By default, remote script node requests look like "{scriptURI}&{scriptCallbackParam}={callbackString}&{scriptQueryParam}={sQuery}&{scriptQueryAppend}" - else if(dataType === YAHOO.util.DataSourceBase.TYPE_SCRIPTNODE) { - sQuery = "&" + (this.dataSource.scriptQueryParam || "query") + "=" + sQuery + - (this.dataSource.scriptQueryAppend ? ("&" + this.dataSource.scriptQueryAppend) : ""); - } - - return sQuery; -}; - -/** - * Makes query request to the DataSource. - * - * @method sendQuery - * @param sQuery {String} Query string. - */ -YAHOO.widget.AutoComplete.prototype.sendQuery = function(sQuery) { - // Activate focus for a new interaction - this._bFocused = true; - - // Adjust programatically sent queries to look like they were input by user - // when delimiters are enabled - var newQuery = (this.delimChar) ? this._elTextbox.value + sQuery : sQuery; - this._sendQuery(newQuery); -}; - -/** - * Snaps container to bottom-left corner of input element - * - * @method snapContainer - */ -YAHOO.widget.AutoComplete.prototype.snapContainer = function() { - var oTextbox = this._elTextbox, - pos = YAHOO.util.Dom.getXY(oTextbox); - pos[1] += YAHOO.util.Dom.get(oTextbox).offsetHeight + 2; - YAHOO.util.Dom.setXY(this._elContainer,pos); -}; - -/** - * Expands container. - * - * @method expandContainer - */ -YAHOO.widget.AutoComplete.prototype.expandContainer = function() { - this._toggleContainer(true); -}; - -/** - * Collapses container. - * - * @method collapseContainer - */ -YAHOO.widget.AutoComplete.prototype.collapseContainer = function() { - this._toggleContainer(false); -}; - -/** - * Clears entire list of suggestions. - * - * @method clearList - */ -YAHOO.widget.AutoComplete.prototype.clearList = function() { - var allItems = this._elList.childNodes, - i=allItems.length-1; - for(; i>-1; i--) { - allItems[i].style.display = "none"; - } -}; - -/** - * Handles subset matching for when queryMatchSubset is enabled. - * - * @method getSubsetMatches - * @param sQuery {String} Query string. - * @return {Object} oParsedResponse or null. - */ -YAHOO.widget.AutoComplete.prototype.getSubsetMatches = function(sQuery) { - var subQuery, oCachedResponse, subRequest; - // Loop through substrings of each cached element's query property... - for(var i = sQuery.length; i >= this.minQueryLength ; i--) { - subRequest = this.generateRequest(sQuery.substr(0,i)); - this.dataRequestEvent.fire(this, subQuery, subRequest); - YAHOO.log("Searching for query subset \"" + subQuery + "\" in cache", "info", this.toString()); - - // If a substring of the query is found in the cache - oCachedResponse = this.dataSource.getCachedResponse(subRequest); - if(oCachedResponse) { - YAHOO.log("Found match for query subset \"" + subQuery + "\": " + YAHOO.lang.dump(oCachedResponse), "info", this.toString()); - return this.filterResults.apply(this.dataSource, [sQuery, oCachedResponse, oCachedResponse, {scope:this}]); - } - } - YAHOO.log("Did not find subset match for query subset \"" + sQuery + "\"" , "info", this.toString()); - return null; -}; - -/** - * Executed by DataSource (within DataSource scope via doBeforeParseData()) to - * handle responseStripAfter cleanup. - * - * @method preparseRawResponse - * @param sQuery {String} Query string. - * @return {Object} oParsedResponse or null. - */ -YAHOO.widget.AutoComplete.prototype.preparseRawResponse = function(oRequest, oFullResponse, oCallback) { - var nEnd = ((this.responseStripAfter !== "") && (oFullResponse.indexOf)) ? - oFullResponse.indexOf(this.responseStripAfter) : -1; - if(nEnd != -1) { - oFullResponse = oFullResponse.substring(0,nEnd); - } - return oFullResponse; -}; - -/** - * Executed by DataSource (within DataSource scope via doBeforeCallback()) to - * filter results through a simple client-side matching algorithm. - * - * @method filterResults - * @param sQuery {String} Original request. - * @param oFullResponse {Object} Full response object. - * @param oParsedResponse {Object} Parsed response object. - * @param oCallback {Object} Callback object. - * @return {Object} Filtered response object. - */ - -YAHOO.widget.AutoComplete.prototype.filterResults = function(sQuery, oFullResponse, oParsedResponse, oCallback) { - // If AC has passed a query string value back to itself, grab it - if(oCallback && oCallback.argument && oCallback.argument.query) { - sQuery = oCallback.argument.query; - } - - // Only if a query string is available to match against - if(sQuery && sQuery !== "") { - // First make a copy of the oParseResponse - oParsedResponse = YAHOO.widget.AutoComplete._cloneObject(oParsedResponse); - - var oAC = oCallback.scope, - oDS = this, - allResults = oParsedResponse.results, // the array of results - filteredResults = [], // container for filtered results, - nMax = oAC.maxResultsDisplayed, // max to find - bMatchCase = (oDS.queryMatchCase || oAC.queryMatchCase), // backward compat - bMatchContains = (oDS.queryMatchContains || oAC.queryMatchContains); // backward compat - - // Loop through each result object... - for(var i=0, len=allResults.length; i -1))) { - // Stash the match - filteredResults.push(oResult); - } - } - - // Filter no more if maxResultsDisplayed is reached - if(len>nMax && filteredResults.length===nMax) { - break; - } - } - oParsedResponse.results = filteredResults; - YAHOO.log("Filtered " + filteredResults.length + " results against query \"" + sQuery + "\": " + YAHOO.lang.dump(filteredResults), "info", this.toString()); - } - else { - YAHOO.log("Did not filter results against query", "info", this.toString()); - } - - return oParsedResponse; -}; - -/** - * Handles response for display. This is the callback function method passed to - * YAHOO.util.DataSourceBase#sendRequest so results from the DataSource are - * returned to the AutoComplete instance. - * - * @method handleResponse - * @param sQuery {String} Original request. - * @param oResponse {Object} Response object. - * @param oPayload {MIXED} (optional) Additional argument(s) - */ -YAHOO.widget.AutoComplete.prototype.handleResponse = function(sQuery, oResponse, oPayload) { - if((this instanceof YAHOO.widget.AutoComplete) && this._sName) { - this._populateList(sQuery, oResponse, oPayload); - } -}; - -/** - * Overridable method called before container is loaded with result data. - * - * @method doBeforeLoadData - * @param sQuery {String} Original request. - * @param oResponse {Object} Response object. - * @param oPayload {MIXED} (optional) Additional argument(s) - * @return {Boolean} Return true to continue loading data, false to cancel. - */ -YAHOO.widget.AutoComplete.prototype.doBeforeLoadData = function(sQuery, oResponse, oPayload) { - return true; -}; - -/** - * Overridable method that returns HTML markup for one result to be populated - * as innerHTML of an <LI> element. - * - * @method formatResult - * @param oResultData {Object} Result data object. - * @param sQuery {String} The corresponding query string. - * @param sResultMatch {HTMLElement} The current query string. - * @return {String} HTML markup of formatted result data. - */ -YAHOO.widget.AutoComplete.prototype.formatResult = function(oResultData, sQuery, sResultMatch) { - var sMarkup = (sResultMatch) ? sResultMatch : ""; - return sMarkup; -}; - -/** - * Overridable method called before container expands allows implementers to access data - * and DOM elements. - * - * @method doBeforeExpandContainer - * @param elTextbox {HTMLElement} The text input box. - * @param elContainer {HTMLElement} The container element. - * @param sQuery {String} The query string. - * @param aResults {Object[]} An array of query results. - * @return {Boolean} Return true to continue expanding container, false to cancel the expand. - */ -YAHOO.widget.AutoComplete.prototype.doBeforeExpandContainer = function(elTextbox, elContainer, sQuery, aResults) { - return true; -}; - - -/** - * Nulls out the entire AutoComplete instance and related objects, removes attached - * event listeners, and clears out DOM elements inside the container. After - * calling this method, the instance reference should be expliclitly nulled by - * implementer, as in myAutoComplete = null. Use with caution! - * - * @method destroy - */ -YAHOO.widget.AutoComplete.prototype.destroy = function() { - var instanceName = this.toString(); - var elInput = this._elTextbox; - var elContainer = this._elContainer; - - // Unhook custom events - this.textboxFocusEvent.unsubscribeAll(); - this.textboxKeyEvent.unsubscribeAll(); - this.dataRequestEvent.unsubscribeAll(); - this.dataReturnEvent.unsubscribeAll(); - this.dataErrorEvent.unsubscribeAll(); - this.containerPopulateEvent.unsubscribeAll(); - this.containerExpandEvent.unsubscribeAll(); - this.typeAheadEvent.unsubscribeAll(); - this.itemMouseOverEvent.unsubscribeAll(); - this.itemMouseOutEvent.unsubscribeAll(); - this.itemArrowToEvent.unsubscribeAll(); - this.itemArrowFromEvent.unsubscribeAll(); - this.itemSelectEvent.unsubscribeAll(); - this.unmatchedItemSelectEvent.unsubscribeAll(); - this.selectionEnforceEvent.unsubscribeAll(); - this.containerCollapseEvent.unsubscribeAll(); - this.textboxBlurEvent.unsubscribeAll(); - this.textboxChangeEvent.unsubscribeAll(); - - // Unhook DOM events - YAHOO.util.Event.purgeElement(elInput, true); - YAHOO.util.Event.purgeElement(elContainer, true); - - // Remove DOM elements - elContainer.innerHTML = ""; - - // Null out objects - for(var key in this) { - if(YAHOO.lang.hasOwnProperty(this, key)) { - this[key] = null; - } - } - - YAHOO.log("AutoComplete instance destroyed: " + instanceName); -}; - -///////////////////////////////////////////////////////////////////////////// -// -// Public events -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Fired when the input field receives focus. - * - * @event textboxFocusEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - */ -YAHOO.widget.AutoComplete.prototype.textboxFocusEvent = null; - -/** - * Fired when the input field receives key input. - * - * @event textboxKeyEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param nKeycode {Number} The keycode number. - */ -YAHOO.widget.AutoComplete.prototype.textboxKeyEvent = null; - -/** - * Fired when the AutoComplete instance makes a request to the DataSource. - * - * @event dataRequestEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param sQuery {String} The query string. - * @param oRequest {Object} The request. - */ -YAHOO.widget.AutoComplete.prototype.dataRequestEvent = null; - -/** - * Fired when the AutoComplete instance receives query results from the data - * source. - * - * @event dataReturnEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param sQuery {String} The query string. - * @param aResults {Object[]} Results array. - */ -YAHOO.widget.AutoComplete.prototype.dataReturnEvent = null; - -/** - * Fired when the AutoComplete instance does not receive query results from the - * DataSource due to an error. - * - * @event dataErrorEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param sQuery {String} The query string. - * @param oResponse {Object} The response object, if available. - */ -YAHOO.widget.AutoComplete.prototype.dataErrorEvent = null; - -/** - * Fired when the results container is populated. - * - * @event containerPopulateEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - */ -YAHOO.widget.AutoComplete.prototype.containerPopulateEvent = null; - -/** - * Fired when the results container is expanded. - * - * @event containerExpandEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - */ -YAHOO.widget.AutoComplete.prototype.containerExpandEvent = null; - -/** - * Fired when the input field has been prefilled by the type-ahead - * feature. - * - * @event typeAheadEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param sQuery {String} The query string. - * @param sPrefill {String} The prefill string. - */ -YAHOO.widget.AutoComplete.prototype.typeAheadEvent = null; - -/** - * Fired when result item has been moused over. - * - * @event itemMouseOverEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param elItem {HTMLElement} The <li> element item moused to. - */ -YAHOO.widget.AutoComplete.prototype.itemMouseOverEvent = null; - -/** - * Fired when result item has been moused out. - * - * @event itemMouseOutEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param elItem {HTMLElement} The <li> element item moused from. - */ -YAHOO.widget.AutoComplete.prototype.itemMouseOutEvent = null; - -/** - * Fired when result item has been arrowed to. - * - * @event itemArrowToEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param elItem {HTMLElement} The <li> element item arrowed to. - */ -YAHOO.widget.AutoComplete.prototype.itemArrowToEvent = null; - -/** - * Fired when result item has been arrowed away from. - * - * @event itemArrowFromEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param elItem {HTMLElement} The <li> element item arrowed from. - */ -YAHOO.widget.AutoComplete.prototype.itemArrowFromEvent = null; - -/** - * Fired when an item is selected via mouse click, ENTER key, or TAB key. - * - * @event itemSelectEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param elItem {HTMLElement} The selected <li> element item. - * @param oData {Object} The data returned for the item, either as an object, - * or mapped from the schema into an array. - */ -YAHOO.widget.AutoComplete.prototype.itemSelectEvent = null; - -/** - * Fired when a user selection does not match any of the displayed result items. - * - * @event unmatchedItemSelectEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param sSelection {String} The selected string. - */ -YAHOO.widget.AutoComplete.prototype.unmatchedItemSelectEvent = null; - -/** - * Fired if forceSelection is enabled and the user's input has been cleared - * because it did not match one of the returned query results. - * - * @event selectionEnforceEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param sClearedValue {String} The cleared value (including delimiters if applicable). - */ -YAHOO.widget.AutoComplete.prototype.selectionEnforceEvent = null; - -/** - * Fired when the results container is collapsed. - * - * @event containerCollapseEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - */ -YAHOO.widget.AutoComplete.prototype.containerCollapseEvent = null; - -/** - * Fired when the input field loses focus. - * - * @event textboxBlurEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - */ -YAHOO.widget.AutoComplete.prototype.textboxBlurEvent = null; - -/** - * Fired when the input field value has changed when it loses focus. - * - * @event textboxChangeEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - */ -YAHOO.widget.AutoComplete.prototype.textboxChangeEvent = null; - -///////////////////////////////////////////////////////////////////////////// -// -// Private member variables -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Internal class variable to index multiple AutoComplete instances. - * - * @property _nIndex - * @type Number - * @default 0 - * @private - */ -YAHOO.widget.AutoComplete._nIndex = 0; - -/** - * Name of AutoComplete instance. - * - * @property _sName - * @type String - * @private - */ -YAHOO.widget.AutoComplete.prototype._sName = null; - -/** - * Text input field DOM element. - * - * @property _elTextbox - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elTextbox = null; - -/** - * Container DOM element. - * - * @property _elContainer - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elContainer = null; - -/** - * Reference to content element within container element. - * - * @property _elContent - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elContent = null; - -/** - * Reference to header element within content element. - * - * @property _elHeader - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elHeader = null; - -/** - * Reference to body element within content element. - * - * @property _elBody - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elBody = null; - -/** - * Reference to footer element within content element. - * - * @property _elFooter - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elFooter = null; - -/** - * Reference to shadow element within container element. - * - * @property _elShadow - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elShadow = null; - -/** - * Reference to iframe element within container element. - * - * @property _elIFrame - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elIFrame = null; - -/** - * Whether or not the widget instance is currently active. If query results come back - * but the user has already moved on, do not proceed with auto complete behavior. - * - * @property _bFocused - * @type Boolean - * @private - */ -YAHOO.widget.AutoComplete.prototype._bFocused = false; - -/** - * Animation instance for container expand/collapse. - * - * @property _oAnim - * @type Boolean - * @private - */ -YAHOO.widget.AutoComplete.prototype._oAnim = null; - -/** - * Whether or not the results container is currently open. - * - * @property _bContainerOpen - * @type Boolean - * @private - */ -YAHOO.widget.AutoComplete.prototype._bContainerOpen = false; - -/** - * Whether or not the mouse is currently over the results - * container. This is necessary in order to prevent clicks on container items - * from being text input field blur events. - * - * @property _bOverContainer - * @type Boolean - * @private - */ -YAHOO.widget.AutoComplete.prototype._bOverContainer = false; - -/** - * Internal reference to <ul> elements that contains query results within the - * results container. - * - * @property _elList - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elList = null; - -/* - * Array of <li> elements references that contain query results within the - * results container. - * - * @property _aListItemEls - * @type HTMLElement[] - * @private - */ -//YAHOO.widget.AutoComplete.prototype._aListItemEls = null; - -/** - * Number of <li> elements currently displayed in results container. - * - * @property _nDisplayedItems - * @type Number - * @private - */ -YAHOO.widget.AutoComplete.prototype._nDisplayedItems = 0; - -/* - * Internal count of <li> elements displayed and hidden in results container. - * - * @property _maxResultsDisplayed - * @type Number - * @private - */ -//YAHOO.widget.AutoComplete.prototype._maxResultsDisplayed = 0; - -/** - * Current query string - * - * @property _sCurQuery - * @type String - * @private - */ -YAHOO.widget.AutoComplete.prototype._sCurQuery = null; - -/** - * Selections from previous queries (for saving delimited queries). - * - * @property _sPastSelections - * @type String - * @default "" - * @private - */ -YAHOO.widget.AutoComplete.prototype._sPastSelections = ""; - -/** - * Stores initial input value used to determine if textboxChangeEvent should be fired. - * - * @property _sInitInputValue - * @type String - * @private - */ -YAHOO.widget.AutoComplete.prototype._sInitInputValue = null; - -/** - * Pointer to the currently highlighted <li> element in the container. - * - * @property _elCurListItem - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elCurListItem = null; - -/** - * Pointer to the currently pre-highlighted <li> element in the container. - * - * @property _elCurPrehighlightItem - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elCurPrehighlightItem = null; - -/** - * Whether or not an item has been selected since the container was populated - * with results. Reset to false by _populateList, and set to true when item is - * selected. - * - * @property _bItemSelected - * @type Boolean - * @private - */ -YAHOO.widget.AutoComplete.prototype._bItemSelected = false; - -/** - * Key code of the last key pressed in textbox. - * - * @property _nKeyCode - * @type Number - * @private - */ -YAHOO.widget.AutoComplete.prototype._nKeyCode = null; - -/** - * Delay timeout ID. - * - * @property _nDelayID - * @type Number - * @private - */ -YAHOO.widget.AutoComplete.prototype._nDelayID = -1; - -/** - * TypeAhead delay timeout ID. - * - * @property _nTypeAheadDelayID - * @type Number - * @private - */ -YAHOO.widget.AutoComplete.prototype._nTypeAheadDelayID = -1; - -/** - * Src to iFrame used when useIFrame = true. Supports implementations over SSL - * as well. - * - * @property _iFrameSrc - * @type String - * @private - */ -YAHOO.widget.AutoComplete.prototype._iFrameSrc = "javascript:false;"; - -/** - * For users typing via certain IMEs, queries must be triggered by intervals, - * since key events yet supported across all browsers for all IMEs. - * - * @property _queryInterval - * @type Object - * @private - */ -YAHOO.widget.AutoComplete.prototype._queryInterval = null; - -/** - * Internal tracker to last known textbox value, used to determine whether or not - * to trigger a query via interval for certain IME users. - * - * @event _sLastTextboxValue - * @type String - * @private - */ -YAHOO.widget.AutoComplete.prototype._sLastTextboxValue = null; - -///////////////////////////////////////////////////////////////////////////// -// -// Private methods -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Updates and validates latest public config properties. - * - * @method __initProps - * @private - */ -YAHOO.widget.AutoComplete.prototype._initProps = function() { - // Correct any invalid values - var minQueryLength = this.minQueryLength; - if(!YAHOO.lang.isNumber(minQueryLength)) { - this.minQueryLength = 1; - } - var maxResultsDisplayed = this.maxResultsDisplayed; - if(!YAHOO.lang.isNumber(maxResultsDisplayed) || (maxResultsDisplayed < 1)) { - this.maxResultsDisplayed = 10; - } - var queryDelay = this.queryDelay; - if(!YAHOO.lang.isNumber(queryDelay) || (queryDelay < 0)) { - this.queryDelay = 0.2; - } - var typeAheadDelay = this.typeAheadDelay; - if(!YAHOO.lang.isNumber(typeAheadDelay) || (typeAheadDelay < 0)) { - this.typeAheadDelay = 0.2; - } - var delimChar = this.delimChar; - if(YAHOO.lang.isString(delimChar) && (delimChar.length > 0)) { - this.delimChar = [delimChar]; - } - else if(!YAHOO.lang.isArray(delimChar)) { - this.delimChar = null; - } - var animSpeed = this.animSpeed; - if((this.animHoriz || this.animVert) && YAHOO.util.Anim) { - if(!YAHOO.lang.isNumber(animSpeed) || (animSpeed < 0)) { - this.animSpeed = 0.3; - } - if(!this._oAnim ) { - this._oAnim = new YAHOO.util.Anim(this._elContent, {}, this.animSpeed); - } - else { - this._oAnim.duration = this.animSpeed; - } - } - if(this.forceSelection && delimChar) { - YAHOO.log("The forceSelection feature has been enabled with delimChar defined.","warn", this.toString()); - } -}; - -/** - * Initializes the results container helpers if they are enabled and do - * not exist - * - * @method _initContainerHelperEls - * @private - */ -YAHOO.widget.AutoComplete.prototype._initContainerHelperEls = function() { - if(this.useShadow && !this._elShadow) { - var elShadow = document.createElement("div"); - elShadow.className = "yui-ac-shadow"; - elShadow.style.width = 0; - elShadow.style.height = 0; - this._elShadow = this._elContainer.appendChild(elShadow); - } - if(this.useIFrame && !this._elIFrame) { - var elIFrame = document.createElement("iframe"); - elIFrame.src = this._iFrameSrc; - elIFrame.frameBorder = 0; - elIFrame.scrolling = "no"; - elIFrame.style.position = "absolute"; - elIFrame.style.width = 0; - elIFrame.style.height = 0; - elIFrame.style.padding = 0; - elIFrame.tabIndex = -1; - elIFrame.role = "presentation"; - elIFrame.title = "Presentational iframe shim"; - this._elIFrame = this._elContainer.appendChild(elIFrame); - } -}; - -/** - * Initializes the results container once at object creation - * - * @method _initContainerEl - * @private - */ -YAHOO.widget.AutoComplete.prototype._initContainerEl = function() { - YAHOO.util.Dom.addClass(this._elContainer, "yui-ac-container"); - - if(!this._elContent) { - // The elContent div is assigned DOM listeners and - // helps size the iframe and shadow properly - var elContent = document.createElement("div"); - elContent.className = "yui-ac-content"; - elContent.style.display = "none"; - - this._elContent = this._elContainer.appendChild(elContent); - - var elHeader = document.createElement("div"); - elHeader.className = "yui-ac-hd"; - elHeader.style.display = "none"; - this._elHeader = this._elContent.appendChild(elHeader); - - var elBody = document.createElement("div"); - elBody.className = "yui-ac-bd"; - this._elBody = this._elContent.appendChild(elBody); - - var elFooter = document.createElement("div"); - elFooter.className = "yui-ac-ft"; - elFooter.style.display = "none"; - this._elFooter = this._elContent.appendChild(elFooter); - } - else { - YAHOO.log("Could not initialize the container","warn",this.toString()); - } -}; - -/** - * Clears out contents of container body and creates up to - * YAHOO.widget.AutoComplete#maxResultsDisplayed <li> elements in an - * <ul> element. - * - * @method _initListEl - * @private - */ -YAHOO.widget.AutoComplete.prototype._initListEl = function() { - var nListLength = this.maxResultsDisplayed, - elList = this._elList || document.createElement("ul"), - elListItem; - - while(elList.childNodes.length < nListLength) { - elListItem = document.createElement("li"); - elListItem.style.display = "none"; - elListItem._nItemIndex = elList.childNodes.length; - elList.appendChild(elListItem); - } - if(!this._elList) { - var elBody = this._elBody; - YAHOO.util.Event.purgeElement(elBody, true); - elBody.innerHTML = ""; - this._elList = elBody.appendChild(elList); - } - - this._elBody.style.display = ""; -}; - -/** - * Focuses input field. - * - * @method _focus - * @private - */ -YAHOO.widget.AutoComplete.prototype._focus = function() { - // http://developer.mozilla.org/en/docs/index.php?title=Key-navigable_custom_DHTML_widgets - var oSelf = this; - setTimeout(function() { - try { - oSelf._elTextbox.focus(); - } - catch(e) { - } - },0); -}; - -/** - * Enables interval detection for IME support. - * - * @method _enableIntervalDetection - * @private - */ -YAHOO.widget.AutoComplete.prototype._enableIntervalDetection = function() { - var oSelf = this; - if(!oSelf._queryInterval && oSelf.queryInterval) { - oSelf._queryInterval = setInterval(function() { oSelf._onInterval(); }, oSelf.queryInterval); - YAHOO.log("Interval set", "info", this.toString()); - } -}; - -/** - * Enables interval detection for a less performant but brute force mechanism to - * detect input values at an interval set by queryInterval and send queries if - * input value has changed. Needed to support right-click+paste or shift+insert - * edge cases. Please note that intervals are cleared at the end of each interaction, - * so enableIntervalDetection must be called for each new interaction. The - * recommended approach is to call it in response to textboxFocusEvent. - * - * @method enableIntervalDetection - */ -YAHOO.widget.AutoComplete.prototype.enableIntervalDetection = - YAHOO.widget.AutoComplete.prototype._enableIntervalDetection; - -/** - * Enables query triggers based on text input detection by intervals (rather - * than by key events). - * - * @method _onInterval - * @private - */ -YAHOO.widget.AutoComplete.prototype._onInterval = function() { - var currValue = this._elTextbox.value; - var lastValue = this._sLastTextboxValue; - if(currValue != lastValue) { - this._sLastTextboxValue = currValue; - this._sendQuery(currValue); - } -}; - -/** - * Cancels text input detection by intervals. - * - * @method _clearInterval - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._clearInterval = function() { - if(this._queryInterval) { - clearInterval(this._queryInterval); - this._queryInterval = null; - YAHOO.log("Interval cleared", "info", this.toString()); - } -}; - -/** - * Whether or not key is functional or should be ignored. Note that the right - * arrow key is NOT an ignored key since it triggers queries for certain intl - * charsets. - * - * @method _isIgnoreKey - * @param nKeycode {Number} Code of key pressed. - * @return {Boolean} True if key should be ignored, false otherwise. - * @private - */ -YAHOO.widget.AutoComplete.prototype._isIgnoreKey = function(nKeyCode) { - if((nKeyCode == 9) || (nKeyCode == 13) || // tab, enter - (nKeyCode == 16) || (nKeyCode == 17) || // shift, ctl - (nKeyCode >= 18 && nKeyCode <= 20) || // alt, pause/break,caps lock - (nKeyCode == 27) || // esc - (nKeyCode >= 33 && nKeyCode <= 35) || // page up,page down,end - /*(nKeyCode >= 36 && nKeyCode <= 38) || // home,left,up - (nKeyCode == 40) || // down*/ - (nKeyCode >= 36 && nKeyCode <= 40) || // home,left,up, right, down - (nKeyCode >= 44 && nKeyCode <= 45) || // print screen,insert - (nKeyCode == 229) // Bug 2041973: Korean XP fires 2 keyup events, the key and 229 - ) { - return true; - } - return false; -}; - -/** - * Makes query request to the DataSource. - * - * @method _sendQuery - * @param sQuery {String} Query string. - * @private - */ -YAHOO.widget.AutoComplete.prototype._sendQuery = function(sQuery) { - // Widget has been effectively turned off - if(this.minQueryLength < 0) { - this._toggleContainer(false); - YAHOO.log("Property minQueryLength is less than 0", "info", this.toString()); - return; - } - // Delimiter has been enabled - if(this.delimChar) { - var extraction = this._extractQuery(sQuery); - // Here is the query itself - sQuery = extraction.query; - // ...and save the rest of the string for later - this._sPastSelections = extraction.previous; - } - - // Don't search queries that are too short - if((sQuery && (sQuery.length < this.minQueryLength)) || (!sQuery && this.minQueryLength > 0)) { - if(this._nDelayID != -1) { - clearTimeout(this._nDelayID); - } - this._toggleContainer(false); - YAHOO.log("Query \"" + sQuery + "\" is too short", "info", this.toString()); - return; - } - - sQuery = encodeURIComponent(sQuery); - this._nDelayID = -1; // Reset timeout ID because request is being made - - // Subset matching - if(this.dataSource.queryMatchSubset || this.queryMatchSubset) { // backward compat - var oResponse = this.getSubsetMatches(sQuery); - if(oResponse) { - this.handleResponse(sQuery, oResponse, {query: sQuery}); - return; - } - } - - if(this.dataSource.responseStripAfter) { - this.dataSource.doBeforeParseData = this.preparseRawResponse; - } - if(this.applyLocalFilter) { - this.dataSource.doBeforeCallback = this.filterResults; - } - - var sRequest = this.generateRequest(sQuery); - this.dataRequestEvent.fire(this, sQuery, sRequest); - YAHOO.log("Sending query \"" + sRequest + "\"", "info", this.toString()); - - this.dataSource.sendRequest(sRequest, { - success : this.handleResponse, - failure : this.handleResponse, - scope : this, - argument: { - query: sQuery - } - }); -}; - -/** - * Populates the given <li> element with return value from formatResult(). - * - * @method _populateListItem - * @param elListItem {HTMLElement} The LI element. - * @param oResult {Object} The result object. - * @param sCurQuery {String} The query string. - * @private - */ -YAHOO.widget.AutoComplete.prototype._populateListItem = function(elListItem, oResult, sQuery) { - elListItem.innerHTML = this.formatResult(oResult, sQuery, elListItem._sResultMatch); -}; - -/** - * Populates the array of <li> elements in the container with query - * results. - * - * @method _populateList - * @param sQuery {String} Original request. - * @param oResponse {Object} Response object. - * @param oPayload {MIXED} (optional) Additional argument(s) - * @private - */ -YAHOO.widget.AutoComplete.prototype._populateList = function(sQuery, oResponse, oPayload) { - // Clear previous timeout - if(this._nTypeAheadDelayID != -1) { - clearTimeout(this._nTypeAheadDelayID); - } - - sQuery = (oPayload && oPayload.query) ? oPayload.query : sQuery; - - // Pass data through abstract method for any transformations - var ok = this.doBeforeLoadData(sQuery, oResponse, oPayload); - - // Data is ok - if(ok && !oResponse.error) { - this.dataReturnEvent.fire(this, sQuery, oResponse.results); - - // Continue only if instance is still active (i.e., user hasn't already moved on) - if(this._bFocused) { - // Store state for this interaction - var sCurQuery = decodeURIComponent(sQuery); - this._sCurQuery = sCurQuery; - this._bItemSelected = false; - - var allResults = oResponse.results, - nItemsToShow = Math.min(allResults.length,this.maxResultsDisplayed), - sMatchKey = (this.dataSource.responseSchema.fields) ? - (this.dataSource.responseSchema.fields[0].key || this.dataSource.responseSchema.fields[0]) : 0; - - if(nItemsToShow > 0) { - // Make sure container and helpers are ready to go - if(!this._elList || (this._elList.childNodes.length < nItemsToShow)) { - this._initListEl(); - } - this._initContainerHelperEls(); - - var allListItemEls = this._elList.childNodes; - // Fill items with data from the bottom up - for(var i = nItemsToShow-1; i >= 0; i--) { - var elListItem = allListItemEls[i], - oResult = allResults[i]; - - // Backward compatibility - if(this.resultTypeList) { - // Results need to be converted back to an array - var aResult = []; - // Match key is first - aResult[0] = (YAHOO.lang.isString(oResult)) ? oResult : oResult[sMatchKey] || oResult[this.key]; - // Add additional data to the result array - var fields = this.dataSource.responseSchema.fields; - if(YAHOO.lang.isArray(fields) && (fields.length > 1)) { - for(var k=1, len=fields.length; k= nItemsToShow; j--) { - extraListItem = allListItemEls[j]; - extraListItem.style.display = "none"; - } - } - - this._nDisplayedItems = nItemsToShow; - - this.containerPopulateEvent.fire(this, sQuery, allResults); - - // Highlight the first item - if(this.autoHighlight) { - var elFirstListItem = this._elList.firstChild; - this._toggleHighlight(elFirstListItem,"to"); - this.itemArrowToEvent.fire(this, elFirstListItem); - YAHOO.log("Arrowed to first item", "info", this.toString()); - this._typeAhead(elFirstListItem,sQuery); - } - // Unhighlight any previous time - else { - this._toggleHighlight(this._elCurListItem,"from"); - } - - // Pre-expansion stuff - ok = this._doBeforeExpandContainer(this._elTextbox, this._elContainer, sQuery, allResults); - - // Expand the container - this._toggleContainer(ok); - } - else { - this._toggleContainer(false); - } - - YAHOO.log("Container populated with " + nItemsToShow + " list items", "info", this.toString()); - return; - } - } - // Error - else { - this.dataErrorEvent.fire(this, sQuery, oResponse); - } - - YAHOO.log("Could not populate list", "info", this.toString()); -}; - -/** - * Called before container expands, by default snaps container to the - * bottom-left corner of the input element, then calls public overrideable method. - * - * @method _doBeforeExpandContainer - * @param elTextbox {HTMLElement} The text input box. - * @param elContainer {HTMLElement} The container element. - * @param sQuery {String} The query string. - * @param aResults {Object[]} An array of query results. - * @return {Boolean} Return true to continue expanding container, false to cancel the expand. - * @private - */ -YAHOO.widget.AutoComplete.prototype._doBeforeExpandContainer = function(elTextbox, elContainer, sQuery, aResults) { - if(this.autoSnapContainer) { - this.snapContainer(); - } - - return this.doBeforeExpandContainer(elTextbox, elContainer, sQuery, aResults); -}; - -/** - * When forceSelection is true and the user attempts - * leave the text input box without selecting an item from the query results, - * the user selection is cleared. - * - * @method _clearSelection - * @private - */ -YAHOO.widget.AutoComplete.prototype._clearSelection = function() { - var extraction = (this.delimChar) ? this._extractQuery(this._elTextbox.value) : - {previous:"",query:this._elTextbox.value}; - this._elTextbox.value = extraction.previous; - this.selectionEnforceEvent.fire(this, extraction.query); - YAHOO.log("Selection enforced", "info", this.toString()); -}; - -/** - * Whether or not user-typed value in the text input box matches any of the - * query results. - * - * @method _textMatchesOption - * @return {HTMLElement} Matching list item element if user-input text matches - * a result, null otherwise. - * @private - */ -YAHOO.widget.AutoComplete.prototype._textMatchesOption = function() { - var elMatch = null; - - for(var i=0; i= 0; i--) { - nNewIndex = sQuery.lastIndexOf(aDelimChar[i]); - if(nNewIndex > nDelimIndex) { - nDelimIndex = nNewIndex; - } - } - // If we think the last delimiter is a space (" "), make sure it is NOT - // a false positive by also checking the char directly before it - if(aDelimChar[i] == " ") { - for (var j = aDelimChar.length-1; j >= 0; j--) { - if(sQuery[nDelimIndex - 1] == aDelimChar[j]) { - nDelimIndex--; - break; - } - } - } - // A delimiter has been found in the query so extract the latest query from past selections - if(nDelimIndex > -1) { - nQueryStart = nDelimIndex + 1; - // Trim any white space from the beginning... - while(sQuery.charAt(nQueryStart) == " ") { - nQueryStart += 1; - } - // ...and save the rest of the string for later - sPrevious = sQuery.substring(0,nQueryStart); - // Here is the query itself - sQuery = sQuery.substr(nQueryStart); - } - // No delimiter found in the query, so there are no selections from past queries - else { - sPrevious = ""; - } - - return { - previous: sPrevious, - query: sQuery - }; -}; - -/** - * Syncs results container with its helpers. - * - * @method _toggleContainerHelpers - * @param bShow {Boolean} True if container is expanded, false if collapsed - * @private - */ -YAHOO.widget.AutoComplete.prototype._toggleContainerHelpers = function(bShow) { - var width = this._elContent.offsetWidth + "px"; - var height = this._elContent.offsetHeight + "px"; - - if(this.useIFrame && this._elIFrame) { - var elIFrame = this._elIFrame; - if(bShow) { - elIFrame.style.width = width; - elIFrame.style.height = height; - elIFrame.style.padding = ""; - YAHOO.log("Iframe expanded", "info", this.toString()); - } - else { - elIFrame.style.width = 0; - elIFrame.style.height = 0; - elIFrame.style.padding = 0; - YAHOO.log("Iframe collapsed", "info", this.toString()); - } - } - if(this.useShadow && this._elShadow) { - var elShadow = this._elShadow; - if(bShow) { - elShadow.style.width = width; - elShadow.style.height = height; - YAHOO.log("Shadow expanded", "info", this.toString()); - } - else { - elShadow.style.width = 0; - elShadow.style.height = 0; - YAHOO.log("Shadow collapsed", "info", this.toString()); - } - } -}; - -/** - * Animates expansion or collapse of the container. - * - * @method _toggleContainer - * @param bShow {Boolean} True if container should be expanded, false if container should be collapsed - * @private - */ -YAHOO.widget.AutoComplete.prototype._toggleContainer = function(bShow) { - YAHOO.log("Toggling container " + ((bShow) ? "open" : "closed"), "info", this.toString()); - - var elContainer = this._elContainer; - - // If implementer has container always open and it's already open, don't mess with it - // Container is initialized with display "none" so it may need to be shown first time through - if(this.alwaysShowContainer && this._bContainerOpen) { - return; - } - - // Reset states - if(!bShow) { - this._toggleHighlight(this._elCurListItem,"from"); - this._nDisplayedItems = 0; - this._sCurQuery = null; - - // Container is already closed, so don't bother with changing the UI - if(this._elContent.style.display == "none") { - return; - } - } - - // If animation is enabled... - var oAnim = this._oAnim; - if(oAnim && oAnim.getEl() && (this.animHoriz || this.animVert)) { - if(oAnim.isAnimated()) { - oAnim.stop(true); - } - - // Clone container to grab current size offscreen - var oClone = this._elContent.cloneNode(true); - elContainer.appendChild(oClone); - oClone.style.top = "-9000px"; - oClone.style.width = ""; - oClone.style.height = ""; - oClone.style.display = ""; - - // Current size of the container is the EXPANDED size - var wExp = oClone.offsetWidth; - var hExp = oClone.offsetHeight; - - // Calculate COLLAPSED sizes based on horiz and vert anim - var wColl = (this.animHoriz) ? 0 : wExp; - var hColl = (this.animVert) ? 0 : hExp; - - // Set animation sizes - oAnim.attributes = (bShow) ? - {width: { to: wExp }, height: { to: hExp }} : - {width: { to: wColl}, height: { to: hColl }}; - - // If opening anew, set to a collapsed size... - if(bShow && !this._bContainerOpen) { - this._elContent.style.width = wColl+"px"; - this._elContent.style.height = hColl+"px"; - } - // Else, set it to its last known size. - else { - this._elContent.style.width = wExp+"px"; - this._elContent.style.height = hExp+"px"; - } - - elContainer.removeChild(oClone); - oClone = null; - - var oSelf = this; - var onAnimComplete = function() { - // Finish the collapse - oAnim.onComplete.unsubscribeAll(); - - if(bShow) { - oSelf._toggleContainerHelpers(true); - oSelf._bContainerOpen = bShow; - oSelf.containerExpandEvent.fire(oSelf); - YAHOO.log("Container expanded", "info", oSelf.toString()); - } - else { - oSelf._elContent.style.display = "none"; - oSelf._bContainerOpen = bShow; - oSelf.containerCollapseEvent.fire(oSelf); - YAHOO.log("Container collapsed", "info", oSelf.toString()); - } - }; - - // Display container and animate it - this._toggleContainerHelpers(false); // Bug 1424486: Be early to hide, late to show; - this._elContent.style.display = ""; - oAnim.onComplete.subscribe(onAnimComplete); - oAnim.animate(); - } - // Else don't animate, just show or hide - else { - if(bShow) { - this._elContent.style.display = ""; - this._toggleContainerHelpers(true); - this._bContainerOpen = bShow; - this.containerExpandEvent.fire(this); - YAHOO.log("Container expanded", "info", this.toString()); - } - else { - this._toggleContainerHelpers(false); - this._elContent.style.display = "none"; - this._bContainerOpen = bShow; - this.containerCollapseEvent.fire(this); - YAHOO.log("Container collapsed", "info", this.toString()); - } - } - -}; - -/** - * Toggles the highlight on or off for an item in the container, and also cleans - * up highlighting of any previous item. - * - * @method _toggleHighlight - * @param elNewListItem {HTMLElement} The <li> element item to receive highlight behavior. - * @param sType {String} Type "mouseover" will toggle highlight on, and "mouseout" will toggle highlight off. - * @private - */ -YAHOO.widget.AutoComplete.prototype._toggleHighlight = function(elNewListItem, sType) { - if(elNewListItem) { - var sHighlight = this.highlightClassName; - if(this._elCurListItem) { - // Remove highlight from old item - YAHOO.util.Dom.removeClass(this._elCurListItem, sHighlight); - this._elCurListItem = null; - } - - if((sType == "to") && sHighlight) { - // Apply highlight to new item - YAHOO.util.Dom.addClass(elNewListItem, sHighlight); - this._elCurListItem = elNewListItem; - } - } -}; - -/** - * Toggles the pre-highlight on or off for an item in the container, and also cleans - * up pre-highlighting of any previous item. - * - * @method _togglePrehighlight - * @param elNewListItem {HTMLElement} The <li> element item to receive highlight behavior. - * @param sType {String} Type "mouseover" will toggle highlight on, and "mouseout" will toggle highlight off. - * @private - */ -YAHOO.widget.AutoComplete.prototype._togglePrehighlight = function(elNewListItem, sType) { - var sPrehighlight = this.prehighlightClassName; - - if(this._elCurPrehighlightItem) { - YAHOO.util.Dom.removeClass(this._elCurPrehighlightItem, sPrehighlight); - } - if(elNewListItem == this._elCurListItem) { - return; - } - - if((sType == "mouseover") && sPrehighlight) { - // Apply prehighlight to new item - YAHOO.util.Dom.addClass(elNewListItem, sPrehighlight); - this._elCurPrehighlightItem = elNewListItem; - } - else { - // Remove prehighlight from old item - YAHOO.util.Dom.removeClass(elNewListItem, sPrehighlight); - } -}; - -/** - * Updates the text input box value with selected query result. If a delimiter - * has been defined, then the value gets appended with the delimiter. - * - * @method _updateValue - * @param elListItem {HTMLElement} The <li> element item with which to update the value. - * @private - */ -YAHOO.widget.AutoComplete.prototype._updateValue = function(elListItem) { - if(!this.suppressInputUpdate) { - var elTextbox = this._elTextbox; - var sDelimChar = (this.delimChar) ? (this.delimChar[0] || this.delimChar) : null; - var sResultMatch = elListItem._sResultMatch; - - // Calculate the new value - var sNewValue = ""; - if(sDelimChar) { - // Preserve selections from past queries - sNewValue = this._sPastSelections; - // Add new selection plus delimiter - sNewValue += sResultMatch + sDelimChar; - if(sDelimChar != " ") { - sNewValue += " "; - } - } - else { - sNewValue = sResultMatch; - } - - // Update input field - elTextbox.value = sNewValue; - - // Scroll to bottom of textarea if necessary - if(elTextbox.type == "textarea") { - elTextbox.scrollTop = elTextbox.scrollHeight; - } - - // Move cursor to end - var end = elTextbox.value.length; - this._selectText(elTextbox,end,end); - - this._elCurListItem = elListItem; - } -}; - -/** - * Selects a result item from the container - * - * @method _selectItem - * @param elListItem {HTMLElement} The selected <li> element item. - * @private - */ -YAHOO.widget.AutoComplete.prototype._selectItem = function(elListItem) { - this._bItemSelected = true; - this._updateValue(elListItem); - this._sPastSelections = this._elTextbox.value; - this._clearInterval(); - this.itemSelectEvent.fire(this, elListItem, elListItem._oResultData); - YAHOO.log("Item selected: " + YAHOO.lang.dump(elListItem._oResultData), "info", this.toString()); - this._toggleContainer(false); -}; - -/** - * If an item is highlighted in the container, the right arrow key jumps to the - * end of the textbox and selects the highlighted item, otherwise the container - * is closed. - * - * @method _jumpSelection - * @private - */ -YAHOO.widget.AutoComplete.prototype._jumpSelection = function() { - if(this._elCurListItem) { - this._selectItem(this._elCurListItem); - } - else { - this._toggleContainer(false); - } -}; - -/** - * Triggered by up and down arrow keys, changes the current highlighted - * <li> element item. Scrolls container if necessary. - * - * @method _moveSelection - * @param nKeyCode {Number} Code of key pressed. - * @private - */ -YAHOO.widget.AutoComplete.prototype._moveSelection = function(nKeyCode) { - if(this._bContainerOpen) { - // Determine current item's id number - var elCurListItem = this._elCurListItem, - nCurItemIndex = -1; - - if(elCurListItem) { - nCurItemIndex = elCurListItem._nItemIndex; - } - - var nNewItemIndex = (nKeyCode == 40) ? - (nCurItemIndex + 1) : (nCurItemIndex - 1); - - // Out of bounds - if(nNewItemIndex < -2 || nNewItemIndex >= this._nDisplayedItems) { - return; - } - - if(elCurListItem) { - // Unhighlight current item - this._toggleHighlight(elCurListItem, "from"); - this.itemArrowFromEvent.fire(this, elCurListItem); - YAHOO.log("Item arrowed from: " + elCurListItem._nItemIndex, "info", this.toString()); - } - if(nNewItemIndex == -1) { - // Go back to query (remove type-ahead string) - if(this.delimChar) { - this._elTextbox.value = this._sPastSelections + this._sCurQuery; - } - else { - this._elTextbox.value = this._sCurQuery; - } - return; - } - if(nNewItemIndex == -2) { - // Close container - this._toggleContainer(false); - return; - } - - var elNewListItem = this._elList.childNodes[nNewItemIndex], - - // Scroll the container if necessary - elContent = this._elContent, - sOF = YAHOO.util.Dom.getStyle(elContent,"overflow"), - sOFY = YAHOO.util.Dom.getStyle(elContent,"overflowY"), - scrollOn = ((sOF == "auto") || (sOF == "scroll") || (sOFY == "auto") || (sOFY == "scroll")); - if(scrollOn && (nNewItemIndex > -1) && - (nNewItemIndex < this._nDisplayedItems)) { - // User is keying down - if(nKeyCode == 40) { - // Bottom of selected item is below scroll area... - if((elNewListItem.offsetTop+elNewListItem.offsetHeight) > (elContent.scrollTop + elContent.offsetHeight)) { - // Set bottom of scroll area to bottom of selected item - elContent.scrollTop = (elNewListItem.offsetTop+elNewListItem.offsetHeight) - elContent.offsetHeight; - } - // Bottom of selected item is above scroll area... - else if((elNewListItem.offsetTop+elNewListItem.offsetHeight) < elContent.scrollTop) { - // Set top of selected item to top of scroll area - elContent.scrollTop = elNewListItem.offsetTop; - - } - } - // User is keying up - else { - // Top of selected item is above scroll area - if(elNewListItem.offsetTop < elContent.scrollTop) { - // Set top of scroll area to top of selected item - this._elContent.scrollTop = elNewListItem.offsetTop; - } - // Top of selected item is below scroll area - else if(elNewListItem.offsetTop > (elContent.scrollTop + elContent.offsetHeight)) { - // Set bottom of selected item to bottom of scroll area - this._elContent.scrollTop = (elNewListItem.offsetTop+elNewListItem.offsetHeight) - elContent.offsetHeight; - } - } - } - - this._toggleHighlight(elNewListItem, "to"); - this.itemArrowToEvent.fire(this, elNewListItem); - YAHOO.log("Item arrowed to " + elNewListItem._nItemIndex, "info", this.toString()); - if(this.typeAhead) { - this._updateValue(elNewListItem); - } - } -}; - -///////////////////////////////////////////////////////////////////////////// -// -// Private event handlers -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Handles container mouseover events. - * - * @method _onContainerMouseover - * @param v {HTMLEvent} The mouseover event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onContainerMouseover = function(v,oSelf) { - var elTarget = YAHOO.util.Event.getTarget(v); - var elTag = elTarget.nodeName.toLowerCase(); - while(elTarget && (elTag != "table")) { - switch(elTag) { - case "body": - return; - case "li": - if(oSelf.prehighlightClassName) { - oSelf._togglePrehighlight(elTarget,"mouseover"); - } - else { - oSelf._toggleHighlight(elTarget,"to"); - } - - oSelf.itemMouseOverEvent.fire(oSelf, elTarget); - YAHOO.log("Item moused over " + elTarget._nItemIndex, "info", oSelf.toString()); - break; - case "div": - if(YAHOO.util.Dom.hasClass(elTarget,"yui-ac-container")) { - oSelf._bOverContainer = true; - return; - } - break; - default: - break; - } - - elTarget = elTarget.parentNode; - if(elTarget) { - elTag = elTarget.nodeName.toLowerCase(); - } - } -}; - -/** - * Handles container mouseout events. - * - * @method _onContainerMouseout - * @param v {HTMLEvent} The mouseout event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onContainerMouseout = function(v,oSelf) { - var elTarget = YAHOO.util.Event.getTarget(v); - var elTag = elTarget.nodeName.toLowerCase(); - while(elTarget && (elTag != "table")) { - switch(elTag) { - case "body": - return; - case "li": - if(oSelf.prehighlightClassName) { - oSelf._togglePrehighlight(elTarget,"mouseout"); - } - else { - oSelf._toggleHighlight(elTarget,"from"); - } - - oSelf.itemMouseOutEvent.fire(oSelf, elTarget); - YAHOO.log("Item moused out " + elTarget._nItemIndex, "info", oSelf.toString()); - break; - case "ul": - oSelf._toggleHighlight(oSelf._elCurListItem,"to"); - break; - case "div": - if(YAHOO.util.Dom.hasClass(elTarget,"yui-ac-container")) { - oSelf._bOverContainer = false; - return; - } - break; - default: - break; - } - - elTarget = elTarget.parentNode; - if(elTarget) { - elTag = elTarget.nodeName.toLowerCase(); - } - } -}; - -/** - * Handles container click events. - * - * @method _onContainerClick - * @param v {HTMLEvent} The click event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onContainerClick = function(v,oSelf) { - var elTarget = YAHOO.util.Event.getTarget(v); - var elTag = elTarget.nodeName.toLowerCase(); - while(elTarget && (elTag != "table")) { - switch(elTag) { - case "body": - return; - case "li": - // In case item has not been moused over - oSelf._toggleHighlight(elTarget,"to"); - oSelf._selectItem(elTarget); - return; - default: - break; - } - - elTarget = elTarget.parentNode; - if(elTarget) { - elTag = elTarget.nodeName.toLowerCase(); - } - } -}; - - -/** - * Handles container scroll events. - * - * @method _onContainerScroll - * @param v {HTMLEvent} The scroll event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onContainerScroll = function(v,oSelf) { - oSelf._focus(); -}; - -/** - * Handles container resize events. - * - * @method _onContainerResize - * @param v {HTMLEvent} The resize event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onContainerResize = function(v,oSelf) { - oSelf._toggleContainerHelpers(oSelf._bContainerOpen); -}; - - -/** - * Handles textbox keydown events of functional keys, mainly for UI behavior. - * - * @method _onTextboxKeyDown - * @param v {HTMLEvent} The keydown event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onTextboxKeyDown = function(v,oSelf) { - var nKeyCode = v.keyCode; - - // Clear timeout - if(oSelf._nTypeAheadDelayID != -1) { - clearTimeout(oSelf._nTypeAheadDelayID); - } - - switch (nKeyCode) { - case 9: // tab - if(!YAHOO.env.ua.opera && (navigator.userAgent.toLowerCase().indexOf("mac") == -1) || (YAHOO.env.ua.webkit>420)) { - // select an item or clear out - if(oSelf._elCurListItem) { - if(oSelf.delimChar && (oSelf._nKeyCode != nKeyCode)) { - if(oSelf._bContainerOpen) { - YAHOO.util.Event.stopEvent(v); - } - } - oSelf._selectItem(oSelf._elCurListItem); - } - else { - oSelf._toggleContainer(false); - } - } - break; - case 13: // enter - if(!YAHOO.env.ua.opera && (navigator.userAgent.toLowerCase().indexOf("mac") == -1) || (YAHOO.env.ua.webkit>420)) { - if(oSelf._elCurListItem) { - if(oSelf._nKeyCode != nKeyCode) { - if(oSelf._bContainerOpen) { - YAHOO.util.Event.stopEvent(v); - } - } - oSelf._selectItem(oSelf._elCurListItem); - } - else { - oSelf._toggleContainer(false); - } - } - break; - case 27: // esc - oSelf._toggleContainer(false); - return; - case 39: // right - oSelf._jumpSelection(); - break; - case 38: // up - if(oSelf._bContainerOpen) { - YAHOO.util.Event.stopEvent(v); - oSelf._moveSelection(nKeyCode); - } - break; - case 40: // down - if(oSelf._bContainerOpen) { - YAHOO.util.Event.stopEvent(v); - oSelf._moveSelection(nKeyCode); - } - break; - default: - oSelf._bItemSelected = false; - oSelf._toggleHighlight(oSelf._elCurListItem, "from"); - - oSelf.textboxKeyEvent.fire(oSelf, nKeyCode); - YAHOO.log("Textbox keyed", "info", oSelf.toString()); - break; - } - - if(nKeyCode === 18){ - oSelf._enableIntervalDetection(); - } - oSelf._nKeyCode = nKeyCode; -}; - -/** - * Handles textbox keypress events. - * @method _onTextboxKeyPress - * @param v {HTMLEvent} The keypress event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onTextboxKeyPress = function(v,oSelf) { - var nKeyCode = v.keyCode; - - // Expose only to non SF3 (bug 1978549) Mac browsers (bug 790337) and Opera browsers (bug 583531), - // where stopEvent is ineffective on keydown events - if(YAHOO.env.ua.opera || (navigator.userAgent.toLowerCase().indexOf("mac") != -1) && (YAHOO.env.ua.webkit < 420)) { - switch (nKeyCode) { - case 9: // tab - // select an item or clear out - if(oSelf._bContainerOpen) { - if(oSelf.delimChar) { - YAHOO.util.Event.stopEvent(v); - } - if(oSelf._elCurListItem) { - oSelf._selectItem(oSelf._elCurListItem); - } - else { - oSelf._toggleContainer(false); - } - } - break; - case 13: // enter - if(oSelf._bContainerOpen) { - YAHOO.util.Event.stopEvent(v); - if(oSelf._elCurListItem) { - oSelf._selectItem(oSelf._elCurListItem); - } - else { - oSelf._toggleContainer(false); - } - } - break; - default: - break; - } - } - - //TODO: (?) limit only to non-IE, non-Mac-FF for Korean IME support (bug 811948) - // Korean IME detected - else if(nKeyCode == 229) { - oSelf._enableIntervalDetection(); - } -}; - -/** - * Handles textbox keyup events to trigger queries. - * - * @method _onTextboxKeyUp - * @param v {HTMLEvent} The keyup event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onTextboxKeyUp = function(v,oSelf) { - var sText = this.value; //string in textbox - - // Check to see if any of the public properties have been updated - oSelf._initProps(); - - // Filter out chars that don't trigger queries - var nKeyCode = v.keyCode; - if(oSelf._isIgnoreKey(nKeyCode)) { - return; - } - - // Clear previous timeout - if(oSelf._nDelayID != -1) { - clearTimeout(oSelf._nDelayID); - } - - // Set new timeout - oSelf._nDelayID = setTimeout(function(){ - oSelf._sendQuery(sText); - },(oSelf.queryDelay * 1000)); -}; - -/** - * Handles text input box receiving focus. - * - * @method _onTextboxFocus - * @param v {HTMLEvent} The focus event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onTextboxFocus = function (v,oSelf) { - // Start of a new interaction - if(!oSelf._bFocused) { - oSelf._elTextbox.setAttribute("autocomplete","off"); - oSelf._bFocused = true; - oSelf._sInitInputValue = oSelf._elTextbox.value; - oSelf.textboxFocusEvent.fire(oSelf); - YAHOO.log("Textbox focused", "info", oSelf.toString()); - } -}; - -/** - * Handles text input box losing focus. - * - * @method _onTextboxBlur - * @param v {HTMLEvent} The focus event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onTextboxBlur = function (v,oSelf) { - // Is a true blur - if(!oSelf._bOverContainer || (oSelf._nKeyCode == 9)) { - // Current query needs to be validated as a selection - if(!oSelf._bItemSelected) { - var elMatchListItem = oSelf._textMatchesOption(); - // Container is closed or current query doesn't match any result - if(!oSelf._bContainerOpen || (oSelf._bContainerOpen && (elMatchListItem === null))) { - // Force selection is enabled so clear the current query - if(oSelf.forceSelection) { - oSelf._clearSelection(); - } - // Treat current query as a valid selection - else { - oSelf.unmatchedItemSelectEvent.fire(oSelf, oSelf._sCurQuery); - YAHOO.log("Unmatched item selected: " + oSelf._sCurQuery, "info", oSelf.toString()); - } - } - // Container is open and current query matches a result - else { - // Force a selection when textbox is blurred with a match - if(oSelf.forceSelection) { - oSelf._selectItem(elMatchListItem); - } - } - } - - oSelf._clearInterval(); - oSelf._bFocused = false; - if(oSelf._sInitInputValue !== oSelf._elTextbox.value) { - oSelf.textboxChangeEvent.fire(oSelf); - } - oSelf.textboxBlurEvent.fire(oSelf); - YAHOO.log("Textbox blurred", "info", oSelf.toString()); - - oSelf._toggleContainer(false); - } - // Not a true blur if it was a selection via mouse click - else { - oSelf._focus(); - } -}; - -/** - * Handles window unload event. - * - * @method _onWindowUnload - * @param v {HTMLEvent} The unload event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onWindowUnload = function(v,oSelf) { - if(oSelf && oSelf._elTextbox && oSelf.allowBrowserAutocomplete) { - oSelf._elTextbox.setAttribute("autocomplete","on"); - } -}; - -///////////////////////////////////////////////////////////////////////////// -// -// Deprecated for Backwards Compatibility -// -///////////////////////////////////////////////////////////////////////////// -/** - * @method doBeforeSendQuery - * @deprecated Use generateRequest. - */ -YAHOO.widget.AutoComplete.prototype.doBeforeSendQuery = function(sQuery) { - return this.generateRequest(sQuery); -}; - -/** - * @method getListItems - * @deprecated Use getListEl().childNodes. - */ -YAHOO.widget.AutoComplete.prototype.getListItems = function() { - var allListItemEls = [], - els = this._elList.childNodes; - for(var i=els.length-1; i>=0; i--) { - allListItemEls[i] = els[i]; - } - return allListItemEls; -}; - -///////////////////////////////////////////////////////////////////////// -// -// Private static methods -// -///////////////////////////////////////////////////////////////////////// - -/** - * Clones object literal or array of object literals. - * - * @method AutoComplete._cloneObject - * @param o {Object} Object. - * @private - * @static - */ -YAHOO.widget.AutoComplete._cloneObject = function(o) { - if(!YAHOO.lang.isValue(o)) { - return o; - } - - var copy = {}; - - if(YAHOO.lang.isFunction(o)) { - copy = o; - } - else if(YAHOO.lang.isArray(o)) { - var array = []; - for(var i=0,len=o.length;i-1;A--){B[A].style.display="none";}};YAHOO.widget.AutoComplete.prototype.getSubsetMatches=function(E){var D,C,A;for(var B=E.length;B>=this.minQueryLength;B--){A=this.generateRequest(E.substr(0,B));this.dataRequestEvent.fire(this,D,A);C=this.dataSource.getCachedResponse(A);if(C){return this.filterResults.apply(this.dataSource,[E,C,C,{scope:this}]);}}return null;};YAHOO.widget.AutoComplete.prototype.preparseRawResponse=function(C,B,A){var D=((this.responseStripAfter!=="")&&(B.indexOf))?B.indexOf(this.responseStripAfter):-1;if(D!=-1){B=B.substring(0,D);}return B;};YAHOO.widget.AutoComplete.prototype.filterResults=function(K,M,Q,L){if(L&&L.argument&&L.argument.query){K=L.argument.query;}if(K&&K!==""){Q=YAHOO.widget.AutoComplete._cloneObject(Q);var I=L.scope,P=this,C=Q.results,N=[],B=I.maxResultsDisplayed,J=(P.queryMatchCase||I.queryMatchCase),A=(P.queryMatchContains||I.queryMatchContains);for(var D=0,H=C.length;D-1))){N.push(F);}}if(H>B&&N.length===B){break;}}Q.results=N;}else{}return Q;};YAHOO.widget.AutoComplete.prototype.handleResponse=function(C,A,B){if((this instanceof YAHOO.widget.AutoComplete)&&this._sName){this._populateList(C,A,B);}};YAHOO.widget.AutoComplete.prototype.doBeforeLoadData=function(C,A,B){return true;};YAHOO.widget.AutoComplete.prototype.formatResult=function(B,D,A){var C=(A)?A:"";return C;};YAHOO.widget.AutoComplete.prototype.doBeforeExpandContainer=function(D,A,C,B){return true;};YAHOO.widget.AutoComplete.prototype.destroy=function(){var B=this.toString();var A=this._elTextbox;var D=this._elContainer;this.textboxFocusEvent.unsubscribeAll();this.textboxKeyEvent.unsubscribeAll();this.dataRequestEvent.unsubscribeAll();this.dataReturnEvent.unsubscribeAll();this.dataErrorEvent.unsubscribeAll();this.containerPopulateEvent.unsubscribeAll();this.containerExpandEvent.unsubscribeAll();this.typeAheadEvent.unsubscribeAll();this.itemMouseOverEvent.unsubscribeAll();this.itemMouseOutEvent.unsubscribeAll();this.itemArrowToEvent.unsubscribeAll();this.itemArrowFromEvent.unsubscribeAll();this.itemSelectEvent.unsubscribeAll();this.unmatchedItemSelectEvent.unsubscribeAll();this.selectionEnforceEvent.unsubscribeAll();this.containerCollapseEvent.unsubscribeAll();this.textboxBlurEvent.unsubscribeAll();this.textboxChangeEvent.unsubscribeAll();YAHOO.util.Event.purgeElement(A,true);YAHOO.util.Event.purgeElement(D,true);D.innerHTML="";for(var C in this){if(YAHOO.lang.hasOwnProperty(this,C)){this[C]=null;}}};YAHOO.widget.AutoComplete.prototype.textboxFocusEvent=null;YAHOO.widget.AutoComplete.prototype.textboxKeyEvent=null;YAHOO.widget.AutoComplete.prototype.dataRequestEvent=null;YAHOO.widget.AutoComplete.prototype.dataReturnEvent=null;YAHOO.widget.AutoComplete.prototype.dataErrorEvent=null;YAHOO.widget.AutoComplete.prototype.containerPopulateEvent=null;YAHOO.widget.AutoComplete.prototype.containerExpandEvent=null;YAHOO.widget.AutoComplete.prototype.typeAheadEvent=null;YAHOO.widget.AutoComplete.prototype.itemMouseOverEvent=null;YAHOO.widget.AutoComplete.prototype.itemMouseOutEvent=null; -YAHOO.widget.AutoComplete.prototype.itemArrowToEvent=null;YAHOO.widget.AutoComplete.prototype.itemArrowFromEvent=null;YAHOO.widget.AutoComplete.prototype.itemSelectEvent=null;YAHOO.widget.AutoComplete.prototype.unmatchedItemSelectEvent=null;YAHOO.widget.AutoComplete.prototype.selectionEnforceEvent=null;YAHOO.widget.AutoComplete.prototype.containerCollapseEvent=null;YAHOO.widget.AutoComplete.prototype.textboxBlurEvent=null;YAHOO.widget.AutoComplete.prototype.textboxChangeEvent=null;YAHOO.widget.AutoComplete._nIndex=0;YAHOO.widget.AutoComplete.prototype._sName=null;YAHOO.widget.AutoComplete.prototype._elTextbox=null;YAHOO.widget.AutoComplete.prototype._elContainer=null;YAHOO.widget.AutoComplete.prototype._elContent=null;YAHOO.widget.AutoComplete.prototype._elHeader=null;YAHOO.widget.AutoComplete.prototype._elBody=null;YAHOO.widget.AutoComplete.prototype._elFooter=null;YAHOO.widget.AutoComplete.prototype._elShadow=null;YAHOO.widget.AutoComplete.prototype._elIFrame=null;YAHOO.widget.AutoComplete.prototype._bFocused=false;YAHOO.widget.AutoComplete.prototype._oAnim=null;YAHOO.widget.AutoComplete.prototype._bContainerOpen=false;YAHOO.widget.AutoComplete.prototype._bOverContainer=false;YAHOO.widget.AutoComplete.prototype._elList=null;YAHOO.widget.AutoComplete.prototype._nDisplayedItems=0;YAHOO.widget.AutoComplete.prototype._sCurQuery=null;YAHOO.widget.AutoComplete.prototype._sPastSelections="";YAHOO.widget.AutoComplete.prototype._sInitInputValue=null;YAHOO.widget.AutoComplete.prototype._elCurListItem=null;YAHOO.widget.AutoComplete.prototype._elCurPrehighlightItem=null;YAHOO.widget.AutoComplete.prototype._bItemSelected=false;YAHOO.widget.AutoComplete.prototype._nKeyCode=null;YAHOO.widget.AutoComplete.prototype._nDelayID=-1;YAHOO.widget.AutoComplete.prototype._nTypeAheadDelayID=-1;YAHOO.widget.AutoComplete.prototype._iFrameSrc="javascript:false;";YAHOO.widget.AutoComplete.prototype._queryInterval=null;YAHOO.widget.AutoComplete.prototype._sLastTextboxValue=null;YAHOO.widget.AutoComplete.prototype._initProps=function(){var B=this.minQueryLength;if(!YAHOO.lang.isNumber(B)){this.minQueryLength=1;}var E=this.maxResultsDisplayed;if(!YAHOO.lang.isNumber(E)||(E<1)){this.maxResultsDisplayed=10;}var F=this.queryDelay;if(!YAHOO.lang.isNumber(F)||(F<0)){this.queryDelay=0.2;}var C=this.typeAheadDelay;if(!YAHOO.lang.isNumber(C)||(C<0)){this.typeAheadDelay=0.2;}var A=this.delimChar;if(YAHOO.lang.isString(A)&&(A.length>0)){this.delimChar=[A];}else{if(!YAHOO.lang.isArray(A)){this.delimChar=null;}}var D=this.animSpeed;if((this.animHoriz||this.animVert)&&YAHOO.util.Anim){if(!YAHOO.lang.isNumber(D)||(D<0)){this.animSpeed=0.3;}if(!this._oAnim){this._oAnim=new YAHOO.util.Anim(this._elContent,{},this.animSpeed);}else{this._oAnim.duration=this.animSpeed;}}if(this.forceSelection&&A){}};YAHOO.widget.AutoComplete.prototype._initContainerHelperEls=function(){if(this.useShadow&&!this._elShadow){var A=document.createElement("div");A.className="yui-ac-shadow";A.style.width=0;A.style.height=0;this._elShadow=this._elContainer.appendChild(A);}if(this.useIFrame&&!this._elIFrame){var B=document.createElement("iframe");B.src=this._iFrameSrc;B.frameBorder=0;B.scrolling="no";B.style.position="absolute";B.style.width=0;B.style.height=0;B.style.padding=0;B.tabIndex=-1;B.role="presentation";B.title="Presentational iframe shim";this._elIFrame=this._elContainer.appendChild(B);}};YAHOO.widget.AutoComplete.prototype._initContainerEl=function(){YAHOO.util.Dom.addClass(this._elContainer,"yui-ac-container");if(!this._elContent){var C=document.createElement("div");C.className="yui-ac-content";C.style.display="none";this._elContent=this._elContainer.appendChild(C);var B=document.createElement("div");B.className="yui-ac-hd";B.style.display="none";this._elHeader=this._elContent.appendChild(B);var D=document.createElement("div");D.className="yui-ac-bd";this._elBody=this._elContent.appendChild(D);var A=document.createElement("div");A.className="yui-ac-ft";A.style.display="none";this._elFooter=this._elContent.appendChild(A);}else{}};YAHOO.widget.AutoComplete.prototype._initListEl=function(){var C=this.maxResultsDisplayed,A=this._elList||document.createElement("ul"),B;while(A.childNodes.length=18&&A<=20)||(A==27)||(A>=33&&A<=35)||(A>=36&&A<=40)||(A>=44&&A<=45)||(A==229)){return true;}return false;};YAHOO.widget.AutoComplete.prototype._sendQuery=function(D){if(this.minQueryLength<0){this._toggleContainer(false);return;}if(this.delimChar){var A=this._extractQuery(D);D=A.query;this._sPastSelections=A.previous;}if((D&&(D.length0)){if(this._nDelayID!=-1){clearTimeout(this._nDelayID);}this._toggleContainer(false);return;}D=encodeURIComponent(D);this._nDelayID=-1;if(this.dataSource.queryMatchSubset||this.queryMatchSubset){var C=this.getSubsetMatches(D);if(C){this.handleResponse(D,C,{query:D});return; -}}if(this.dataSource.responseStripAfter){this.dataSource.doBeforeParseData=this.preparseRawResponse;}if(this.applyLocalFilter){this.dataSource.doBeforeCallback=this.filterResults;}var B=this.generateRequest(D);this.dataRequestEvent.fire(this,D,B);this.dataSource.sendRequest(B,{success:this.handleResponse,failure:this.handleResponse,scope:this,argument:{query:D}});};YAHOO.widget.AutoComplete.prototype._populateListItem=function(B,A,C){B.innerHTML=this.formatResult(A,C,B._sResultMatch);};YAHOO.widget.AutoComplete.prototype._populateList=function(K,F,C){if(this._nTypeAheadDelayID!=-1){clearTimeout(this._nTypeAheadDelayID);}K=(C&&C.query)?C.query:K;var H=this.doBeforeLoadData(K,F,C);if(H&&!F.error){this.dataReturnEvent.fire(this,K,F.results);if(this._bFocused){var M=decodeURIComponent(K);this._sCurQuery=M;this._bItemSelected=false;var R=F.results,A=Math.min(R.length,this.maxResultsDisplayed),J=(this.dataSource.responseSchema.fields)?(this.dataSource.responseSchema.fields[0].key||this.dataSource.responseSchema.fields[0]):0;if(A>0){if(!this._elList||(this._elList.childNodes.length=0;Q--){var P=I[Q],E=R[Q];if(this.resultTypeList){var B=[];B[0]=(YAHOO.lang.isString(E))?E:E[J]||E[this.key];var L=this.dataSource.responseSchema.fields;if(YAHOO.lang.isArray(L)&&(L.length>1)){for(var N=1,S=L.length;N=A;O--){G=I[O];G.style.display="none";}}this._nDisplayedItems=A;this.containerPopulateEvent.fire(this,K,R);if(this.autoHighlight){var D=this._elList.firstChild;this._toggleHighlight(D,"to");this.itemArrowToEvent.fire(this,D);this._typeAhead(D,K);}else{this._toggleHighlight(this._elCurListItem,"from");}H=this._doBeforeExpandContainer(this._elTextbox,this._elContainer,K,R);this._toggleContainer(H);}else{this._toggleContainer(false);}return;}}else{this.dataErrorEvent.fire(this,K,F);}};YAHOO.widget.AutoComplete.prototype._doBeforeExpandContainer=function(D,A,C,B){if(this.autoSnapContainer){this.snapContainer();}return this.doBeforeExpandContainer(D,A,C,B);};YAHOO.widget.AutoComplete.prototype._clearSelection=function(){var A=(this.delimChar)?this._extractQuery(this._elTextbox.value):{previous:"",query:this._elTextbox.value};this._elTextbox.value=A.previous;this.selectionEnforceEvent.fire(this,A.query);};YAHOO.widget.AutoComplete.prototype._textMatchesOption=function(){var A=null;for(var B=0;B=0;B--){G=H.lastIndexOf(C[B]);if(G>F){F=G;}}if(C[B]==" "){for(var A=C.length-1;A>=0;A--){if(H[F-1]==C[A]){F--;break;}}}if(F>-1){E=F+1;while(H.charAt(E)==" "){E+=1;}D=H.substring(0,E);H=H.substr(E);}else{D="";}return{previous:D,query:H};};YAHOO.widget.AutoComplete.prototype._toggleContainerHelpers=function(D){var E=this._elContent.offsetWidth+"px";var B=this._elContent.offsetHeight+"px";if(this.useIFrame&&this._elIFrame){var C=this._elIFrame;if(D){C.style.width=E;C.style.height=B;C.style.padding="";}else{C.style.width=0;C.style.height=0;C.style.padding=0;}}if(this.useShadow&&this._elShadow){var A=this._elShadow;if(D){A.style.width=E;A.style.height=B;}else{A.style.width=0;A.style.height=0;}}};YAHOO.widget.AutoComplete.prototype._toggleContainer=function(I){var D=this._elContainer;if(this.alwaysShowContainer&&this._bContainerOpen){return;}if(!I){this._toggleHighlight(this._elCurListItem,"from");this._nDisplayedItems=0;this._sCurQuery=null;if(this._elContent.style.display=="none"){return;}}var A=this._oAnim;if(A&&A.getEl()&&(this.animHoriz||this.animVert)){if(A.isAnimated()){A.stop(true);}var G=this._elContent.cloneNode(true);D.appendChild(G);G.style.top="-9000px";G.style.width="";G.style.height="";G.style.display="";var F=G.offsetWidth;var C=G.offsetHeight;var B=(this.animHoriz)?0:F;var E=(this.animVert)?0:C;A.attributes=(I)?{width:{to:F},height:{to:C}}:{width:{to:B},height:{to:E}};if(I&&!this._bContainerOpen){this._elContent.style.width=B+"px";this._elContent.style.height=E+"px";}else{this._elContent.style.width=F+"px";this._elContent.style.height=C+"px";}D.removeChild(G);G=null;var H=this;var J=function(){A.onComplete.unsubscribeAll();if(I){H._toggleContainerHelpers(true);H._bContainerOpen=I;H.containerExpandEvent.fire(H);}else{H._elContent.style.display="none";H._bContainerOpen=I;H.containerCollapseEvent.fire(H);}};this._toggleContainerHelpers(false);this._elContent.style.display="";A.onComplete.subscribe(J);A.animate();}else{if(I){this._elContent.style.display="";this._toggleContainerHelpers(true);this._bContainerOpen=I;this.containerExpandEvent.fire(this);}else{this._toggleContainerHelpers(false);this._elContent.style.display="none";this._bContainerOpen=I;this.containerCollapseEvent.fire(this);}}};YAHOO.widget.AutoComplete.prototype._toggleHighlight=function(A,C){if(A){var B=this.highlightClassName; -if(this._elCurListItem){YAHOO.util.Dom.removeClass(this._elCurListItem,B);this._elCurListItem=null;}if((C=="to")&&B){YAHOO.util.Dom.addClass(A,B);this._elCurListItem=A;}}};YAHOO.widget.AutoComplete.prototype._togglePrehighlight=function(B,C){var A=this.prehighlightClassName;if(this._elCurPrehighlightItem){YAHOO.util.Dom.removeClass(this._elCurPrehighlightItem,A);}if(B==this._elCurListItem){return;}if((C=="mouseover")&&A){YAHOO.util.Dom.addClass(B,A);this._elCurPrehighlightItem=B;}else{YAHOO.util.Dom.removeClass(B,A);}};YAHOO.widget.AutoComplete.prototype._updateValue=function(C){if(!this.suppressInputUpdate){var F=this._elTextbox;var E=(this.delimChar)?(this.delimChar[0]||this.delimChar):null;var B=C._sResultMatch;var D="";if(E){D=this._sPastSelections;D+=B+E;if(E!=" "){D+=" ";}}else{D=B;}F.value=D;if(F.type=="textarea"){F.scrollTop=F.scrollHeight;}var A=F.value.length;this._selectText(F,A,A);this._elCurListItem=C;}};YAHOO.widget.AutoComplete.prototype._selectItem=function(A){this._bItemSelected=true;this._updateValue(A);this._sPastSelections=this._elTextbox.value;this._clearInterval();this.itemSelectEvent.fire(this,A,A._oResultData);this._toggleContainer(false);};YAHOO.widget.AutoComplete.prototype._jumpSelection=function(){if(this._elCurListItem){this._selectItem(this._elCurListItem);}else{this._toggleContainer(false);}};YAHOO.widget.AutoComplete.prototype._moveSelection=function(G){if(this._bContainerOpen){var H=this._elCurListItem,D=-1;if(H){D=H._nItemIndex;}var E=(G==40)?(D+1):(D-1);if(E<-2||E>=this._nDisplayedItems){return;}if(H){this._toggleHighlight(H,"from");this.itemArrowFromEvent.fire(this,H);}if(E==-1){if(this.delimChar){this._elTextbox.value=this._sPastSelections+this._sCurQuery;}else{this._elTextbox.value=this._sCurQuery;}return;}if(E==-2){this._toggleContainer(false);return;}var F=this._elList.childNodes[E],B=this._elContent,C=YAHOO.util.Dom.getStyle(B,"overflow"),I=YAHOO.util.Dom.getStyle(B,"overflowY"),A=((C=="auto")||(C=="scroll")||(I=="auto")||(I=="scroll"));if(A&&(E>-1)&&(E(B.scrollTop+B.offsetHeight)){B.scrollTop=(F.offsetTop+F.offsetHeight)-B.offsetHeight;}else{if((F.offsetTop+F.offsetHeight)(B.scrollTop+B.offsetHeight)){this._elContent.scrollTop=(F.offsetTop+F.offsetHeight)-B.offsetHeight;}}}}this._toggleHighlight(F,"to");this.itemArrowToEvent.fire(this,F);if(this.typeAhead){this._updateValue(F);}}};YAHOO.widget.AutoComplete.prototype._onContainerMouseover=function(A,C){var D=YAHOO.util.Event.getTarget(A);var B=D.nodeName.toLowerCase();while(D&&(B!="table")){switch(B){case"body":return;case"li":if(C.prehighlightClassName){C._togglePrehighlight(D,"mouseover");}else{C._toggleHighlight(D,"to");}C.itemMouseOverEvent.fire(C,D);break;case"div":if(YAHOO.util.Dom.hasClass(D,"yui-ac-container")){C._bOverContainer=true;return;}break;default:break;}D=D.parentNode;if(D){B=D.nodeName.toLowerCase();}}};YAHOO.widget.AutoComplete.prototype._onContainerMouseout=function(A,C){var D=YAHOO.util.Event.getTarget(A);var B=D.nodeName.toLowerCase();while(D&&(B!="table")){switch(B){case"body":return;case"li":if(C.prehighlightClassName){C._togglePrehighlight(D,"mouseout");}else{C._toggleHighlight(D,"from");}C.itemMouseOutEvent.fire(C,D);break;case"ul":C._toggleHighlight(C._elCurListItem,"to");break;case"div":if(YAHOO.util.Dom.hasClass(D,"yui-ac-container")){C._bOverContainer=false;return;}break;default:break;}D=D.parentNode;if(D){B=D.nodeName.toLowerCase();}}};YAHOO.widget.AutoComplete.prototype._onContainerClick=function(A,C){var D=YAHOO.util.Event.getTarget(A);var B=D.nodeName.toLowerCase();while(D&&(B!="table")){switch(B){case"body":return;case"li":C._toggleHighlight(D,"to");C._selectItem(D);return;default:break;}D=D.parentNode;if(D){B=D.nodeName.toLowerCase();}}};YAHOO.widget.AutoComplete.prototype._onContainerScroll=function(A,B){B._focus();};YAHOO.widget.AutoComplete.prototype._onContainerResize=function(A,B){B._toggleContainerHelpers(B._bContainerOpen);};YAHOO.widget.AutoComplete.prototype._onTextboxKeyDown=function(A,B){var C=A.keyCode;if(B._nTypeAheadDelayID!=-1){clearTimeout(B._nTypeAheadDelayID);}switch(C){case 9:if(!YAHOO.env.ua.opera&&(navigator.userAgent.toLowerCase().indexOf("mac")==-1)||(YAHOO.env.ua.webkit>420)){if(B._elCurListItem){if(B.delimChar&&(B._nKeyCode!=C)){if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);}}B._selectItem(B._elCurListItem);}else{B._toggleContainer(false);}}break;case 13:if(!YAHOO.env.ua.opera&&(navigator.userAgent.toLowerCase().indexOf("mac")==-1)||(YAHOO.env.ua.webkit>420)){if(B._elCurListItem){if(B._nKeyCode!=C){if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);}}B._selectItem(B._elCurListItem);}else{B._toggleContainer(false);}}break;case 27:B._toggleContainer(false);return;case 39:B._jumpSelection();break;case 38:if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);B._moveSelection(C);}break;case 40:if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);B._moveSelection(C);}break;default:B._bItemSelected=false;B._toggleHighlight(B._elCurListItem,"from");B.textboxKeyEvent.fire(B,C);break;}if(C===18){B._enableIntervalDetection();}B._nKeyCode=C;};YAHOO.widget.AutoComplete.prototype._onTextboxKeyPress=function(A,B){var C=A.keyCode;if(YAHOO.env.ua.opera||(navigator.userAgent.toLowerCase().indexOf("mac")!=-1)&&(YAHOO.env.ua.webkit<420)){switch(C){case 9:if(B._bContainerOpen){if(B.delimChar){YAHOO.util.Event.stopEvent(A);}if(B._elCurListItem){B._selectItem(B._elCurListItem);}else{B._toggleContainer(false);}}break;case 13:if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);if(B._elCurListItem){B._selectItem(B._elCurListItem);}else{B._toggleContainer(false);}}break;default:break;}}else{if(C==229){B._enableIntervalDetection();}}};YAHOO.widget.AutoComplete.prototype._onTextboxKeyUp=function(A,C){var B=this.value;C._initProps();var D=A.keyCode;if(C._isIgnoreKey(D)){return; -}if(C._nDelayID!=-1){clearTimeout(C._nDelayID);}C._nDelayID=setTimeout(function(){C._sendQuery(B);},(C.queryDelay*1000));};YAHOO.widget.AutoComplete.prototype._onTextboxFocus=function(A,B){if(!B._bFocused){B._elTextbox.setAttribute("autocomplete","off");B._bFocused=true;B._sInitInputValue=B._elTextbox.value;B.textboxFocusEvent.fire(B);}};YAHOO.widget.AutoComplete.prototype._onTextboxBlur=function(A,C){if(!C._bOverContainer||(C._nKeyCode==9)){if(!C._bItemSelected){var B=C._textMatchesOption();if(!C._bContainerOpen||(C._bContainerOpen&&(B===null))){if(C.forceSelection){C._clearSelection();}else{C.unmatchedItemSelectEvent.fire(C,C._sCurQuery);}}else{if(C.forceSelection){C._selectItem(B);}}}C._clearInterval();C._bFocused=false;if(C._sInitInputValue!==C._elTextbox.value){C.textboxChangeEvent.fire(C);}C.textboxBlurEvent.fire(C);C._toggleContainer(false);}else{C._focus();}};YAHOO.widget.AutoComplete.prototype._onWindowUnload=function(A,B){if(B&&B._elTextbox&&B.allowBrowserAutocomplete){B._elTextbox.setAttribute("autocomplete","on");}};YAHOO.widget.AutoComplete.prototype.doBeforeSendQuery=function(A){return this.generateRequest(A);};YAHOO.widget.AutoComplete.prototype.getListItems=function(){var C=[],B=this._elList.childNodes;for(var A=B.length-1;A>=0;A--){C[A]=B[A];}return C;};YAHOO.widget.AutoComplete._cloneObject=function(D){if(!YAHOO.lang.isValue(D)){return D;}var F={};if(YAHOO.lang.isFunction(D)){F=D;}else{if(YAHOO.lang.isArray(D)){var E=[];for(var C=0,B=D.length;C - *
  • Navigate with up/down arrow keys and/or mouse to pick a selection
  • - *
  • The drop down container can "roll down" or "fly out" via configurable - * animation
  • - *
  • UI look-and-feel customizable through CSS, including container - * attributes, borders, position, fonts, etc
  • - * - * - * @class AutoComplete - * @constructor - * @param elInput {HTMLElement} DOM element reference of an input field. - * @param elInput {String} String ID of an input field. - * @param elContainer {HTMLElement} DOM element reference of an existing DIV. - * @param elContainer {String} String ID of an existing DIV. - * @param oDataSource {YAHOO.widget.DataSource} DataSource instance. - * @param oConfigs {Object} (optional) Object literal of configuration params. - */ -YAHOO.widget.AutoComplete = function(elInput,elContainer,oDataSource,oConfigs) { - if(elInput && elContainer && oDataSource) { - // Validate DataSource - if(oDataSource && YAHOO.lang.isFunction(oDataSource.sendRequest)) { - this.dataSource = oDataSource; - } - else { - return; - } - - // YAHOO.widget.DataSource schema backwards compatibility - // Converted deprecated schema into supported schema - // First assume key data is held in position 0 of results array - this.key = 0; - var schema = oDataSource.responseSchema; - // An old school schema has been defined in the deprecated DataSource constructor - if(oDataSource._aDeprecatedSchema) { - var aDeprecatedSchema = oDataSource._aDeprecatedSchema; - if(YAHOO.lang.isArray(aDeprecatedSchema)) { - - if((oDataSource.responseType === YAHOO.util.DataSourceBase.TYPE_JSON) || - (oDataSource.responseType === YAHOO.util.DataSourceBase.TYPE_UNKNOWN)) { // Used to default to unknown - // Store the resultsList - schema.resultsList = aDeprecatedSchema[0]; - // Store the key - this.key = aDeprecatedSchema[1]; - // Only resultsList and key are defined, so grab all the data - schema.fields = (aDeprecatedSchema.length < 3) ? null : aDeprecatedSchema.slice(1); - } - else if(oDataSource.responseType === YAHOO.util.DataSourceBase.TYPE_XML) { - schema.resultNode = aDeprecatedSchema[0]; - this.key = aDeprecatedSchema[1]; - schema.fields = aDeprecatedSchema.slice(1); - } - else if(oDataSource.responseType === YAHOO.util.DataSourceBase.TYPE_TEXT) { - schema.recordDelim = aDeprecatedSchema[0]; - schema.fieldDelim = aDeprecatedSchema[1]; - } - oDataSource.responseSchema = schema; - } - } - - // Validate input element - if(YAHOO.util.Dom.inDocument(elInput)) { - if(YAHOO.lang.isString(elInput)) { - this._sName = "instance" + YAHOO.widget.AutoComplete._nIndex + " " + elInput; - this._elTextbox = document.getElementById(elInput); - } - else { - this._sName = (elInput.id) ? - "instance" + YAHOO.widget.AutoComplete._nIndex + " " + elInput.id: - "instance" + YAHOO.widget.AutoComplete._nIndex; - this._elTextbox = elInput; - } - YAHOO.util.Dom.addClass(this._elTextbox, "yui-ac-input"); - } - else { - return; - } - - // Validate container element - if(YAHOO.util.Dom.inDocument(elContainer)) { - if(YAHOO.lang.isString(elContainer)) { - this._elContainer = document.getElementById(elContainer); - } - else { - this._elContainer = elContainer; - } - if(this._elContainer.style.display == "none") { - } - - // For skinning - var elParent = this._elContainer.parentNode; - var elTag = elParent.tagName.toLowerCase(); - if(elTag == "div") { - YAHOO.util.Dom.addClass(elParent, "yui-ac"); - } - else { - } - } - else { - return; - } - - // Default applyLocalFilter setting is to enable for local sources - if(this.dataSource.dataType === YAHOO.util.DataSourceBase.TYPE_LOCAL) { - this.applyLocalFilter = true; - } - - // Set any config params passed in to override defaults - if(oConfigs && (oConfigs.constructor == Object)) { - for(var sConfig in oConfigs) { - if(sConfig) { - this[sConfig] = oConfigs[sConfig]; - } - } - } - - // Initialization sequence - this._initContainerEl(); - this._initProps(); - this._initListEl(); - this._initContainerHelperEls(); - - // Set up events - var oSelf = this; - var elTextbox = this._elTextbox; - - // Dom events - YAHOO.util.Event.addListener(elTextbox,"keyup",oSelf._onTextboxKeyUp,oSelf); - YAHOO.util.Event.addListener(elTextbox,"keydown",oSelf._onTextboxKeyDown,oSelf); - YAHOO.util.Event.addListener(elTextbox,"focus",oSelf._onTextboxFocus,oSelf); - YAHOO.util.Event.addListener(elTextbox,"blur",oSelf._onTextboxBlur,oSelf); - YAHOO.util.Event.addListener(elContainer,"mouseover",oSelf._onContainerMouseover,oSelf); - YAHOO.util.Event.addListener(elContainer,"mouseout",oSelf._onContainerMouseout,oSelf); - YAHOO.util.Event.addListener(elContainer,"click",oSelf._onContainerClick,oSelf); - YAHOO.util.Event.addListener(elContainer,"scroll",oSelf._onContainerScroll,oSelf); - YAHOO.util.Event.addListener(elContainer,"resize",oSelf._onContainerResize,oSelf); - YAHOO.util.Event.addListener(elTextbox,"keypress",oSelf._onTextboxKeyPress,oSelf); - YAHOO.util.Event.addListener(window,"unload",oSelf._onWindowUnload,oSelf); - - // Custom events - this.textboxFocusEvent = new YAHOO.util.CustomEvent("textboxFocus", this); - this.textboxKeyEvent = new YAHOO.util.CustomEvent("textboxKey", this); - this.dataRequestEvent = new YAHOO.util.CustomEvent("dataRequest", this); - this.dataReturnEvent = new YAHOO.util.CustomEvent("dataReturn", this); - this.dataErrorEvent = new YAHOO.util.CustomEvent("dataError", this); - this.containerPopulateEvent = new YAHOO.util.CustomEvent("containerPopulate", this); - this.containerExpandEvent = new YAHOO.util.CustomEvent("containerExpand", this); - this.typeAheadEvent = new YAHOO.util.CustomEvent("typeAhead", this); - this.itemMouseOverEvent = new YAHOO.util.CustomEvent("itemMouseOver", this); - this.itemMouseOutEvent = new YAHOO.util.CustomEvent("itemMouseOut", this); - this.itemArrowToEvent = new YAHOO.util.CustomEvent("itemArrowTo", this); - this.itemArrowFromEvent = new YAHOO.util.CustomEvent("itemArrowFrom", this); - this.itemSelectEvent = new YAHOO.util.CustomEvent("itemSelect", this); - this.unmatchedItemSelectEvent = new YAHOO.util.CustomEvent("unmatchedItemSelect", this); - this.selectionEnforceEvent = new YAHOO.util.CustomEvent("selectionEnforce", this); - this.containerCollapseEvent = new YAHOO.util.CustomEvent("containerCollapse", this); - this.textboxBlurEvent = new YAHOO.util.CustomEvent("textboxBlur", this); - this.textboxChangeEvent = new YAHOO.util.CustomEvent("textboxChange", this); - - // Finish up - elTextbox.setAttribute("autocomplete","off"); - YAHOO.widget.AutoComplete._nIndex++; - } - // Required arguments were not found - else { - } -}; - -///////////////////////////////////////////////////////////////////////////// -// -// Public member variables -// -///////////////////////////////////////////////////////////////////////////// - -/** - * The DataSource object that encapsulates the data used for auto completion. - * This object should be an inherited object from YAHOO.widget.DataSource. - * - * @property dataSource - * @type YAHOO.widget.DataSource - */ -YAHOO.widget.AutoComplete.prototype.dataSource = null; - -/** - * By default, results from local DataSources will pass through the filterResults - * method to apply a client-side matching algorithm. - * - * @property applyLocalFilter - * @type Boolean - * @default true for local arrays and json, otherwise false - */ -YAHOO.widget.AutoComplete.prototype.applyLocalFilter = null; - -/** - * When applyLocalFilter is true, the local filtering algorthim can have case sensitivity - * enabled. - * - * @property queryMatchCase - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.queryMatchCase = false; - -/** - * When applyLocalFilter is true, results can be locally filtered to return - * matching strings that "contain" the query string rather than simply "start with" - * the query string. - * - * @property queryMatchContains - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.queryMatchContains = false; - -/** - * Enables query subset matching. When the DataSource's cache is enabled and queryMatchSubset is - * true, substrings of queries will return matching cached results. For - * instance, if the first query is for "abc" susequent queries that start with - * "abc", like "abcd", will be queried against the cache, and not the live data - * source. Recommended only for DataSources that return comprehensive results - * for queries with very few characters. - * - * @property queryMatchSubset - * @type Boolean - * @default false - * - */ -YAHOO.widget.AutoComplete.prototype.queryMatchSubset = false; - -/** - * Number of characters that must be entered before querying for results. A negative value - * effectively turns off the widget. A value of 0 allows queries of null or empty string - * values. - * - * @property minQueryLength - * @type Number - * @default 1 - */ -YAHOO.widget.AutoComplete.prototype.minQueryLength = 1; - -/** - * Maximum number of results to display in results container. - * - * @property maxResultsDisplayed - * @type Number - * @default 10 - */ -YAHOO.widget.AutoComplete.prototype.maxResultsDisplayed = 10; - -/** - * Number of seconds to delay before submitting a query request. If a query - * request is received before a previous one has completed its delay, the - * previous request is cancelled and the new request is set to the delay. If - * typeAhead is also enabled, this value must always be less than the typeAheadDelay - * in order to avoid certain race conditions. - * - * @property queryDelay - * @type Number - * @default 0.2 - */ -YAHOO.widget.AutoComplete.prototype.queryDelay = 0.2; - -/** - * If typeAhead is true, number of seconds to delay before updating input with - * typeAhead value. In order to prevent certain race conditions, this value must - * always be greater than the queryDelay. - * - * @property typeAheadDelay - * @type Number - * @default 0.5 - */ -YAHOO.widget.AutoComplete.prototype.typeAheadDelay = 0.5; - -/** - * When IME usage is detected or interval detection is explicitly enabled, - * AutoComplete will detect the input value at the given interval and send a - * query if the value has changed. - * - * @property queryInterval - * @type Number - * @default 500 - */ -YAHOO.widget.AutoComplete.prototype.queryInterval = 500; - -/** - * Class name of a highlighted item within results container. - * - * @property highlightClassName - * @type String - * @default "yui-ac-highlight" - */ -YAHOO.widget.AutoComplete.prototype.highlightClassName = "yui-ac-highlight"; - -/** - * Class name of a pre-highlighted item within results container. - * - * @property prehighlightClassName - * @type String - */ -YAHOO.widget.AutoComplete.prototype.prehighlightClassName = null; - -/** - * Query delimiter. A single character separator for multiple delimited - * selections. Multiple delimiter characteres may be defined as an array of - * strings. A null value or empty string indicates that query results cannot - * be delimited. This feature is not recommended if you need forceSelection to - * be true. - * - * @property delimChar - * @type String | String[] - */ -YAHOO.widget.AutoComplete.prototype.delimChar = null; - -/** - * Whether or not the first item in results container should be automatically highlighted - * on expand. - * - * @property autoHighlight - * @type Boolean - * @default true - */ -YAHOO.widget.AutoComplete.prototype.autoHighlight = true; - -/** - * If autohighlight is enabled, whether or not the input field should be automatically updated - * with the first query result as the user types, auto-selecting the substring portion - * of the first result that the user has not yet typed. - * - * @property typeAhead - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.typeAhead = false; - -/** - * Whether or not to animate the expansion/collapse of the results container in the - * horizontal direction. - * - * @property animHoriz - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.animHoriz = false; - -/** - * Whether or not to animate the expansion/collapse of the results container in the - * vertical direction. - * - * @property animVert - * @type Boolean - * @default true - */ -YAHOO.widget.AutoComplete.prototype.animVert = true; - -/** - * Speed of container expand/collapse animation, in seconds.. - * - * @property animSpeed - * @type Number - * @default 0.3 - */ -YAHOO.widget.AutoComplete.prototype.animSpeed = 0.3; - -/** - * Whether or not to force the user's selection to match one of the query - * results. Enabling this feature essentially transforms the input field into a - * <select> field. This feature is not recommended with delimiter character(s) - * defined. - * - * @property forceSelection - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.forceSelection = false; - -/** - * Whether or not to allow browsers to cache user-typed input in the input - * field. Disabling this feature will prevent the widget from setting the - * autocomplete="off" on the input field. When autocomplete="off" - * and users click the back button after form submission, user-typed input can - * be prefilled by the browser from its cache. This caching of user input may - * not be desired for sensitive data, such as credit card numbers, in which - * case, implementers should consider setting allowBrowserAutocomplete to false. - * - * @property allowBrowserAutocomplete - * @type Boolean - * @default true - */ -YAHOO.widget.AutoComplete.prototype.allowBrowserAutocomplete = true; - -/** - * Enabling this feature prevents the toggling of the container to a collapsed state. - * Setting to true does not automatically trigger the opening of the container. - * Implementers are advised to pre-load the container with an explicit "sendQuery()" call. - * - * @property alwaysShowContainer - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.alwaysShowContainer = false; - -/** - * Whether or not to use an iFrame to layer over Windows form elements in - * IE. Set to true only when the results container will be on top of a - * <select> field in IE and thus exposed to the IE z-index bug (i.e., - * 5.5 < IE < 7). - * - * @property useIFrame - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.useIFrame = false; - -/** - * Whether or not the results container should have a shadow. - * - * @property useShadow - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.useShadow = false; - -/** - * Whether or not the input field should be updated with selections. - * - * @property suppressInputUpdate - * @type Boolean - * @default false - */ -YAHOO.widget.AutoComplete.prototype.suppressInputUpdate = false; - -/** - * For backward compatibility to pre-2.6.0 formatResults() signatures, setting - * resultsTypeList to true will take each object literal result returned by - * DataSource and flatten into an array. - * - * @property resultTypeList - * @type Boolean - * @default true - */ -YAHOO.widget.AutoComplete.prototype.resultTypeList = true; - -/** - * For XHR DataSources, AutoComplete will automatically insert a "?" between the server URI and - * the "query" param/value pair. To prevent this behavior, implementers should - * set this value to false. To more fully customize the query syntax, implementers - * should override the generateRequest() method. - * - * @property queryQuestionMark - * @type Boolean - * @default true - */ -YAHOO.widget.AutoComplete.prototype.queryQuestionMark = true; - -/** - * If true, before each time the container expands, the container element will be - * positioned to snap to the bottom-left corner of the input element. If - * autoSnapContainer is set to false, this positioning will not be done. - * - * @property autoSnapContainer - * @type Boolean - * @default true - */ -YAHOO.widget.AutoComplete.prototype.autoSnapContainer = true; - -///////////////////////////////////////////////////////////////////////////// -// -// Public methods -// -///////////////////////////////////////////////////////////////////////////// - - /** - * Public accessor to the unique name of the AutoComplete instance. - * - * @method toString - * @return {String} Unique name of the AutoComplete instance. - */ -YAHOO.widget.AutoComplete.prototype.toString = function() { - return "AutoComplete " + this._sName; -}; - - /** - * Returns DOM reference to input element. - * - * @method getInputEl - * @return {HTMLELement} DOM reference to input element. - */ -YAHOO.widget.AutoComplete.prototype.getInputEl = function() { - return this._elTextbox; -}; - - /** - * Returns DOM reference to container element. - * - * @method getContainerEl - * @return {HTMLELement} DOM reference to container element. - */ -YAHOO.widget.AutoComplete.prototype.getContainerEl = function() { - return this._elContainer; -}; - - /** - * Returns true if widget instance is currently active. - * - * @method isFocused - * @return {Boolean} Returns true if widget instance is currently active. - */ -YAHOO.widget.AutoComplete.prototype.isFocused = function() { - return this._bFocused; -}; - - /** - * Returns true if container is in an expanded state, false otherwise. - * - * @method isContainerOpen - * @return {Boolean} Returns true if container is in an expanded state, false otherwise. - */ -YAHOO.widget.AutoComplete.prototype.isContainerOpen = function() { - return this._bContainerOpen; -}; - -/** - * Public accessor to the <ul> element that displays query results within the results container. - * - * @method getListEl - * @return {HTMLElement[]} Reference to <ul> element within the results container. - */ -YAHOO.widget.AutoComplete.prototype.getListEl = function() { - return this._elList; -}; - -/** - * Public accessor to the matching string associated with a given <li> result. - * - * @method getListItemMatch - * @param elListItem {HTMLElement} Reference to <LI> element. - * @return {String} Matching string. - */ -YAHOO.widget.AutoComplete.prototype.getListItemMatch = function(elListItem) { - if(elListItem._sResultMatch) { - return elListItem._sResultMatch; - } - else { - return null; - } -}; - -/** - * Public accessor to the result data associated with a given <li> result. - * - * @method getListItemData - * @param elListItem {HTMLElement} Reference to <LI> element. - * @return {Object} Result data. - */ -YAHOO.widget.AutoComplete.prototype.getListItemData = function(elListItem) { - if(elListItem._oResultData) { - return elListItem._oResultData; - } - else { - return null; - } -}; - -/** - * Public accessor to the index of the associated with a given <li> result. - * - * @method getListItemIndex - * @param elListItem {HTMLElement} Reference to <LI> element. - * @return {Number} Index. - */ -YAHOO.widget.AutoComplete.prototype.getListItemIndex = function(elListItem) { - if(YAHOO.lang.isNumber(elListItem._nItemIndex)) { - return elListItem._nItemIndex; - } - else { - return null; - } -}; - -/** - * Sets HTML markup for the results container header. This markup will be - * inserted within a <div> tag with a class of "yui-ac-hd". - * - * @method setHeader - * @param sHeader {String} HTML markup for results container header. - */ -YAHOO.widget.AutoComplete.prototype.setHeader = function(sHeader) { - if(this._elHeader) { - var elHeader = this._elHeader; - if(sHeader) { - elHeader.innerHTML = sHeader; - elHeader.style.display = ""; - } - else { - elHeader.innerHTML = ""; - elHeader.style.display = "none"; - } - } -}; - -/** - * Sets HTML markup for the results container footer. This markup will be - * inserted within a <div> tag with a class of "yui-ac-ft". - * - * @method setFooter - * @param sFooter {String} HTML markup for results container footer. - */ -YAHOO.widget.AutoComplete.prototype.setFooter = function(sFooter) { - if(this._elFooter) { - var elFooter = this._elFooter; - if(sFooter) { - elFooter.innerHTML = sFooter; - elFooter.style.display = ""; - } - else { - elFooter.innerHTML = ""; - elFooter.style.display = "none"; - } - } -}; - -/** - * Sets HTML markup for the results container body. This markup will be - * inserted within a <div> tag with a class of "yui-ac-bd". - * - * @method setBody - * @param sBody {String} HTML markup for results container body. - */ -YAHOO.widget.AutoComplete.prototype.setBody = function(sBody) { - if(this._elBody) { - var elBody = this._elBody; - YAHOO.util.Event.purgeElement(elBody, true); - if(sBody) { - elBody.innerHTML = sBody; - elBody.style.display = ""; - } - else { - elBody.innerHTML = ""; - elBody.style.display = "none"; - } - this._elList = null; - } -}; - -/** -* A function that converts an AutoComplete query into a request value which is then -* passed to the DataSource's sendRequest method in order to retrieve data for -* the query. By default, returns a String with the syntax: "query={query}" -* Implementers can customize this method for custom request syntaxes. -* -* @method generateRequest -* @param sQuery {String} Query string -* @return {MIXED} Request -*/ -YAHOO.widget.AutoComplete.prototype.generateRequest = function(sQuery) { - var dataType = this.dataSource.dataType; - - // Transform query string in to a request for remote data - // By default, local data doesn't need a transformation, just passes along the query as is. - if(dataType === YAHOO.util.DataSourceBase.TYPE_XHR) { - // By default, XHR GET requests look like "{scriptURI}?{scriptQueryParam}={sQuery}&{scriptQueryAppend}" - if(!this.dataSource.connMethodPost) { - sQuery = (this.queryQuestionMark ? "?" : "") + (this.dataSource.scriptQueryParam || "query") + "=" + sQuery + - (this.dataSource.scriptQueryAppend ? ("&" + this.dataSource.scriptQueryAppend) : ""); - } - // By default, XHR POST bodies are sent to the {scriptURI} like "{scriptQueryParam}={sQuery}&{scriptQueryAppend}" - else { - sQuery = (this.dataSource.scriptQueryParam || "query") + "=" + sQuery + - (this.dataSource.scriptQueryAppend ? ("&" + this.dataSource.scriptQueryAppend) : ""); - } - } - // By default, remote script node requests look like "{scriptURI}&{scriptCallbackParam}={callbackString}&{scriptQueryParam}={sQuery}&{scriptQueryAppend}" - else if(dataType === YAHOO.util.DataSourceBase.TYPE_SCRIPTNODE) { - sQuery = "&" + (this.dataSource.scriptQueryParam || "query") + "=" + sQuery + - (this.dataSource.scriptQueryAppend ? ("&" + this.dataSource.scriptQueryAppend) : ""); - } - - return sQuery; -}; - -/** - * Makes query request to the DataSource. - * - * @method sendQuery - * @param sQuery {String} Query string. - */ -YAHOO.widget.AutoComplete.prototype.sendQuery = function(sQuery) { - // Activate focus for a new interaction - this._bFocused = true; - - // Adjust programatically sent queries to look like they were input by user - // when delimiters are enabled - var newQuery = (this.delimChar) ? this._elTextbox.value + sQuery : sQuery; - this._sendQuery(newQuery); -}; - -/** - * Snaps container to bottom-left corner of input element - * - * @method snapContainer - */ -YAHOO.widget.AutoComplete.prototype.snapContainer = function() { - var oTextbox = this._elTextbox, - pos = YAHOO.util.Dom.getXY(oTextbox); - pos[1] += YAHOO.util.Dom.get(oTextbox).offsetHeight + 2; - YAHOO.util.Dom.setXY(this._elContainer,pos); -}; - -/** - * Expands container. - * - * @method expandContainer - */ -YAHOO.widget.AutoComplete.prototype.expandContainer = function() { - this._toggleContainer(true); -}; - -/** - * Collapses container. - * - * @method collapseContainer - */ -YAHOO.widget.AutoComplete.prototype.collapseContainer = function() { - this._toggleContainer(false); -}; - -/** - * Clears entire list of suggestions. - * - * @method clearList - */ -YAHOO.widget.AutoComplete.prototype.clearList = function() { - var allItems = this._elList.childNodes, - i=allItems.length-1; - for(; i>-1; i--) { - allItems[i].style.display = "none"; - } -}; - -/** - * Handles subset matching for when queryMatchSubset is enabled. - * - * @method getSubsetMatches - * @param sQuery {String} Query string. - * @return {Object} oParsedResponse or null. - */ -YAHOO.widget.AutoComplete.prototype.getSubsetMatches = function(sQuery) { - var subQuery, oCachedResponse, subRequest; - // Loop through substrings of each cached element's query property... - for(var i = sQuery.length; i >= this.minQueryLength ; i--) { - subRequest = this.generateRequest(sQuery.substr(0,i)); - this.dataRequestEvent.fire(this, subQuery, subRequest); - - // If a substring of the query is found in the cache - oCachedResponse = this.dataSource.getCachedResponse(subRequest); - if(oCachedResponse) { - return this.filterResults.apply(this.dataSource, [sQuery, oCachedResponse, oCachedResponse, {scope:this}]); - } - } - return null; -}; - -/** - * Executed by DataSource (within DataSource scope via doBeforeParseData()) to - * handle responseStripAfter cleanup. - * - * @method preparseRawResponse - * @param sQuery {String} Query string. - * @return {Object} oParsedResponse or null. - */ -YAHOO.widget.AutoComplete.prototype.preparseRawResponse = function(oRequest, oFullResponse, oCallback) { - var nEnd = ((this.responseStripAfter !== "") && (oFullResponse.indexOf)) ? - oFullResponse.indexOf(this.responseStripAfter) : -1; - if(nEnd != -1) { - oFullResponse = oFullResponse.substring(0,nEnd); - } - return oFullResponse; -}; - -/** - * Executed by DataSource (within DataSource scope via doBeforeCallback()) to - * filter results through a simple client-side matching algorithm. - * - * @method filterResults - * @param sQuery {String} Original request. - * @param oFullResponse {Object} Full response object. - * @param oParsedResponse {Object} Parsed response object. - * @param oCallback {Object} Callback object. - * @return {Object} Filtered response object. - */ - -YAHOO.widget.AutoComplete.prototype.filterResults = function(sQuery, oFullResponse, oParsedResponse, oCallback) { - // If AC has passed a query string value back to itself, grab it - if(oCallback && oCallback.argument && oCallback.argument.query) { - sQuery = oCallback.argument.query; - } - - // Only if a query string is available to match against - if(sQuery && sQuery !== "") { - // First make a copy of the oParseResponse - oParsedResponse = YAHOO.widget.AutoComplete._cloneObject(oParsedResponse); - - var oAC = oCallback.scope, - oDS = this, - allResults = oParsedResponse.results, // the array of results - filteredResults = [], // container for filtered results, - nMax = oAC.maxResultsDisplayed, // max to find - bMatchCase = (oDS.queryMatchCase || oAC.queryMatchCase), // backward compat - bMatchContains = (oDS.queryMatchContains || oAC.queryMatchContains); // backward compat - - // Loop through each result object... - for(var i=0, len=allResults.length; i -1))) { - // Stash the match - filteredResults.push(oResult); - } - } - - // Filter no more if maxResultsDisplayed is reached - if(len>nMax && filteredResults.length===nMax) { - break; - } - } - oParsedResponse.results = filteredResults; - } - else { - } - - return oParsedResponse; -}; - -/** - * Handles response for display. This is the callback function method passed to - * YAHOO.util.DataSourceBase#sendRequest so results from the DataSource are - * returned to the AutoComplete instance. - * - * @method handleResponse - * @param sQuery {String} Original request. - * @param oResponse {Object} Response object. - * @param oPayload {MIXED} (optional) Additional argument(s) - */ -YAHOO.widget.AutoComplete.prototype.handleResponse = function(sQuery, oResponse, oPayload) { - if((this instanceof YAHOO.widget.AutoComplete) && this._sName) { - this._populateList(sQuery, oResponse, oPayload); - } -}; - -/** - * Overridable method called before container is loaded with result data. - * - * @method doBeforeLoadData - * @param sQuery {String} Original request. - * @param oResponse {Object} Response object. - * @param oPayload {MIXED} (optional) Additional argument(s) - * @return {Boolean} Return true to continue loading data, false to cancel. - */ -YAHOO.widget.AutoComplete.prototype.doBeforeLoadData = function(sQuery, oResponse, oPayload) { - return true; -}; - -/** - * Overridable method that returns HTML markup for one result to be populated - * as innerHTML of an <LI> element. - * - * @method formatResult - * @param oResultData {Object} Result data object. - * @param sQuery {String} The corresponding query string. - * @param sResultMatch {HTMLElement} The current query string. - * @return {String} HTML markup of formatted result data. - */ -YAHOO.widget.AutoComplete.prototype.formatResult = function(oResultData, sQuery, sResultMatch) { - var sMarkup = (sResultMatch) ? sResultMatch : ""; - return sMarkup; -}; - -/** - * Overridable method called before container expands allows implementers to access data - * and DOM elements. - * - * @method doBeforeExpandContainer - * @param elTextbox {HTMLElement} The text input box. - * @param elContainer {HTMLElement} The container element. - * @param sQuery {String} The query string. - * @param aResults {Object[]} An array of query results. - * @return {Boolean} Return true to continue expanding container, false to cancel the expand. - */ -YAHOO.widget.AutoComplete.prototype.doBeforeExpandContainer = function(elTextbox, elContainer, sQuery, aResults) { - return true; -}; - - -/** - * Nulls out the entire AutoComplete instance and related objects, removes attached - * event listeners, and clears out DOM elements inside the container. After - * calling this method, the instance reference should be expliclitly nulled by - * implementer, as in myAutoComplete = null. Use with caution! - * - * @method destroy - */ -YAHOO.widget.AutoComplete.prototype.destroy = function() { - var instanceName = this.toString(); - var elInput = this._elTextbox; - var elContainer = this._elContainer; - - // Unhook custom events - this.textboxFocusEvent.unsubscribeAll(); - this.textboxKeyEvent.unsubscribeAll(); - this.dataRequestEvent.unsubscribeAll(); - this.dataReturnEvent.unsubscribeAll(); - this.dataErrorEvent.unsubscribeAll(); - this.containerPopulateEvent.unsubscribeAll(); - this.containerExpandEvent.unsubscribeAll(); - this.typeAheadEvent.unsubscribeAll(); - this.itemMouseOverEvent.unsubscribeAll(); - this.itemMouseOutEvent.unsubscribeAll(); - this.itemArrowToEvent.unsubscribeAll(); - this.itemArrowFromEvent.unsubscribeAll(); - this.itemSelectEvent.unsubscribeAll(); - this.unmatchedItemSelectEvent.unsubscribeAll(); - this.selectionEnforceEvent.unsubscribeAll(); - this.containerCollapseEvent.unsubscribeAll(); - this.textboxBlurEvent.unsubscribeAll(); - this.textboxChangeEvent.unsubscribeAll(); - - // Unhook DOM events - YAHOO.util.Event.purgeElement(elInput, true); - YAHOO.util.Event.purgeElement(elContainer, true); - - // Remove DOM elements - elContainer.innerHTML = ""; - - // Null out objects - for(var key in this) { - if(YAHOO.lang.hasOwnProperty(this, key)) { - this[key] = null; - } - } - -}; - -///////////////////////////////////////////////////////////////////////////// -// -// Public events -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Fired when the input field receives focus. - * - * @event textboxFocusEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - */ -YAHOO.widget.AutoComplete.prototype.textboxFocusEvent = null; - -/** - * Fired when the input field receives key input. - * - * @event textboxKeyEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param nKeycode {Number} The keycode number. - */ -YAHOO.widget.AutoComplete.prototype.textboxKeyEvent = null; - -/** - * Fired when the AutoComplete instance makes a request to the DataSource. - * - * @event dataRequestEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param sQuery {String} The query string. - * @param oRequest {Object} The request. - */ -YAHOO.widget.AutoComplete.prototype.dataRequestEvent = null; - -/** - * Fired when the AutoComplete instance receives query results from the data - * source. - * - * @event dataReturnEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param sQuery {String} The query string. - * @param aResults {Object[]} Results array. - */ -YAHOO.widget.AutoComplete.prototype.dataReturnEvent = null; - -/** - * Fired when the AutoComplete instance does not receive query results from the - * DataSource due to an error. - * - * @event dataErrorEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param sQuery {String} The query string. - * @param oResponse {Object} The response object, if available. - */ -YAHOO.widget.AutoComplete.prototype.dataErrorEvent = null; - -/** - * Fired when the results container is populated. - * - * @event containerPopulateEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - */ -YAHOO.widget.AutoComplete.prototype.containerPopulateEvent = null; - -/** - * Fired when the results container is expanded. - * - * @event containerExpandEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - */ -YAHOO.widget.AutoComplete.prototype.containerExpandEvent = null; - -/** - * Fired when the input field has been prefilled by the type-ahead - * feature. - * - * @event typeAheadEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param sQuery {String} The query string. - * @param sPrefill {String} The prefill string. - */ -YAHOO.widget.AutoComplete.prototype.typeAheadEvent = null; - -/** - * Fired when result item has been moused over. - * - * @event itemMouseOverEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param elItem {HTMLElement} The <li> element item moused to. - */ -YAHOO.widget.AutoComplete.prototype.itemMouseOverEvent = null; - -/** - * Fired when result item has been moused out. - * - * @event itemMouseOutEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param elItem {HTMLElement} The <li> element item moused from. - */ -YAHOO.widget.AutoComplete.prototype.itemMouseOutEvent = null; - -/** - * Fired when result item has been arrowed to. - * - * @event itemArrowToEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param elItem {HTMLElement} The <li> element item arrowed to. - */ -YAHOO.widget.AutoComplete.prototype.itemArrowToEvent = null; - -/** - * Fired when result item has been arrowed away from. - * - * @event itemArrowFromEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param elItem {HTMLElement} The <li> element item arrowed from. - */ -YAHOO.widget.AutoComplete.prototype.itemArrowFromEvent = null; - -/** - * Fired when an item is selected via mouse click, ENTER key, or TAB key. - * - * @event itemSelectEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param elItem {HTMLElement} The selected <li> element item. - * @param oData {Object} The data returned for the item, either as an object, - * or mapped from the schema into an array. - */ -YAHOO.widget.AutoComplete.prototype.itemSelectEvent = null; - -/** - * Fired when a user selection does not match any of the displayed result items. - * - * @event unmatchedItemSelectEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param sSelection {String} The selected string. - */ -YAHOO.widget.AutoComplete.prototype.unmatchedItemSelectEvent = null; - -/** - * Fired if forceSelection is enabled and the user's input has been cleared - * because it did not match one of the returned query results. - * - * @event selectionEnforceEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @param sClearedValue {String} The cleared value (including delimiters if applicable). - */ -YAHOO.widget.AutoComplete.prototype.selectionEnforceEvent = null; - -/** - * Fired when the results container is collapsed. - * - * @event containerCollapseEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - */ -YAHOO.widget.AutoComplete.prototype.containerCollapseEvent = null; - -/** - * Fired when the input field loses focus. - * - * @event textboxBlurEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - */ -YAHOO.widget.AutoComplete.prototype.textboxBlurEvent = null; - -/** - * Fired when the input field value has changed when it loses focus. - * - * @event textboxChangeEvent - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - */ -YAHOO.widget.AutoComplete.prototype.textboxChangeEvent = null; - -///////////////////////////////////////////////////////////////////////////// -// -// Private member variables -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Internal class variable to index multiple AutoComplete instances. - * - * @property _nIndex - * @type Number - * @default 0 - * @private - */ -YAHOO.widget.AutoComplete._nIndex = 0; - -/** - * Name of AutoComplete instance. - * - * @property _sName - * @type String - * @private - */ -YAHOO.widget.AutoComplete.prototype._sName = null; - -/** - * Text input field DOM element. - * - * @property _elTextbox - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elTextbox = null; - -/** - * Container DOM element. - * - * @property _elContainer - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elContainer = null; - -/** - * Reference to content element within container element. - * - * @property _elContent - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elContent = null; - -/** - * Reference to header element within content element. - * - * @property _elHeader - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elHeader = null; - -/** - * Reference to body element within content element. - * - * @property _elBody - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elBody = null; - -/** - * Reference to footer element within content element. - * - * @property _elFooter - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elFooter = null; - -/** - * Reference to shadow element within container element. - * - * @property _elShadow - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elShadow = null; - -/** - * Reference to iframe element within container element. - * - * @property _elIFrame - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elIFrame = null; - -/** - * Whether or not the widget instance is currently active. If query results come back - * but the user has already moved on, do not proceed with auto complete behavior. - * - * @property _bFocused - * @type Boolean - * @private - */ -YAHOO.widget.AutoComplete.prototype._bFocused = false; - -/** - * Animation instance for container expand/collapse. - * - * @property _oAnim - * @type Boolean - * @private - */ -YAHOO.widget.AutoComplete.prototype._oAnim = null; - -/** - * Whether or not the results container is currently open. - * - * @property _bContainerOpen - * @type Boolean - * @private - */ -YAHOO.widget.AutoComplete.prototype._bContainerOpen = false; - -/** - * Whether or not the mouse is currently over the results - * container. This is necessary in order to prevent clicks on container items - * from being text input field blur events. - * - * @property _bOverContainer - * @type Boolean - * @private - */ -YAHOO.widget.AutoComplete.prototype._bOverContainer = false; - -/** - * Internal reference to <ul> elements that contains query results within the - * results container. - * - * @property _elList - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elList = null; - -/* - * Array of <li> elements references that contain query results within the - * results container. - * - * @property _aListItemEls - * @type HTMLElement[] - * @private - */ -//YAHOO.widget.AutoComplete.prototype._aListItemEls = null; - -/** - * Number of <li> elements currently displayed in results container. - * - * @property _nDisplayedItems - * @type Number - * @private - */ -YAHOO.widget.AutoComplete.prototype._nDisplayedItems = 0; - -/* - * Internal count of <li> elements displayed and hidden in results container. - * - * @property _maxResultsDisplayed - * @type Number - * @private - */ -//YAHOO.widget.AutoComplete.prototype._maxResultsDisplayed = 0; - -/** - * Current query string - * - * @property _sCurQuery - * @type String - * @private - */ -YAHOO.widget.AutoComplete.prototype._sCurQuery = null; - -/** - * Selections from previous queries (for saving delimited queries). - * - * @property _sPastSelections - * @type String - * @default "" - * @private - */ -YAHOO.widget.AutoComplete.prototype._sPastSelections = ""; - -/** - * Stores initial input value used to determine if textboxChangeEvent should be fired. - * - * @property _sInitInputValue - * @type String - * @private - */ -YAHOO.widget.AutoComplete.prototype._sInitInputValue = null; - -/** - * Pointer to the currently highlighted <li> element in the container. - * - * @property _elCurListItem - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elCurListItem = null; - -/** - * Pointer to the currently pre-highlighted <li> element in the container. - * - * @property _elCurPrehighlightItem - * @type HTMLElement - * @private - */ -YAHOO.widget.AutoComplete.prototype._elCurPrehighlightItem = null; - -/** - * Whether or not an item has been selected since the container was populated - * with results. Reset to false by _populateList, and set to true when item is - * selected. - * - * @property _bItemSelected - * @type Boolean - * @private - */ -YAHOO.widget.AutoComplete.prototype._bItemSelected = false; - -/** - * Key code of the last key pressed in textbox. - * - * @property _nKeyCode - * @type Number - * @private - */ -YAHOO.widget.AutoComplete.prototype._nKeyCode = null; - -/** - * Delay timeout ID. - * - * @property _nDelayID - * @type Number - * @private - */ -YAHOO.widget.AutoComplete.prototype._nDelayID = -1; - -/** - * TypeAhead delay timeout ID. - * - * @property _nTypeAheadDelayID - * @type Number - * @private - */ -YAHOO.widget.AutoComplete.prototype._nTypeAheadDelayID = -1; - -/** - * Src to iFrame used when useIFrame = true. Supports implementations over SSL - * as well. - * - * @property _iFrameSrc - * @type String - * @private - */ -YAHOO.widget.AutoComplete.prototype._iFrameSrc = "javascript:false;"; - -/** - * For users typing via certain IMEs, queries must be triggered by intervals, - * since key events yet supported across all browsers for all IMEs. - * - * @property _queryInterval - * @type Object - * @private - */ -YAHOO.widget.AutoComplete.prototype._queryInterval = null; - -/** - * Internal tracker to last known textbox value, used to determine whether or not - * to trigger a query via interval for certain IME users. - * - * @event _sLastTextboxValue - * @type String - * @private - */ -YAHOO.widget.AutoComplete.prototype._sLastTextboxValue = null; - -///////////////////////////////////////////////////////////////////////////// -// -// Private methods -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Updates and validates latest public config properties. - * - * @method __initProps - * @private - */ -YAHOO.widget.AutoComplete.prototype._initProps = function() { - // Correct any invalid values - var minQueryLength = this.minQueryLength; - if(!YAHOO.lang.isNumber(minQueryLength)) { - this.minQueryLength = 1; - } - var maxResultsDisplayed = this.maxResultsDisplayed; - if(!YAHOO.lang.isNumber(maxResultsDisplayed) || (maxResultsDisplayed < 1)) { - this.maxResultsDisplayed = 10; - } - var queryDelay = this.queryDelay; - if(!YAHOO.lang.isNumber(queryDelay) || (queryDelay < 0)) { - this.queryDelay = 0.2; - } - var typeAheadDelay = this.typeAheadDelay; - if(!YAHOO.lang.isNumber(typeAheadDelay) || (typeAheadDelay < 0)) { - this.typeAheadDelay = 0.2; - } - var delimChar = this.delimChar; - if(YAHOO.lang.isString(delimChar) && (delimChar.length > 0)) { - this.delimChar = [delimChar]; - } - else if(!YAHOO.lang.isArray(delimChar)) { - this.delimChar = null; - } - var animSpeed = this.animSpeed; - if((this.animHoriz || this.animVert) && YAHOO.util.Anim) { - if(!YAHOO.lang.isNumber(animSpeed) || (animSpeed < 0)) { - this.animSpeed = 0.3; - } - if(!this._oAnim ) { - this._oAnim = new YAHOO.util.Anim(this._elContent, {}, this.animSpeed); - } - else { - this._oAnim.duration = this.animSpeed; - } - } - if(this.forceSelection && delimChar) { - } -}; - -/** - * Initializes the results container helpers if they are enabled and do - * not exist - * - * @method _initContainerHelperEls - * @private - */ -YAHOO.widget.AutoComplete.prototype._initContainerHelperEls = function() { - if(this.useShadow && !this._elShadow) { - var elShadow = document.createElement("div"); - elShadow.className = "yui-ac-shadow"; - elShadow.style.width = 0; - elShadow.style.height = 0; - this._elShadow = this._elContainer.appendChild(elShadow); - } - if(this.useIFrame && !this._elIFrame) { - var elIFrame = document.createElement("iframe"); - elIFrame.src = this._iFrameSrc; - elIFrame.frameBorder = 0; - elIFrame.scrolling = "no"; - elIFrame.style.position = "absolute"; - elIFrame.style.width = 0; - elIFrame.style.height = 0; - elIFrame.style.padding = 0; - elIFrame.tabIndex = -1; - elIFrame.role = "presentation"; - elIFrame.title = "Presentational iframe shim"; - this._elIFrame = this._elContainer.appendChild(elIFrame); - } -}; - -/** - * Initializes the results container once at object creation - * - * @method _initContainerEl - * @private - */ -YAHOO.widget.AutoComplete.prototype._initContainerEl = function() { - YAHOO.util.Dom.addClass(this._elContainer, "yui-ac-container"); - - if(!this._elContent) { - // The elContent div is assigned DOM listeners and - // helps size the iframe and shadow properly - var elContent = document.createElement("div"); - elContent.className = "yui-ac-content"; - elContent.style.display = "none"; - - this._elContent = this._elContainer.appendChild(elContent); - - var elHeader = document.createElement("div"); - elHeader.className = "yui-ac-hd"; - elHeader.style.display = "none"; - this._elHeader = this._elContent.appendChild(elHeader); - - var elBody = document.createElement("div"); - elBody.className = "yui-ac-bd"; - this._elBody = this._elContent.appendChild(elBody); - - var elFooter = document.createElement("div"); - elFooter.className = "yui-ac-ft"; - elFooter.style.display = "none"; - this._elFooter = this._elContent.appendChild(elFooter); - } - else { - } -}; - -/** - * Clears out contents of container body and creates up to - * YAHOO.widget.AutoComplete#maxResultsDisplayed <li> elements in an - * <ul> element. - * - * @method _initListEl - * @private - */ -YAHOO.widget.AutoComplete.prototype._initListEl = function() { - var nListLength = this.maxResultsDisplayed, - elList = this._elList || document.createElement("ul"), - elListItem; - - while(elList.childNodes.length < nListLength) { - elListItem = document.createElement("li"); - elListItem.style.display = "none"; - elListItem._nItemIndex = elList.childNodes.length; - elList.appendChild(elListItem); - } - if(!this._elList) { - var elBody = this._elBody; - YAHOO.util.Event.purgeElement(elBody, true); - elBody.innerHTML = ""; - this._elList = elBody.appendChild(elList); - } - - this._elBody.style.display = ""; -}; - -/** - * Focuses input field. - * - * @method _focus - * @private - */ -YAHOO.widget.AutoComplete.prototype._focus = function() { - // http://developer.mozilla.org/en/docs/index.php?title=Key-navigable_custom_DHTML_widgets - var oSelf = this; - setTimeout(function() { - try { - oSelf._elTextbox.focus(); - } - catch(e) { - } - },0); -}; - -/** - * Enables interval detection for IME support. - * - * @method _enableIntervalDetection - * @private - */ -YAHOO.widget.AutoComplete.prototype._enableIntervalDetection = function() { - var oSelf = this; - if(!oSelf._queryInterval && oSelf.queryInterval) { - oSelf._queryInterval = setInterval(function() { oSelf._onInterval(); }, oSelf.queryInterval); - } -}; - -/** - * Enables interval detection for a less performant but brute force mechanism to - * detect input values at an interval set by queryInterval and send queries if - * input value has changed. Needed to support right-click+paste or shift+insert - * edge cases. Please note that intervals are cleared at the end of each interaction, - * so enableIntervalDetection must be called for each new interaction. The - * recommended approach is to call it in response to textboxFocusEvent. - * - * @method enableIntervalDetection - */ -YAHOO.widget.AutoComplete.prototype.enableIntervalDetection = - YAHOO.widget.AutoComplete.prototype._enableIntervalDetection; - -/** - * Enables query triggers based on text input detection by intervals (rather - * than by key events). - * - * @method _onInterval - * @private - */ -YAHOO.widget.AutoComplete.prototype._onInterval = function() { - var currValue = this._elTextbox.value; - var lastValue = this._sLastTextboxValue; - if(currValue != lastValue) { - this._sLastTextboxValue = currValue; - this._sendQuery(currValue); - } -}; - -/** - * Cancels text input detection by intervals. - * - * @method _clearInterval - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._clearInterval = function() { - if(this._queryInterval) { - clearInterval(this._queryInterval); - this._queryInterval = null; - } -}; - -/** - * Whether or not key is functional or should be ignored. Note that the right - * arrow key is NOT an ignored key since it triggers queries for certain intl - * charsets. - * - * @method _isIgnoreKey - * @param nKeycode {Number} Code of key pressed. - * @return {Boolean} True if key should be ignored, false otherwise. - * @private - */ -YAHOO.widget.AutoComplete.prototype._isIgnoreKey = function(nKeyCode) { - if((nKeyCode == 9) || (nKeyCode == 13) || // tab, enter - (nKeyCode == 16) || (nKeyCode == 17) || // shift, ctl - (nKeyCode >= 18 && nKeyCode <= 20) || // alt, pause/break,caps lock - (nKeyCode == 27) || // esc - (nKeyCode >= 33 && nKeyCode <= 35) || // page up,page down,end - /*(nKeyCode >= 36 && nKeyCode <= 38) || // home,left,up - (nKeyCode == 40) || // down*/ - (nKeyCode >= 36 && nKeyCode <= 40) || // home,left,up, right, down - (nKeyCode >= 44 && nKeyCode <= 45) || // print screen,insert - (nKeyCode == 229) // Bug 2041973: Korean XP fires 2 keyup events, the key and 229 - ) { - return true; - } - return false; -}; - -/** - * Makes query request to the DataSource. - * - * @method _sendQuery - * @param sQuery {String} Query string. - * @private - */ -YAHOO.widget.AutoComplete.prototype._sendQuery = function(sQuery) { - // Widget has been effectively turned off - if(this.minQueryLength < 0) { - this._toggleContainer(false); - return; - } - // Delimiter has been enabled - if(this.delimChar) { - var extraction = this._extractQuery(sQuery); - // Here is the query itself - sQuery = extraction.query; - // ...and save the rest of the string for later - this._sPastSelections = extraction.previous; - } - - // Don't search queries that are too short - if((sQuery && (sQuery.length < this.minQueryLength)) || (!sQuery && this.minQueryLength > 0)) { - if(this._nDelayID != -1) { - clearTimeout(this._nDelayID); - } - this._toggleContainer(false); - return; - } - - sQuery = encodeURIComponent(sQuery); - this._nDelayID = -1; // Reset timeout ID because request is being made - - // Subset matching - if(this.dataSource.queryMatchSubset || this.queryMatchSubset) { // backward compat - var oResponse = this.getSubsetMatches(sQuery); - if(oResponse) { - this.handleResponse(sQuery, oResponse, {query: sQuery}); - return; - } - } - - if(this.dataSource.responseStripAfter) { - this.dataSource.doBeforeParseData = this.preparseRawResponse; - } - if(this.applyLocalFilter) { - this.dataSource.doBeforeCallback = this.filterResults; - } - - var sRequest = this.generateRequest(sQuery); - this.dataRequestEvent.fire(this, sQuery, sRequest); - - this.dataSource.sendRequest(sRequest, { - success : this.handleResponse, - failure : this.handleResponse, - scope : this, - argument: { - query: sQuery - } - }); -}; - -/** - * Populates the given <li> element with return value from formatResult(). - * - * @method _populateListItem - * @param elListItem {HTMLElement} The LI element. - * @param oResult {Object} The result object. - * @param sCurQuery {String} The query string. - * @private - */ -YAHOO.widget.AutoComplete.prototype._populateListItem = function(elListItem, oResult, sQuery) { - elListItem.innerHTML = this.formatResult(oResult, sQuery, elListItem._sResultMatch); -}; - -/** - * Populates the array of <li> elements in the container with query - * results. - * - * @method _populateList - * @param sQuery {String} Original request. - * @param oResponse {Object} Response object. - * @param oPayload {MIXED} (optional) Additional argument(s) - * @private - */ -YAHOO.widget.AutoComplete.prototype._populateList = function(sQuery, oResponse, oPayload) { - // Clear previous timeout - if(this._nTypeAheadDelayID != -1) { - clearTimeout(this._nTypeAheadDelayID); - } - - sQuery = (oPayload && oPayload.query) ? oPayload.query : sQuery; - - // Pass data through abstract method for any transformations - var ok = this.doBeforeLoadData(sQuery, oResponse, oPayload); - - // Data is ok - if(ok && !oResponse.error) { - this.dataReturnEvent.fire(this, sQuery, oResponse.results); - - // Continue only if instance is still active (i.e., user hasn't already moved on) - if(this._bFocused) { - // Store state for this interaction - var sCurQuery = decodeURIComponent(sQuery); - this._sCurQuery = sCurQuery; - this._bItemSelected = false; - - var allResults = oResponse.results, - nItemsToShow = Math.min(allResults.length,this.maxResultsDisplayed), - sMatchKey = (this.dataSource.responseSchema.fields) ? - (this.dataSource.responseSchema.fields[0].key || this.dataSource.responseSchema.fields[0]) : 0; - - if(nItemsToShow > 0) { - // Make sure container and helpers are ready to go - if(!this._elList || (this._elList.childNodes.length < nItemsToShow)) { - this._initListEl(); - } - this._initContainerHelperEls(); - - var allListItemEls = this._elList.childNodes; - // Fill items with data from the bottom up - for(var i = nItemsToShow-1; i >= 0; i--) { - var elListItem = allListItemEls[i], - oResult = allResults[i]; - - // Backward compatibility - if(this.resultTypeList) { - // Results need to be converted back to an array - var aResult = []; - // Match key is first - aResult[0] = (YAHOO.lang.isString(oResult)) ? oResult : oResult[sMatchKey] || oResult[this.key]; - // Add additional data to the result array - var fields = this.dataSource.responseSchema.fields; - if(YAHOO.lang.isArray(fields) && (fields.length > 1)) { - for(var k=1, len=fields.length; k= nItemsToShow; j--) { - extraListItem = allListItemEls[j]; - extraListItem.style.display = "none"; - } - } - - this._nDisplayedItems = nItemsToShow; - - this.containerPopulateEvent.fire(this, sQuery, allResults); - - // Highlight the first item - if(this.autoHighlight) { - var elFirstListItem = this._elList.firstChild; - this._toggleHighlight(elFirstListItem,"to"); - this.itemArrowToEvent.fire(this, elFirstListItem); - this._typeAhead(elFirstListItem,sQuery); - } - // Unhighlight any previous time - else { - this._toggleHighlight(this._elCurListItem,"from"); - } - - // Pre-expansion stuff - ok = this._doBeforeExpandContainer(this._elTextbox, this._elContainer, sQuery, allResults); - - // Expand the container - this._toggleContainer(ok); - } - else { - this._toggleContainer(false); - } - - return; - } - } - // Error - else { - this.dataErrorEvent.fire(this, sQuery, oResponse); - } - -}; - -/** - * Called before container expands, by default snaps container to the - * bottom-left corner of the input element, then calls public overrideable method. - * - * @method _doBeforeExpandContainer - * @param elTextbox {HTMLElement} The text input box. - * @param elContainer {HTMLElement} The container element. - * @param sQuery {String} The query string. - * @param aResults {Object[]} An array of query results. - * @return {Boolean} Return true to continue expanding container, false to cancel the expand. - * @private - */ -YAHOO.widget.AutoComplete.prototype._doBeforeExpandContainer = function(elTextbox, elContainer, sQuery, aResults) { - if(this.autoSnapContainer) { - this.snapContainer(); - } - - return this.doBeforeExpandContainer(elTextbox, elContainer, sQuery, aResults); -}; - -/** - * When forceSelection is true and the user attempts - * leave the text input box without selecting an item from the query results, - * the user selection is cleared. - * - * @method _clearSelection - * @private - */ -YAHOO.widget.AutoComplete.prototype._clearSelection = function() { - var extraction = (this.delimChar) ? this._extractQuery(this._elTextbox.value) : - {previous:"",query:this._elTextbox.value}; - this._elTextbox.value = extraction.previous; - this.selectionEnforceEvent.fire(this, extraction.query); -}; - -/** - * Whether or not user-typed value in the text input box matches any of the - * query results. - * - * @method _textMatchesOption - * @return {HTMLElement} Matching list item element if user-input text matches - * a result, null otherwise. - * @private - */ -YAHOO.widget.AutoComplete.prototype._textMatchesOption = function() { - var elMatch = null; - - for(var i=0; i= 0; i--) { - nNewIndex = sQuery.lastIndexOf(aDelimChar[i]); - if(nNewIndex > nDelimIndex) { - nDelimIndex = nNewIndex; - } - } - // If we think the last delimiter is a space (" "), make sure it is NOT - // a false positive by also checking the char directly before it - if(aDelimChar[i] == " ") { - for (var j = aDelimChar.length-1; j >= 0; j--) { - if(sQuery[nDelimIndex - 1] == aDelimChar[j]) { - nDelimIndex--; - break; - } - } - } - // A delimiter has been found in the query so extract the latest query from past selections - if(nDelimIndex > -1) { - nQueryStart = nDelimIndex + 1; - // Trim any white space from the beginning... - while(sQuery.charAt(nQueryStart) == " ") { - nQueryStart += 1; - } - // ...and save the rest of the string for later - sPrevious = sQuery.substring(0,nQueryStart); - // Here is the query itself - sQuery = sQuery.substr(nQueryStart); - } - // No delimiter found in the query, so there are no selections from past queries - else { - sPrevious = ""; - } - - return { - previous: sPrevious, - query: sQuery - }; -}; - -/** - * Syncs results container with its helpers. - * - * @method _toggleContainerHelpers - * @param bShow {Boolean} True if container is expanded, false if collapsed - * @private - */ -YAHOO.widget.AutoComplete.prototype._toggleContainerHelpers = function(bShow) { - var width = this._elContent.offsetWidth + "px"; - var height = this._elContent.offsetHeight + "px"; - - if(this.useIFrame && this._elIFrame) { - var elIFrame = this._elIFrame; - if(bShow) { - elIFrame.style.width = width; - elIFrame.style.height = height; - elIFrame.style.padding = ""; - } - else { - elIFrame.style.width = 0; - elIFrame.style.height = 0; - elIFrame.style.padding = 0; - } - } - if(this.useShadow && this._elShadow) { - var elShadow = this._elShadow; - if(bShow) { - elShadow.style.width = width; - elShadow.style.height = height; - } - else { - elShadow.style.width = 0; - elShadow.style.height = 0; - } - } -}; - -/** - * Animates expansion or collapse of the container. - * - * @method _toggleContainer - * @param bShow {Boolean} True if container should be expanded, false if container should be collapsed - * @private - */ -YAHOO.widget.AutoComplete.prototype._toggleContainer = function(bShow) { - - var elContainer = this._elContainer; - - // If implementer has container always open and it's already open, don't mess with it - // Container is initialized with display "none" so it may need to be shown first time through - if(this.alwaysShowContainer && this._bContainerOpen) { - return; - } - - // Reset states - if(!bShow) { - this._toggleHighlight(this._elCurListItem,"from"); - this._nDisplayedItems = 0; - this._sCurQuery = null; - - // Container is already closed, so don't bother with changing the UI - if(this._elContent.style.display == "none") { - return; - } - } - - // If animation is enabled... - var oAnim = this._oAnim; - if(oAnim && oAnim.getEl() && (this.animHoriz || this.animVert)) { - if(oAnim.isAnimated()) { - oAnim.stop(true); - } - - // Clone container to grab current size offscreen - var oClone = this._elContent.cloneNode(true); - elContainer.appendChild(oClone); - oClone.style.top = "-9000px"; - oClone.style.width = ""; - oClone.style.height = ""; - oClone.style.display = ""; - - // Current size of the container is the EXPANDED size - var wExp = oClone.offsetWidth; - var hExp = oClone.offsetHeight; - - // Calculate COLLAPSED sizes based on horiz and vert anim - var wColl = (this.animHoriz) ? 0 : wExp; - var hColl = (this.animVert) ? 0 : hExp; - - // Set animation sizes - oAnim.attributes = (bShow) ? - {width: { to: wExp }, height: { to: hExp }} : - {width: { to: wColl}, height: { to: hColl }}; - - // If opening anew, set to a collapsed size... - if(bShow && !this._bContainerOpen) { - this._elContent.style.width = wColl+"px"; - this._elContent.style.height = hColl+"px"; - } - // Else, set it to its last known size. - else { - this._elContent.style.width = wExp+"px"; - this._elContent.style.height = hExp+"px"; - } - - elContainer.removeChild(oClone); - oClone = null; - - var oSelf = this; - var onAnimComplete = function() { - // Finish the collapse - oAnim.onComplete.unsubscribeAll(); - - if(bShow) { - oSelf._toggleContainerHelpers(true); - oSelf._bContainerOpen = bShow; - oSelf.containerExpandEvent.fire(oSelf); - } - else { - oSelf._elContent.style.display = "none"; - oSelf._bContainerOpen = bShow; - oSelf.containerCollapseEvent.fire(oSelf); - } - }; - - // Display container and animate it - this._toggleContainerHelpers(false); // Bug 1424486: Be early to hide, late to show; - this._elContent.style.display = ""; - oAnim.onComplete.subscribe(onAnimComplete); - oAnim.animate(); - } - // Else don't animate, just show or hide - else { - if(bShow) { - this._elContent.style.display = ""; - this._toggleContainerHelpers(true); - this._bContainerOpen = bShow; - this.containerExpandEvent.fire(this); - } - else { - this._toggleContainerHelpers(false); - this._elContent.style.display = "none"; - this._bContainerOpen = bShow; - this.containerCollapseEvent.fire(this); - } - } - -}; - -/** - * Toggles the highlight on or off for an item in the container, and also cleans - * up highlighting of any previous item. - * - * @method _toggleHighlight - * @param elNewListItem {HTMLElement} The <li> element item to receive highlight behavior. - * @param sType {String} Type "mouseover" will toggle highlight on, and "mouseout" will toggle highlight off. - * @private - */ -YAHOO.widget.AutoComplete.prototype._toggleHighlight = function(elNewListItem, sType) { - if(elNewListItem) { - var sHighlight = this.highlightClassName; - if(this._elCurListItem) { - // Remove highlight from old item - YAHOO.util.Dom.removeClass(this._elCurListItem, sHighlight); - this._elCurListItem = null; - } - - if((sType == "to") && sHighlight) { - // Apply highlight to new item - YAHOO.util.Dom.addClass(elNewListItem, sHighlight); - this._elCurListItem = elNewListItem; - } - } -}; - -/** - * Toggles the pre-highlight on or off for an item in the container, and also cleans - * up pre-highlighting of any previous item. - * - * @method _togglePrehighlight - * @param elNewListItem {HTMLElement} The <li> element item to receive highlight behavior. - * @param sType {String} Type "mouseover" will toggle highlight on, and "mouseout" will toggle highlight off. - * @private - */ -YAHOO.widget.AutoComplete.prototype._togglePrehighlight = function(elNewListItem, sType) { - var sPrehighlight = this.prehighlightClassName; - - if(this._elCurPrehighlightItem) { - YAHOO.util.Dom.removeClass(this._elCurPrehighlightItem, sPrehighlight); - } - if(elNewListItem == this._elCurListItem) { - return; - } - - if((sType == "mouseover") && sPrehighlight) { - // Apply prehighlight to new item - YAHOO.util.Dom.addClass(elNewListItem, sPrehighlight); - this._elCurPrehighlightItem = elNewListItem; - } - else { - // Remove prehighlight from old item - YAHOO.util.Dom.removeClass(elNewListItem, sPrehighlight); - } -}; - -/** - * Updates the text input box value with selected query result. If a delimiter - * has been defined, then the value gets appended with the delimiter. - * - * @method _updateValue - * @param elListItem {HTMLElement} The <li> element item with which to update the value. - * @private - */ -YAHOO.widget.AutoComplete.prototype._updateValue = function(elListItem) { - if(!this.suppressInputUpdate) { - var elTextbox = this._elTextbox; - var sDelimChar = (this.delimChar) ? (this.delimChar[0] || this.delimChar) : null; - var sResultMatch = elListItem._sResultMatch; - - // Calculate the new value - var sNewValue = ""; - if(sDelimChar) { - // Preserve selections from past queries - sNewValue = this._sPastSelections; - // Add new selection plus delimiter - sNewValue += sResultMatch + sDelimChar; - if(sDelimChar != " ") { - sNewValue += " "; - } - } - else { - sNewValue = sResultMatch; - } - - // Update input field - elTextbox.value = sNewValue; - - // Scroll to bottom of textarea if necessary - if(elTextbox.type == "textarea") { - elTextbox.scrollTop = elTextbox.scrollHeight; - } - - // Move cursor to end - var end = elTextbox.value.length; - this._selectText(elTextbox,end,end); - - this._elCurListItem = elListItem; - } -}; - -/** - * Selects a result item from the container - * - * @method _selectItem - * @param elListItem {HTMLElement} The selected <li> element item. - * @private - */ -YAHOO.widget.AutoComplete.prototype._selectItem = function(elListItem) { - this._bItemSelected = true; - this._updateValue(elListItem); - this._sPastSelections = this._elTextbox.value; - this._clearInterval(); - this.itemSelectEvent.fire(this, elListItem, elListItem._oResultData); - this._toggleContainer(false); -}; - -/** - * If an item is highlighted in the container, the right arrow key jumps to the - * end of the textbox and selects the highlighted item, otherwise the container - * is closed. - * - * @method _jumpSelection - * @private - */ -YAHOO.widget.AutoComplete.prototype._jumpSelection = function() { - if(this._elCurListItem) { - this._selectItem(this._elCurListItem); - } - else { - this._toggleContainer(false); - } -}; - -/** - * Triggered by up and down arrow keys, changes the current highlighted - * <li> element item. Scrolls container if necessary. - * - * @method _moveSelection - * @param nKeyCode {Number} Code of key pressed. - * @private - */ -YAHOO.widget.AutoComplete.prototype._moveSelection = function(nKeyCode) { - if(this._bContainerOpen) { - // Determine current item's id number - var elCurListItem = this._elCurListItem, - nCurItemIndex = -1; - - if(elCurListItem) { - nCurItemIndex = elCurListItem._nItemIndex; - } - - var nNewItemIndex = (nKeyCode == 40) ? - (nCurItemIndex + 1) : (nCurItemIndex - 1); - - // Out of bounds - if(nNewItemIndex < -2 || nNewItemIndex >= this._nDisplayedItems) { - return; - } - - if(elCurListItem) { - // Unhighlight current item - this._toggleHighlight(elCurListItem, "from"); - this.itemArrowFromEvent.fire(this, elCurListItem); - } - if(nNewItemIndex == -1) { - // Go back to query (remove type-ahead string) - if(this.delimChar) { - this._elTextbox.value = this._sPastSelections + this._sCurQuery; - } - else { - this._elTextbox.value = this._sCurQuery; - } - return; - } - if(nNewItemIndex == -2) { - // Close container - this._toggleContainer(false); - return; - } - - var elNewListItem = this._elList.childNodes[nNewItemIndex], - - // Scroll the container if necessary - elContent = this._elContent, - sOF = YAHOO.util.Dom.getStyle(elContent,"overflow"), - sOFY = YAHOO.util.Dom.getStyle(elContent,"overflowY"), - scrollOn = ((sOF == "auto") || (sOF == "scroll") || (sOFY == "auto") || (sOFY == "scroll")); - if(scrollOn && (nNewItemIndex > -1) && - (nNewItemIndex < this._nDisplayedItems)) { - // User is keying down - if(nKeyCode == 40) { - // Bottom of selected item is below scroll area... - if((elNewListItem.offsetTop+elNewListItem.offsetHeight) > (elContent.scrollTop + elContent.offsetHeight)) { - // Set bottom of scroll area to bottom of selected item - elContent.scrollTop = (elNewListItem.offsetTop+elNewListItem.offsetHeight) - elContent.offsetHeight; - } - // Bottom of selected item is above scroll area... - else if((elNewListItem.offsetTop+elNewListItem.offsetHeight) < elContent.scrollTop) { - // Set top of selected item to top of scroll area - elContent.scrollTop = elNewListItem.offsetTop; - - } - } - // User is keying up - else { - // Top of selected item is above scroll area - if(elNewListItem.offsetTop < elContent.scrollTop) { - // Set top of scroll area to top of selected item - this._elContent.scrollTop = elNewListItem.offsetTop; - } - // Top of selected item is below scroll area - else if(elNewListItem.offsetTop > (elContent.scrollTop + elContent.offsetHeight)) { - // Set bottom of selected item to bottom of scroll area - this._elContent.scrollTop = (elNewListItem.offsetTop+elNewListItem.offsetHeight) - elContent.offsetHeight; - } - } - } - - this._toggleHighlight(elNewListItem, "to"); - this.itemArrowToEvent.fire(this, elNewListItem); - if(this.typeAhead) { - this._updateValue(elNewListItem); - } - } -}; - -///////////////////////////////////////////////////////////////////////////// -// -// Private event handlers -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Handles container mouseover events. - * - * @method _onContainerMouseover - * @param v {HTMLEvent} The mouseover event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onContainerMouseover = function(v,oSelf) { - var elTarget = YAHOO.util.Event.getTarget(v); - var elTag = elTarget.nodeName.toLowerCase(); - while(elTarget && (elTag != "table")) { - switch(elTag) { - case "body": - return; - case "li": - if(oSelf.prehighlightClassName) { - oSelf._togglePrehighlight(elTarget,"mouseover"); - } - else { - oSelf._toggleHighlight(elTarget,"to"); - } - - oSelf.itemMouseOverEvent.fire(oSelf, elTarget); - break; - case "div": - if(YAHOO.util.Dom.hasClass(elTarget,"yui-ac-container")) { - oSelf._bOverContainer = true; - return; - } - break; - default: - break; - } - - elTarget = elTarget.parentNode; - if(elTarget) { - elTag = elTarget.nodeName.toLowerCase(); - } - } -}; - -/** - * Handles container mouseout events. - * - * @method _onContainerMouseout - * @param v {HTMLEvent} The mouseout event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onContainerMouseout = function(v,oSelf) { - var elTarget = YAHOO.util.Event.getTarget(v); - var elTag = elTarget.nodeName.toLowerCase(); - while(elTarget && (elTag != "table")) { - switch(elTag) { - case "body": - return; - case "li": - if(oSelf.prehighlightClassName) { - oSelf._togglePrehighlight(elTarget,"mouseout"); - } - else { - oSelf._toggleHighlight(elTarget,"from"); - } - - oSelf.itemMouseOutEvent.fire(oSelf, elTarget); - break; - case "ul": - oSelf._toggleHighlight(oSelf._elCurListItem,"to"); - break; - case "div": - if(YAHOO.util.Dom.hasClass(elTarget,"yui-ac-container")) { - oSelf._bOverContainer = false; - return; - } - break; - default: - break; - } - - elTarget = elTarget.parentNode; - if(elTarget) { - elTag = elTarget.nodeName.toLowerCase(); - } - } -}; - -/** - * Handles container click events. - * - * @method _onContainerClick - * @param v {HTMLEvent} The click event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onContainerClick = function(v,oSelf) { - var elTarget = YAHOO.util.Event.getTarget(v); - var elTag = elTarget.nodeName.toLowerCase(); - while(elTarget && (elTag != "table")) { - switch(elTag) { - case "body": - return; - case "li": - // In case item has not been moused over - oSelf._toggleHighlight(elTarget,"to"); - oSelf._selectItem(elTarget); - return; - default: - break; - } - - elTarget = elTarget.parentNode; - if(elTarget) { - elTag = elTarget.nodeName.toLowerCase(); - } - } -}; - - -/** - * Handles container scroll events. - * - * @method _onContainerScroll - * @param v {HTMLEvent} The scroll event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onContainerScroll = function(v,oSelf) { - oSelf._focus(); -}; - -/** - * Handles container resize events. - * - * @method _onContainerResize - * @param v {HTMLEvent} The resize event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onContainerResize = function(v,oSelf) { - oSelf._toggleContainerHelpers(oSelf._bContainerOpen); -}; - - -/** - * Handles textbox keydown events of functional keys, mainly for UI behavior. - * - * @method _onTextboxKeyDown - * @param v {HTMLEvent} The keydown event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onTextboxKeyDown = function(v,oSelf) { - var nKeyCode = v.keyCode; - - // Clear timeout - if(oSelf._nTypeAheadDelayID != -1) { - clearTimeout(oSelf._nTypeAheadDelayID); - } - - switch (nKeyCode) { - case 9: // tab - if(!YAHOO.env.ua.opera && (navigator.userAgent.toLowerCase().indexOf("mac") == -1) || (YAHOO.env.ua.webkit>420)) { - // select an item or clear out - if(oSelf._elCurListItem) { - if(oSelf.delimChar && (oSelf._nKeyCode != nKeyCode)) { - if(oSelf._bContainerOpen) { - YAHOO.util.Event.stopEvent(v); - } - } - oSelf._selectItem(oSelf._elCurListItem); - } - else { - oSelf._toggleContainer(false); - } - } - break; - case 13: // enter - if(!YAHOO.env.ua.opera && (navigator.userAgent.toLowerCase().indexOf("mac") == -1) || (YAHOO.env.ua.webkit>420)) { - if(oSelf._elCurListItem) { - if(oSelf._nKeyCode != nKeyCode) { - if(oSelf._bContainerOpen) { - YAHOO.util.Event.stopEvent(v); - } - } - oSelf._selectItem(oSelf._elCurListItem); - } - else { - oSelf._toggleContainer(false); - } - } - break; - case 27: // esc - oSelf._toggleContainer(false); - return; - case 39: // right - oSelf._jumpSelection(); - break; - case 38: // up - if(oSelf._bContainerOpen) { - YAHOO.util.Event.stopEvent(v); - oSelf._moveSelection(nKeyCode); - } - break; - case 40: // down - if(oSelf._bContainerOpen) { - YAHOO.util.Event.stopEvent(v); - oSelf._moveSelection(nKeyCode); - } - break; - default: - oSelf._bItemSelected = false; - oSelf._toggleHighlight(oSelf._elCurListItem, "from"); - - oSelf.textboxKeyEvent.fire(oSelf, nKeyCode); - break; - } - - if(nKeyCode === 18){ - oSelf._enableIntervalDetection(); - } - oSelf._nKeyCode = nKeyCode; -}; - -/** - * Handles textbox keypress events. - * @method _onTextboxKeyPress - * @param v {HTMLEvent} The keypress event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onTextboxKeyPress = function(v,oSelf) { - var nKeyCode = v.keyCode; - - // Expose only to non SF3 (bug 1978549) Mac browsers (bug 790337) and Opera browsers (bug 583531), - // where stopEvent is ineffective on keydown events - if(YAHOO.env.ua.opera || (navigator.userAgent.toLowerCase().indexOf("mac") != -1) && (YAHOO.env.ua.webkit < 420)) { - switch (nKeyCode) { - case 9: // tab - // select an item or clear out - if(oSelf._bContainerOpen) { - if(oSelf.delimChar) { - YAHOO.util.Event.stopEvent(v); - } - if(oSelf._elCurListItem) { - oSelf._selectItem(oSelf._elCurListItem); - } - else { - oSelf._toggleContainer(false); - } - } - break; - case 13: // enter - if(oSelf._bContainerOpen) { - YAHOO.util.Event.stopEvent(v); - if(oSelf._elCurListItem) { - oSelf._selectItem(oSelf._elCurListItem); - } - else { - oSelf._toggleContainer(false); - } - } - break; - default: - break; - } - } - - //TODO: (?) limit only to non-IE, non-Mac-FF for Korean IME support (bug 811948) - // Korean IME detected - else if(nKeyCode == 229) { - oSelf._enableIntervalDetection(); - } -}; - -/** - * Handles textbox keyup events to trigger queries. - * - * @method _onTextboxKeyUp - * @param v {HTMLEvent} The keyup event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onTextboxKeyUp = function(v,oSelf) { - var sText = this.value; //string in textbox - - // Check to see if any of the public properties have been updated - oSelf._initProps(); - - // Filter out chars that don't trigger queries - var nKeyCode = v.keyCode; - if(oSelf._isIgnoreKey(nKeyCode)) { - return; - } - - // Clear previous timeout - if(oSelf._nDelayID != -1) { - clearTimeout(oSelf._nDelayID); - } - - // Set new timeout - oSelf._nDelayID = setTimeout(function(){ - oSelf._sendQuery(sText); - },(oSelf.queryDelay * 1000)); -}; - -/** - * Handles text input box receiving focus. - * - * @method _onTextboxFocus - * @param v {HTMLEvent} The focus event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onTextboxFocus = function (v,oSelf) { - // Start of a new interaction - if(!oSelf._bFocused) { - oSelf._elTextbox.setAttribute("autocomplete","off"); - oSelf._bFocused = true; - oSelf._sInitInputValue = oSelf._elTextbox.value; - oSelf.textboxFocusEvent.fire(oSelf); - } -}; - -/** - * Handles text input box losing focus. - * - * @method _onTextboxBlur - * @param v {HTMLEvent} The focus event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onTextboxBlur = function (v,oSelf) { - // Is a true blur - if(!oSelf._bOverContainer || (oSelf._nKeyCode == 9)) { - // Current query needs to be validated as a selection - if(!oSelf._bItemSelected) { - var elMatchListItem = oSelf._textMatchesOption(); - // Container is closed or current query doesn't match any result - if(!oSelf._bContainerOpen || (oSelf._bContainerOpen && (elMatchListItem === null))) { - // Force selection is enabled so clear the current query - if(oSelf.forceSelection) { - oSelf._clearSelection(); - } - // Treat current query as a valid selection - else { - oSelf.unmatchedItemSelectEvent.fire(oSelf, oSelf._sCurQuery); - } - } - // Container is open and current query matches a result - else { - // Force a selection when textbox is blurred with a match - if(oSelf.forceSelection) { - oSelf._selectItem(elMatchListItem); - } - } - } - - oSelf._clearInterval(); - oSelf._bFocused = false; - if(oSelf._sInitInputValue !== oSelf._elTextbox.value) { - oSelf.textboxChangeEvent.fire(oSelf); - } - oSelf.textboxBlurEvent.fire(oSelf); - - oSelf._toggleContainer(false); - } - // Not a true blur if it was a selection via mouse click - else { - oSelf._focus(); - } -}; - -/** - * Handles window unload event. - * - * @method _onWindowUnload - * @param v {HTMLEvent} The unload event. - * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. - * @private - */ -YAHOO.widget.AutoComplete.prototype._onWindowUnload = function(v,oSelf) { - if(oSelf && oSelf._elTextbox && oSelf.allowBrowserAutocomplete) { - oSelf._elTextbox.setAttribute("autocomplete","on"); - } -}; - -///////////////////////////////////////////////////////////////////////////// -// -// Deprecated for Backwards Compatibility -// -///////////////////////////////////////////////////////////////////////////// -/** - * @method doBeforeSendQuery - * @deprecated Use generateRequest. - */ -YAHOO.widget.AutoComplete.prototype.doBeforeSendQuery = function(sQuery) { - return this.generateRequest(sQuery); -}; - -/** - * @method getListItems - * @deprecated Use getListEl().childNodes. - */ -YAHOO.widget.AutoComplete.prototype.getListItems = function() { - var allListItemEls = [], - els = this._elList.childNodes; - for(var i=els.length-1; i>=0; i--) { - allListItemEls[i] = els[i]; - } - return allListItemEls; -}; - -///////////////////////////////////////////////////////////////////////// -// -// Private static methods -// -///////////////////////////////////////////////////////////////////////// - -/** - * Clones object literal or array of object literals. - * - * @method AutoComplete._cloneObject - * @param o {Object} Object. - * @private - * @static - */ -YAHOO.widget.AutoComplete._cloneObject = function(o) { - if(!YAHOO.lang.isValue(o)) { - return o; - } - - var copy = {}; - - if(YAHOO.lang.isFunction(o)) { - copy = o; - } - else if(YAHOO.lang.isArray(o)) { - var array = []; - for(var i=0,len=o.length;i - *
    TYPE_UNKNOWN
    - *
    TYPE_LOCAL
    - *
    TYPE_XHR
    - *
    TYPE_SCRIPTNODE
    - *
    TYPE_JSFUNCTION
    - * - * - * @property dataType - * @type Number - * @default YAHOO.util.DataSourceBase.TYPE_UNKNOWN - * - */ -dataType : DS.TYPE_UNKNOWN, - -/** - * Format of response: - * - *
    - *
    TYPE_UNKNOWN
    - *
    TYPE_JSARRAY
    - *
    TYPE_JSON
    - *
    TYPE_XML
    - *
    TYPE_TEXT
    - *
    TYPE_HTMLTABLE
    - *
    - * - * @property responseType - * @type Number - * @default YAHOO.util.DataSourceBase.TYPE_UNKNOWN - */ -responseType : DS.TYPE_UNKNOWN, - -/** - * Response schema object literal takes a combination of the following properties: - * - *
    - *
    resultsList
    Pointer to array of tabular data
    - *
    resultNode
    Pointer to node name of row data (XML data only)
    - *
    recordDelim
    Record delimiter (text data only)
    - *
    fieldDelim
    Field delimiter (text data only)
    - *
    fields
    Array of field names (aka keys), or array of object literals - * such as: {key:"fieldname",parser:YAHOO.util.DataSourceBase.parseDate}
    - *
    metaFields
    Object literal of keys to include in the oParsedResponse.meta collection
    - *
    metaNode
    Name of the node under which to search for meta information in XML response data
    - *
    - * - * @property responseSchema - * @type Object - */ -responseSchema : null, - -/** - * Additional arguments passed to the JSON parse routine. The JSON string - * is the assumed first argument (where applicable). This property is not - * set by default, but the parse methods will use it if present. - * - * @property parseJSONArgs - * @type {MIXED|Array} If an Array, contents are used as individual arguments. - * Otherwise, value is used as an additional argument. - */ -// property intentionally undefined - -/** - * When working with XML data, setting this property to true enables support for - * XPath-syntaxed locators in schema definitions. - * - * @property useXPath - * @type Boolean - * @default false - */ -useXPath : false, - -///////////////////////////////////////////////////////////////////////////// -// -// DataSourceBase public methods -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Public accessor to the unique name of the DataSource instance. - * - * @method toString - * @return {String} Unique name of the DataSource instance. - */ -toString : function() { - return this._sName; -}, - -/** - * Overridable method passes request to cache and returns cached response if any, - * refreshing the hit in the cache as the newest item. Returns null if there is - * no cache hit. - * - * @method getCachedResponse - * @param oRequest {Object} Request object. - * @param oCallback {Object} Callback object. - * @param oCaller {Object} (deprecated) Use callback object. - * @return {Object} Cached response object or null. - */ -getCachedResponse : function(oRequest, oCallback, oCaller) { - var aCache = this._aCache; - - // If cache is enabled... - if(this.maxCacheEntries > 0) { - // Initialize local cache - if(!aCache) { - this._aCache = []; - YAHOO.log("Cache initialized", "info", this.toString()); - } - // Look in local cache - else { - var nCacheLength = aCache.length; - if(nCacheLength > 0) { - var oResponse = null; - this.fireEvent("cacheRequestEvent", {request:oRequest,callback:oCallback,caller:oCaller}); - - // Loop through each cached element - for(var i = nCacheLength-1; i >= 0; i--) { - var oCacheElem = aCache[i]; - - // Defer cache hit logic to a public overridable method - if(this.isCacheHit(oRequest,oCacheElem.request)) { - // The cache returned a hit! - // Grab the cached response - oResponse = oCacheElem.response; - this.fireEvent("cacheResponseEvent", {request:oRequest,response:oResponse,callback:oCallback,caller:oCaller}); - - // Refresh the position of the cache hit - if(i < nCacheLength-1) { - // Remove element from its original location - aCache.splice(i,1); - // Add as newest - this.addToCache(oRequest, oResponse); - YAHOO.log("Refreshed cache position of the response for \"" + oRequest + "\"", "info", this.toString()); - } - - // Add a cache flag - oResponse.cached = true; - break; - } - } - YAHOO.log("The cached response for \"" + lang.dump(oRequest) + - "\" is " + lang.dump(oResponse), "info", this.toString()); - return oResponse; - } - } - } - else if(aCache) { - this._aCache = null; - YAHOO.log("Cache destroyed", "info", this.toString()); - } - return null; -}, - -/** - * Default overridable method matches given request to given cached request. - * Returns true if is a hit, returns false otherwise. Implementers should - * override this method to customize the cache-matching algorithm. - * - * @method isCacheHit - * @param oRequest {Object} Request object. - * @param oCachedRequest {Object} Cached request object. - * @return {Boolean} True if given request matches cached request, false otherwise. - */ -isCacheHit : function(oRequest, oCachedRequest) { - return (oRequest === oCachedRequest); -}, - -/** - * Adds a new item to the cache. If cache is full, evicts the stalest item - * before adding the new item. - * - * @method addToCache - * @param oRequest {Object} Request object. - * @param oResponse {Object} Response object to cache. - */ -addToCache : function(oRequest, oResponse) { - var aCache = this._aCache; - if(!aCache) { - return; - } - - // If the cache is full, make room by removing stalest element (index=0) - while(aCache.length >= this.maxCacheEntries) { - aCache.shift(); - } - - // Add to cache in the newest position, at the end of the array - var oCacheElem = {request:oRequest,response:oResponse}; - aCache[aCache.length] = oCacheElem; - this.fireEvent("responseCacheEvent", {request:oRequest,response:oResponse}); - YAHOO.log("Cached the response for \"" + oRequest + "\"", "info", this.toString()); -}, - -/** - * Flushes cache. - * - * @method flushCache - */ -flushCache : function() { - if(this._aCache) { - this._aCache = []; - this.fireEvent("cacheFlushEvent"); - YAHOO.log("Flushed the cache", "info", this.toString()); - } -}, - -/** - * Sets up a polling mechanism to send requests at set intervals and forward - * responses to given callback. - * - * @method setInterval - * @param nMsec {Number} Length of interval in milliseconds. - * @param oRequest {Object} Request object. - * @param oCallback {Function} Handler function to receive the response. - * @param oCaller {Object} (deprecated) Use oCallback.scope. - * @return {Number} Interval ID. - */ -setInterval : function(nMsec, oRequest, oCallback, oCaller) { - if(lang.isNumber(nMsec) && (nMsec >= 0)) { - YAHOO.log("Enabling polling to live data for \"" + oRequest + "\" at interval " + nMsec, "info", this.toString()); - var oSelf = this; - var nId = setInterval(function() { - oSelf.makeConnection(oRequest, oCallback, oCaller); - }, nMsec); - this._aIntervals.push(nId); - return nId; - } - else { - YAHOO.log("Could not enable polling to live data for \"" + oRequest + "\" at interval " + nMsec, "info", this.toString()); - } -}, - -/** - * Disables polling mechanism associated with the given interval ID. - * - * @method clearInterval - * @param nId {Number} Interval ID. - */ -clearInterval : function(nId) { - // Remove from tracker if there - var tracker = this._aIntervals || []; - for(var i=tracker.length-1; i>-1; i--) { - if(tracker[i] === nId) { - tracker.splice(i,1); - clearInterval(nId); - } - } -}, - -/** - * Disables all known polling intervals. - * - * @method clearAllIntervals - */ -clearAllIntervals : function() { - var tracker = this._aIntervals || []; - for(var i=tracker.length-1; i>-1; i--) { - clearInterval(tracker[i]); - } - tracker = []; -}, - -/** - * First looks for cached response, then sends request to live data. The - * following arguments are passed to the callback function: - *
    - *
    oRequest
    - *
    The same value that was passed in as the first argument to sendRequest.
    - *
    oParsedResponse
    - *
    An object literal containing the following properties: - *
    - *
    tId
    - *
    Unique transaction ID number.
    - *
    results
    - *
    Schema-parsed data results.
    - *
    error
    - *
    True in cases of data error.
    - *
    cached
    - *
    True when response is returned from DataSource cache.
    - *
    meta
    - *
    Schema-parsed meta data.
    - *
    - *
    oPayload
    - *
    The same value as was passed in as argument in the oCallback object literal.
    - *
    - * - * @method sendRequest - * @param oRequest {Object} Request object. - * @param oCallback {Object} An object literal with the following properties: - *
    - *
    success
    - *
    The function to call when the data is ready.
    - *
    failure
    - *
    The function to call upon a response failure condition.
    - *
    scope
    - *
    The object to serve as the scope for the success and failure handlers.
    - *
    argument
    - *
    Arbitrary data that will be passed back to the success and failure handlers.
    - *
    - * @param oCaller {Object} (deprecated) Use oCallback.scope. - * @return {Number} Transaction ID, or null if response found in cache. - */ -sendRequest : function(oRequest, oCallback, oCaller) { - // First look in cache - var oCachedResponse = this.getCachedResponse(oRequest, oCallback, oCaller); - if(oCachedResponse) { - DS.issueCallback(oCallback,[oRequest,oCachedResponse],false,oCaller); - return null; - } - - - // Not in cache, so forward request to live data - YAHOO.log("Making connection to live data for \"" + oRequest + "\"", "info", this.toString()); - return this.makeConnection(oRequest, oCallback, oCaller); -}, - -/** - * Overridable default method generates a unique transaction ID and passes - * the live data reference directly to the handleResponse function. This - * method should be implemented by subclasses to achieve more complex behavior - * or to access remote data. - * - * @method makeConnection - * @param oRequest {Object} Request object. - * @param oCallback {Object} Callback object literal. - * @param oCaller {Object} (deprecated) Use oCallback.scope. - * @return {Number} Transaction ID. - */ -makeConnection : function(oRequest, oCallback, oCaller) { - var tId = DS._nTransactionId++; - this.fireEvent("requestEvent", {tId:tId, request:oRequest,callback:oCallback,caller:oCaller}); - - /* accounts for the following cases: - YAHOO.util.DataSourceBase.TYPE_UNKNOWN - YAHOO.util.DataSourceBase.TYPE_JSARRAY - YAHOO.util.DataSourceBase.TYPE_JSON - YAHOO.util.DataSourceBase.TYPE_HTMLTABLE - YAHOO.util.DataSourceBase.TYPE_XML - YAHOO.util.DataSourceBase.TYPE_TEXT - */ - var oRawResponse = this.liveData; - - this.handleResponse(oRequest, oRawResponse, oCallback, oCaller, tId); - return tId; -}, - -/** - * Receives raw data response and type converts to XML, JSON, etc as necessary. - * Forwards oFullResponse to appropriate parsing function to get turned into - * oParsedResponse. Calls doBeforeCallback() and adds oParsedResponse to - * the cache when appropriate before calling issueCallback(). - * - * The oParsedResponse object literal has the following properties: - *
    - *
    tId {Number}
    Unique transaction ID - *
    results {Array}
    Array of parsed data results - *
    meta {Object}
    Object literal of meta values - *
    error {Boolean}
    (optional) True if there was an error - *
    cached {Boolean}
    (optional) True if response was cached - *
    - * - * @method handleResponse - * @param oRequest {Object} Request object - * @param oRawResponse {Object} The raw response from the live database. - * @param oCallback {Object} Callback object literal. - * @param oCaller {Object} (deprecated) Use oCallback.scope. - * @param tId {Number} Transaction ID. - */ -handleResponse : function(oRequest, oRawResponse, oCallback, oCaller, tId) { - this.fireEvent("responseEvent", {tId:tId, request:oRequest, response:oRawResponse, - callback:oCallback, caller:oCaller}); - YAHOO.log("Received live data response for \"" + oRequest + "\"", "info", this.toString()); - var xhr = (this.dataType == DS.TYPE_XHR) ? true : false; - var oParsedResponse = null; - var oFullResponse = oRawResponse; - - // Try to sniff data type if it has not been defined - if(this.responseType === DS.TYPE_UNKNOWN) { - var ctype = (oRawResponse && oRawResponse.getResponseHeader) ? oRawResponse.getResponseHeader["Content-Type"] : null; - if(ctype) { - // xml - if(ctype.indexOf("text/xml") > -1) { - this.responseType = DS.TYPE_XML; - } - else if(ctype.indexOf("application/json") > -1) { // json - this.responseType = DS.TYPE_JSON; - } - else if(ctype.indexOf("text/plain") > -1) { // text - this.responseType = DS.TYPE_TEXT; - } - } - else { - if(YAHOO.lang.isArray(oRawResponse)) { // array - this.responseType = DS.TYPE_JSARRAY; - } - // xml - else if(oRawResponse && oRawResponse.nodeType && (oRawResponse.nodeType === 9 || oRawResponse.nodeType === 1 || oRawResponse.nodeType === 11)) { - this.responseType = DS.TYPE_XML; - } - else if(oRawResponse && oRawResponse.nodeName && (oRawResponse.nodeName.toLowerCase() == "table")) { // table - this.responseType = DS.TYPE_HTMLTABLE; - } - else if(YAHOO.lang.isObject(oRawResponse)) { // json - this.responseType = DS.TYPE_JSON; - } - else if(YAHOO.lang.isString(oRawResponse)) { // text - this.responseType = DS.TYPE_TEXT; - } - } - } - - switch(this.responseType) { - case DS.TYPE_JSARRAY: - if(xhr && oRawResponse && oRawResponse.responseText) { - oFullResponse = oRawResponse.responseText; - } - try { - // Convert to JS array if it's a string - if(lang.isString(oFullResponse)) { - var parseArgs = [oFullResponse].concat(this.parseJSONArgs); - // Check for YUI JSON Util - if(lang.JSON) { - oFullResponse = lang.JSON.parse.apply(lang.JSON,parseArgs); - } - // Look for JSON parsers using an API similar to json2.js - else if(window.JSON && JSON.parse) { - oFullResponse = JSON.parse.apply(JSON,parseArgs); - } - // Look for JSON parsers using an API similar to json.js - else if(oFullResponse.parseJSON) { - oFullResponse = oFullResponse.parseJSON.apply(oFullResponse,parseArgs.slice(1)); - } - // No JSON lib found so parse the string - else { - // Trim leading spaces - while (oFullResponse.length > 0 && - (oFullResponse.charAt(0) != "{") && - (oFullResponse.charAt(0) != "[")) { - oFullResponse = oFullResponse.substring(1, oFullResponse.length); - } - - if(oFullResponse.length > 0) { - // Strip extraneous stuff at the end - var arrayEnd = -Math.max(oFullResponse.lastIndexOf("]"),oFullResponse.lastIndexOf("}")); - oFullResponse = oFullResponse.substring(0,arrayEnd+1); - - // Turn the string into an object literal... - // ...eval is necessary here - oFullResponse = eval("(" + oFullResponse + ")"); - - } - } - } - } - catch(e1) { - } - oFullResponse = this.doBeforeParseData(oRequest, oFullResponse, oCallback); - oParsedResponse = this.parseArrayData(oRequest, oFullResponse); - break; - case DS.TYPE_JSON: - if(xhr && oRawResponse && oRawResponse.responseText) { - oFullResponse = oRawResponse.responseText; - } - try { - // Convert to JSON object if it's a string - if(lang.isString(oFullResponse)) { - var parseArgs = [oFullResponse].concat(this.parseJSONArgs); - // Check for YUI JSON Util - if(lang.JSON) { - oFullResponse = lang.JSON.parse.apply(lang.JSON,parseArgs); - } - // Look for JSON parsers using an API similar to json2.js - else if(window.JSON && JSON.parse) { - oFullResponse = JSON.parse.apply(JSON,parseArgs); - } - // Look for JSON parsers using an API similar to json.js - else if(oFullResponse.parseJSON) { - oFullResponse = oFullResponse.parseJSON.apply(oFullResponse,parseArgs.slice(1)); - } - // No JSON lib found so parse the string - else { - // Trim leading spaces - while (oFullResponse.length > 0 && - (oFullResponse.charAt(0) != "{") && - (oFullResponse.charAt(0) != "[")) { - oFullResponse = oFullResponse.substring(1, oFullResponse.length); - } - - if(oFullResponse.length > 0) { - // Strip extraneous stuff at the end - var objEnd = Math.max(oFullResponse.lastIndexOf("]"),oFullResponse.lastIndexOf("}")); - oFullResponse = oFullResponse.substring(0,objEnd+1); - - // Turn the string into an object literal... - // ...eval is necessary here - oFullResponse = eval("(" + oFullResponse + ")"); - - } - } - } - } - catch(e) { - } - - oFullResponse = this.doBeforeParseData(oRequest, oFullResponse, oCallback); - oParsedResponse = this.parseJSONData(oRequest, oFullResponse); - break; - case DS.TYPE_HTMLTABLE: - if(xhr && oRawResponse.responseText) { - var el = document.createElement('div'); - el.innerHTML = oRawResponse.responseText; - oFullResponse = el.getElementsByTagName('table')[0]; - } - oFullResponse = this.doBeforeParseData(oRequest, oFullResponse, oCallback); - oParsedResponse = this.parseHTMLTableData(oRequest, oFullResponse); - break; - case DS.TYPE_XML: - if(xhr && oRawResponse.responseXML) { - oFullResponse = oRawResponse.responseXML; - } - oFullResponse = this.doBeforeParseData(oRequest, oFullResponse, oCallback); - oParsedResponse = this.parseXMLData(oRequest, oFullResponse); - break; - case DS.TYPE_TEXT: - if(xhr && lang.isString(oRawResponse.responseText)) { - oFullResponse = oRawResponse.responseText; - } - oFullResponse = this.doBeforeParseData(oRequest, oFullResponse, oCallback); - oParsedResponse = this.parseTextData(oRequest, oFullResponse); - break; - default: - oFullResponse = this.doBeforeParseData(oRequest, oFullResponse, oCallback); - oParsedResponse = this.parseData(oRequest, oFullResponse); - break; - } - - - // Clean up for consistent signature - oParsedResponse = oParsedResponse || {}; - if(!oParsedResponse.results) { - oParsedResponse.results = []; - } - if(!oParsedResponse.meta) { - oParsedResponse.meta = {}; - } - - // Success - if(!oParsedResponse.error) { - // Last chance to touch the raw response or the parsed response - oParsedResponse = this.doBeforeCallback(oRequest, oFullResponse, oParsedResponse, oCallback); - this.fireEvent("responseParseEvent", {request:oRequest, - response:oParsedResponse, callback:oCallback, caller:oCaller}); - // Cache the response - this.addToCache(oRequest, oParsedResponse); - } - // Error - else { - // Be sure the error flag is on - oParsedResponse.error = true; - this.fireEvent("dataErrorEvent", {request:oRequest, response: oRawResponse, callback:oCallback, - caller:oCaller, message:DS.ERROR_DATANULL}); - YAHOO.log(DS.ERROR_DATANULL, "error", this.toString()); - } - - // Send the response back to the caller - oParsedResponse.tId = tId; - DS.issueCallback(oCallback,[oRequest,oParsedResponse],oParsedResponse.error,oCaller); -}, - -/** - * Overridable method gives implementers access to the original full response - * before the data gets parsed. Implementers should take care not to return an - * unparsable or otherwise invalid response. - * - * @method doBeforeParseData - * @param oRequest {Object} Request object. - * @param oFullResponse {Object} The full response from the live database. - * @param oCallback {Object} The callback object. - * @return {Object} Full response for parsing. - - */ -doBeforeParseData : function(oRequest, oFullResponse, oCallback) { - return oFullResponse; -}, - -/** - * Overridable method gives implementers access to the original full response and - * the parsed response (parsed against the given schema) before the data - * is added to the cache (if applicable) and then sent back to callback function. - * This is your chance to access the raw response and/or populate the parsed - * response with any custom data. - * - * @method doBeforeCallback - * @param oRequest {Object} Request object. - * @param oFullResponse {Object} The full response from the live database. - * @param oParsedResponse {Object} The parsed response to return to calling object. - * @param oCallback {Object} The callback object. - * @return {Object} Parsed response object. - */ -doBeforeCallback : function(oRequest, oFullResponse, oParsedResponse, oCallback) { - return oParsedResponse; -}, - -/** - * Overridable method parses data of generic RESPONSE_TYPE into a response object. - * - * @method parseData - * @param oRequest {Object} Request object. - * @param oFullResponse {Object} The full Array from the live database. - * @return {Object} Parsed response object with the following properties:
    - * - results {Array} Array of parsed data results
    - * - meta {Object} Object literal of meta values
    - * - error {Boolean} (optional) True if there was an error
    - */ -parseData : function(oRequest, oFullResponse) { - if(lang.isValue(oFullResponse)) { - var oParsedResponse = {results:oFullResponse,meta:{}}; - YAHOO.log("Parsed generic data is " + - lang.dump(oParsedResponse), "info", this.toString()); - return oParsedResponse; - - } - YAHOO.log("Generic data could not be parsed: " + lang.dump(oFullResponse), - "error", this.toString()); - return null; -}, - -/** - * Overridable method parses Array data into a response object. - * - * @method parseArrayData - * @param oRequest {Object} Request object. - * @param oFullResponse {Object} The full Array from the live database. - * @return {Object} Parsed response object with the following properties:
    - * - results (Array) Array of parsed data results
    - * - error (Boolean) True if there was an error - */ -parseArrayData : function(oRequest, oFullResponse) { - if(lang.isArray(oFullResponse)) { - var results = [], - i, j, - rec, field, data; - - // Parse for fields - if(lang.isArray(this.responseSchema.fields)) { - var fields = this.responseSchema.fields; - for (i = fields.length - 1; i >= 0; --i) { - if (typeof fields[i] !== 'object') { - fields[i] = { key : fields[i] }; - } - } - - var parsers = {}, p; - for (i = fields.length - 1; i >= 0; --i) { - p = (typeof fields[i].parser === 'function' ? - fields[i].parser : - DS.Parser[fields[i].parser+'']) || fields[i].converter; - if (p) { - parsers[fields[i].key] = p; - } - } - - var arrType = lang.isArray(oFullResponse[0]); - for(i=oFullResponse.length-1; i>-1; i--) { - var oResult = {}; - rec = oFullResponse[i]; - if (typeof rec === 'object') { - for(j=fields.length-1; j>-1; j--) { - field = fields[j]; - data = arrType ? rec[j] : rec[field.key]; - - if (parsers[field.key]) { - data = parsers[field.key].call(this,data); - } - - // Safety measure - if(data === undefined) { - data = null; - } - - oResult[field.key] = data; - } - } - else if (lang.isString(rec)) { - for(j=fields.length-1; j>-1; j--) { - field = fields[j]; - data = rec; - - if (parsers[field.key]) { - data = parsers[field.key].call(this,data); - } - - // Safety measure - if(data === undefined) { - data = null; - } - - oResult[field.key] = data; - } - } - results[i] = oResult; - } - } - // Return entire data set - else { - results = oFullResponse; - } - var oParsedResponse = {results:results}; - YAHOO.log("Parsed array data is " + - lang.dump(oParsedResponse), "info", this.toString()); - return oParsedResponse; - - } - YAHOO.log("Array data could not be parsed: " + lang.dump(oFullResponse), - "error", this.toString()); - return null; -}, - -/** - * Overridable method parses plain text data into a response object. - * - * @method parseTextData - * @param oRequest {Object} Request object. - * @param oFullResponse {Object} The full text response from the live database. - * @return {Object} Parsed response object with the following properties:
    - * - results (Array) Array of parsed data results
    - * - error (Boolean) True if there was an error - */ -parseTextData : function(oRequest, oFullResponse) { - if(lang.isString(oFullResponse)) { - if(lang.isString(this.responseSchema.recordDelim) && - lang.isString(this.responseSchema.fieldDelim)) { - var oParsedResponse = {results:[]}; - var recDelim = this.responseSchema.recordDelim; - var fieldDelim = this.responseSchema.fieldDelim; - if(oFullResponse.length > 0) { - // Delete the last line delimiter at the end of the data if it exists - var newLength = oFullResponse.length-recDelim.length; - if(oFullResponse.substr(newLength) == recDelim) { - oFullResponse = oFullResponse.substr(0, newLength); - } - if(oFullResponse.length > 0) { - // Split along record delimiter to get an array of strings - var recordsarray = oFullResponse.split(recDelim); - // Cycle through each record - for(var i = 0, len = recordsarray.length, recIdx = 0; i < len; ++i) { - var bError = false, - sRecord = recordsarray[i]; - if (lang.isString(sRecord) && (sRecord.length > 0)) { - // Split each record along field delimiter to get data - var fielddataarray = recordsarray[i].split(fieldDelim); - var oResult = {}; - - // Filter for fields data - if(lang.isArray(this.responseSchema.fields)) { - var fields = this.responseSchema.fields; - for(var j=fields.length-1; j>-1; j--) { - try { - // Remove quotation marks from edges, if applicable - var data = fielddataarray[j]; - if (lang.isString(data)) { - if(data.charAt(0) == "\"") { - data = data.substr(1); - } - if(data.charAt(data.length-1) == "\"") { - data = data.substr(0,data.length-1); - } - var field = fields[j]; - var key = (lang.isValue(field.key)) ? field.key : field; - // Backward compatibility - if(!field.parser && field.converter) { - field.parser = field.converter; - YAHOO.log("The field property converter has been deprecated" + - " in favor of parser", "warn", this.toString()); - } - var parser = (typeof field.parser === 'function') ? - field.parser : - DS.Parser[field.parser+'']; - if(parser) { - data = parser.call(this, data); - } - // Safety measure - if(data === undefined) { - data = null; - } - oResult[key] = data; - } - else { - bError = true; - } - } - catch(e) { - bError = true; - } - } - } - // No fields defined so pass along all data as an array - else { - oResult = fielddataarray; - } - if(!bError) { - oParsedResponse.results[recIdx++] = oResult; - } - } - } - } - } - YAHOO.log("Parsed text data is " + - lang.dump(oParsedResponse), "info", this.toString()); - return oParsedResponse; - } - } - YAHOO.log("Text data could not be parsed: " + lang.dump(oFullResponse), - "error", this.toString()); - return null; - -}, - -/** - * Overridable method parses XML data for one result into an object literal. - * - * @method parseXMLResult - * @param result {XML} XML for one result. - * @return {Object} Object literal of data for one result. - */ -parseXMLResult : function(result) { - var oResult = {}, - schema = this.responseSchema; - - try { - // Loop through each data field in each result using the schema - for(var m = schema.fields.length-1; m >= 0 ; m--) { - var field = schema.fields[m]; - var key = (lang.isValue(field.key)) ? field.key : field; - var data = null; - - if(this.useXPath) { - data = YAHOO.util.DataSource._getLocationValue(field, result); - } - else { - // Values may be held in an attribute... - var xmlAttr = result.attributes.getNamedItem(key); - if(xmlAttr) { - data = xmlAttr.value; - } - // ...or in a node - else { - var xmlNode = result.getElementsByTagName(key); - if(xmlNode && xmlNode.item(0)) { - var item = xmlNode.item(0); - // For IE, then DOM... - data = (item) ? ((item.text) ? item.text : (item.textContent) ? item.textContent : null) : null; - // ...then fallback, but check for multiple child nodes - if(!data) { - var datapieces = []; - for(var j=0, len=item.childNodes.length; j 0) { - data = datapieces.join(""); - } - } - } - } - } - - - // Safety net - if(data === null) { - data = ""; - } - // Backward compatibility - if(!field.parser && field.converter) { - field.parser = field.converter; - YAHOO.log("The field property converter has been deprecated" + - " in favor of parser", "warn", this.toString()); - } - var parser = (typeof field.parser === 'function') ? - field.parser : - DS.Parser[field.parser+'']; - if(parser) { - data = parser.call(this, data); - } - // Safety measure - if(data === undefined) { - data = null; - } - oResult[key] = data; - } - } - catch(e) { - YAHOO.log("Error while parsing XML result: " + e.message); - } - - return oResult; -}, - - - -/** - * Overridable method parses XML data into a response object. - * - * @method parseXMLData - * @param oRequest {Object} Request object. - * @param oFullResponse {Object} The full XML response from the live database. - * @return {Object} Parsed response object with the following properties
    - * - results (Array) Array of parsed data results
    - * - error (Boolean) True if there was an error - */ -parseXMLData : function(oRequest, oFullResponse) { - var bError = false, - schema = this.responseSchema, - oParsedResponse = {meta:{}}, - xmlList = null, - metaNode = schema.metaNode, - metaLocators = schema.metaFields || {}, - i,k,loc,v; - - // In case oFullResponse is something funky - try { - // Pull any meta identified - if(this.useXPath) { - for (k in metaLocators) { - oParsedResponse.meta[k] = YAHOO.util.DataSource._getLocationValue(metaLocators[k], oFullResponse); - } - } - else { - metaNode = metaNode ? oFullResponse.getElementsByTagName(metaNode)[0] : - oFullResponse; - - if (metaNode) { - for (k in metaLocators) { - if (lang.hasOwnProperty(metaLocators, k)) { - loc = metaLocators[k]; - // Look for a node - v = metaNode.getElementsByTagName(loc)[0]; - - if (v) { - v = v.firstChild.nodeValue; - } else { - // Look for an attribute - v = metaNode.attributes.getNamedItem(loc); - if (v) { - v = v.value; - } - } - - if (lang.isValue(v)) { - oParsedResponse.meta[k] = v; - } - } - } - } - } - - // For result data - xmlList = (schema.resultNode) ? - oFullResponse.getElementsByTagName(schema.resultNode) : - null; - } - catch(e) { - YAHOO.log("Error while parsing XML data: " + e.message); - } - if(!xmlList || !lang.isArray(schema.fields)) { - bError = true; - } - // Loop through each result - else { - oParsedResponse.results = []; - for(i = xmlList.length-1; i >= 0 ; --i) { - var oResult = this.parseXMLResult(xmlList.item(i)); - // Capture each array of values into an array of results - oParsedResponse.results[i] = oResult; - } - } - if(bError) { - YAHOO.log("XML data could not be parsed: " + - lang.dump(oFullResponse), "error", this.toString()); - oParsedResponse.error = true; - } - else { - YAHOO.log("Parsed XML data is " + - lang.dump(oParsedResponse), "info", this.toString()); - } - return oParsedResponse; -}, - -/** - * Overridable method parses JSON data into a response object. - * - * @method parseJSONData - * @param oRequest {Object} Request object. - * @param oFullResponse {Object} The full JSON from the live database. - * @return {Object} Parsed response object with the following properties
    - * - results (Array) Array of parsed data results
    - * - error (Boolean) True if there was an error - */ -parseJSONData : function(oRequest, oFullResponse) { - var oParsedResponse = {results:[],meta:{}}; - - if(lang.isObject(oFullResponse) && this.responseSchema.resultsList) { - var schema = this.responseSchema, - fields = schema.fields, - resultsList = oFullResponse, - results = [], - metaFields = schema.metaFields || {}, - fieldParsers = [], - fieldPaths = [], - simpleFields = [], - bError = false, - i,len,j,v,key,parser,path; - - // Function to convert the schema's fields into walk paths - var buildPath = function (needle) { - var path = null, keys = [], i = 0; - if (needle) { - // Strip the ["string keys"] and [1] array indexes - needle = needle. - replace(/\[(['"])(.*?)\1\]/g, - function (x,$1,$2) {keys[i]=$2;return '.@'+(i++);}). - replace(/\[(\d+)\]/g, - function (x,$1) {keys[i]=parseInt($1,10)|0;return '.@'+(i++);}). - replace(/^\./,''); // remove leading dot - - // If the cleaned needle contains invalid characters, the - // path is invalid - if (!/[^\w\.\$@]/.test(needle)) { - path = needle.split('.'); - for (i=path.length-1; i >= 0; --i) { - if (path[i].charAt(0) === '@') { - path[i] = keys[parseInt(path[i].substr(1),10)]; - } - } - } - else { - YAHOO.log("Invalid locator: " + needle, "error", this.toString()); - } - } - return path; - }; - - - // Function to walk a path and return the pot of gold - var walkPath = function (path, origin) { - var v=origin,i=0,len=path.length; - for (;i 1) { - fieldPaths[fieldPaths.length] = {key:key,path:path}; - } else { - simpleFields[simpleFields.length] = {key:key,path:path[0]}; - } - } else { - YAHOO.log("Invalid key syntax: " + key,"warn",this.toString()); - } - } - - // Process the results, flattening the records and/or applying parsers if needed - for (i = resultsList.length - 1; i >= 0; --i) { - var r = resultsList[i], rec = {}; - if(r) { - for (j = simpleFields.length - 1; j >= 0; --j) { - // Bug 1777850: data might be held in an array - rec[simpleFields[j].key] = - (r[simpleFields[j].path] !== undefined) ? - r[simpleFields[j].path] : r[j]; - } - - for (j = fieldPaths.length - 1; j >= 0; --j) { - rec[fieldPaths[j].key] = walkPath(fieldPaths[j].path,r); - } - - for (j = fieldParsers.length - 1; j >= 0; --j) { - var p = fieldParsers[j].key; - rec[p] = fieldParsers[j].parser(rec[p]); - if (rec[p] === undefined) { - rec[p] = null; - } - } - } - results[i] = rec; - } - } - else { - results = resultsList; - } - - for (key in metaFields) { - if (lang.hasOwnProperty(metaFields,key)) { - path = buildPath(metaFields[key]); - if (path) { - v = walkPath(path, oFullResponse); - oParsedResponse.meta[key] = v; - } - } - } - - } else { - YAHOO.log("JSON data could not be parsed due to invalid responseSchema.resultsList or invalid response: " + - lang.dump(oFullResponse), "error", this.toString()); - - oParsedResponse.error = true; - } - - oParsedResponse.results = results; - } - else { - YAHOO.log("JSON data could not be parsed: " + - lang.dump(oFullResponse), "error", this.toString()); - oParsedResponse.error = true; - } - - return oParsedResponse; -}, - -/** - * Overridable method parses an HTML TABLE element reference into a response object. - * Data is parsed out of TR elements from all TBODY elements. - * - * @method parseHTMLTableData - * @param oRequest {Object} Request object. - * @param oFullResponse {Object} The full HTML element reference from the live database. - * @return {Object} Parsed response object with the following properties
    - * - results (Array) Array of parsed data results
    - * - error (Boolean) True if there was an error - */ -parseHTMLTableData : function(oRequest, oFullResponse) { - var bError = false; - var elTable = oFullResponse; - var fields = this.responseSchema.fields; - var oParsedResponse = {results:[]}; - - if(lang.isArray(fields)) { - // Iterate through each TBODY - for(var i=0; i-1; j--) { - var elRow = elTbody.rows[j]; - var oResult = {}; - - for(var k=fields.length-1; k>-1; k--) { - var field = fields[k]; - var key = (lang.isValue(field.key)) ? field.key : field; - var data = elRow.cells[k].innerHTML; - - // Backward compatibility - if(!field.parser && field.converter) { - field.parser = field.converter; - YAHOO.log("The field property converter has been deprecated" + - " in favor of parser", "warn", this.toString()); - } - var parser = (typeof field.parser === 'function') ? - field.parser : - DS.Parser[field.parser+'']; - if(parser) { - data = parser.call(this, data); - } - // Safety measure - if(data === undefined) { - data = null; - } - oResult[key] = data; - } - oParsedResponse.results[j] = oResult; - } - } - } - else { - bError = true; - YAHOO.log("Invalid responseSchema.fields", "error", this.toString()); - } - - if(bError) { - YAHOO.log("HTML TABLE data could not be parsed: " + - lang.dump(oFullResponse), "error", this.toString()); - oParsedResponse.error = true; - } - else { - YAHOO.log("Parsed HTML TABLE data is " + - lang.dump(oParsedResponse), "info", this.toString()); - } - return oParsedResponse; -} - -}; - -// DataSourceBase uses EventProvider -lang.augmentProto(DS, util.EventProvider); - - - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -/** - * LocalDataSource class for in-memory data structs including JavaScript arrays, - * JavaScript object literals (JSON), XML documents, and HTML tables. - * - * @namespace YAHOO.util - * @class YAHOO.util.LocalDataSource - * @extends YAHOO.util.DataSourceBase - * @constructor - * @param oLiveData {HTMLElement} Pointer to live data. - * @param oConfigs {object} (optional) Object literal of configuration values. - */ -util.LocalDataSource = function(oLiveData, oConfigs) { - this.dataType = DS.TYPE_LOCAL; - - if(oLiveData) { - if(YAHOO.lang.isArray(oLiveData)) { // array - this.responseType = DS.TYPE_JSARRAY; - } - // xml - else if(oLiveData.nodeType && oLiveData.nodeType == 9) { - this.responseType = DS.TYPE_XML; - } - else if(oLiveData.nodeName && (oLiveData.nodeName.toLowerCase() == "table")) { // table - this.responseType = DS.TYPE_HTMLTABLE; - oLiveData = oLiveData.cloneNode(true); - } - else if(YAHOO.lang.isString(oLiveData)) { // text - this.responseType = DS.TYPE_TEXT; - } - else if(YAHOO.lang.isObject(oLiveData)) { // json - this.responseType = DS.TYPE_JSON; - } - } - else { - oLiveData = []; - this.responseType = DS.TYPE_JSARRAY; - } - - util.LocalDataSource.superclass.constructor.call(this, oLiveData, oConfigs); -}; - -// LocalDataSource extends DataSourceBase -lang.extend(util.LocalDataSource, DS); - -// Copy static members to LocalDataSource class -lang.augmentObject(util.LocalDataSource, DS); - - - - - - - - - - - - - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -/** - * FunctionDataSource class for JavaScript functions. - * - * @namespace YAHOO.util - * @class YAHOO.util.FunctionDataSource - * @extends YAHOO.util.DataSourceBase - * @constructor - * @param oLiveData {HTMLElement} Pointer to live data. - * @param oConfigs {object} (optional) Object literal of configuration values. - */ -util.FunctionDataSource = function(oLiveData, oConfigs) { - this.dataType = DS.TYPE_JSFUNCTION; - oLiveData = oLiveData || function() {}; - - util.FunctionDataSource.superclass.constructor.call(this, oLiveData, oConfigs); -}; - -// FunctionDataSource extends DataSourceBase -lang.extend(util.FunctionDataSource, DS, { - -///////////////////////////////////////////////////////////////////////////// -// -// FunctionDataSource public properties -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Context in which to execute the function. By default, is the DataSource - * instance itself. If set, the function will receive the DataSource instance - * as an additional argument. - * - * @property scope - * @type Object - * @default null - */ -scope : null, - - -///////////////////////////////////////////////////////////////////////////// -// -// FunctionDataSource public methods -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Overriding method passes query to a function. The returned response is then - * forwarded to the handleResponse function. - * - * @method makeConnection - * @param oRequest {Object} Request object. - * @param oCallback {Object} Callback object literal. - * @param oCaller {Object} (deprecated) Use oCallback.scope. - * @return {Number} Transaction ID. - */ -makeConnection : function(oRequest, oCallback, oCaller) { - var tId = DS._nTransactionId++; - this.fireEvent("requestEvent", {tId:tId,request:oRequest,callback:oCallback,caller:oCaller}); - - // Pass the request in as a parameter and - // forward the return value to the handler - - - var oRawResponse = (this.scope) ? this.liveData.call(this.scope, oRequest, this) : this.liveData(oRequest); - - // Try to sniff data type if it has not been defined - if(this.responseType === DS.TYPE_UNKNOWN) { - if(YAHOO.lang.isArray(oRawResponse)) { // array - this.responseType = DS.TYPE_JSARRAY; - } - // xml - else if(oRawResponse && oRawResponse.nodeType && oRawResponse.nodeType == 9) { - this.responseType = DS.TYPE_XML; - } - else if(oRawResponse && oRawResponse.nodeName && (oRawResponse.nodeName.toLowerCase() == "table")) { // table - this.responseType = DS.TYPE_HTMLTABLE; - } - else if(YAHOO.lang.isObject(oRawResponse)) { // json - this.responseType = DS.TYPE_JSON; - } - else if(YAHOO.lang.isString(oRawResponse)) { // text - this.responseType = DS.TYPE_TEXT; - } - } - - this.handleResponse(oRequest, oRawResponse, oCallback, oCaller, tId); - return tId; -} - -}); - -// Copy static members to FunctionDataSource class -lang.augmentObject(util.FunctionDataSource, DS); - - - - - - - - - - - - - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -/** - * ScriptNodeDataSource class for accessing remote data via the YUI Get Utility. - * - * @namespace YAHOO.util - * @class YAHOO.util.ScriptNodeDataSource - * @extends YAHOO.util.DataSourceBase - * @constructor - * @param oLiveData {HTMLElement} Pointer to live data. - * @param oConfigs {object} (optional) Object literal of configuration values. - */ -util.ScriptNodeDataSource = function(oLiveData, oConfigs) { - this.dataType = DS.TYPE_SCRIPTNODE; - oLiveData = oLiveData || ""; - - util.ScriptNodeDataSource.superclass.constructor.call(this, oLiveData, oConfigs); -}; - -// ScriptNodeDataSource extends DataSourceBase -lang.extend(util.ScriptNodeDataSource, DS, { - -///////////////////////////////////////////////////////////////////////////// -// -// ScriptNodeDataSource public properties -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Alias to YUI Get Utility, to allow implementers to use a custom class. - * - * @property getUtility - * @type Object - * @default YAHOO.util.Get - */ -getUtility : util.Get, - -/** - * Defines request/response management in the following manner: - *
    - * - *
    ignoreStaleResponses
    - *
    Send all requests, but handle only the response for the most recently sent request.
    - *
    allowAll
    - *
    Send all requests and handle all responses.
    - *
    - * - * @property asyncMode - * @type String - * @default "allowAll" - */ -asyncMode : "allowAll", - -/** - * Callback string parameter name sent to the remote script. By default, - * requests are sent to - * <URI>?<scriptCallbackParam>=callbackFunction - * - * @property scriptCallbackParam - * @type String - * @default "callback" - */ -scriptCallbackParam : "callback", - - -///////////////////////////////////////////////////////////////////////////// -// -// ScriptNodeDataSource public methods -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Creates a request callback that gets appended to the script URI. Implementers - * can customize this string to match their server's query syntax. - * - * @method generateRequestCallback - * @return {String} String fragment that gets appended to script URI that - * specifies the callback function - */ -generateRequestCallback : function(id) { - return "&" + this.scriptCallbackParam + "=YAHOO.util.ScriptNodeDataSource.callbacks["+id+"]" ; -}, - -/** - * Overridable method gives implementers access to modify the URI before the dynamic - * script node gets inserted. Implementers should take care not to return an - * invalid URI. - * - * @method doBeforeGetScriptNode - * @param {String} URI to the script - * @return {String} URI to the script - */ -doBeforeGetScriptNode : function(sUri) { - return sUri; -}, - -/** - * Overriding method passes query to Get Utility. The returned - * response is then forwarded to the handleResponse function. - * - * @method makeConnection - * @param oRequest {Object} Request object. - * @param oCallback {Object} Callback object literal. - * @param oCaller {Object} (deprecated) Use oCallback.scope. - * @return {Number} Transaction ID. - */ -makeConnection : function(oRequest, oCallback, oCaller) { - var tId = DS._nTransactionId++; - this.fireEvent("requestEvent", {tId:tId,request:oRequest,callback:oCallback,caller:oCaller}); - - // If there are no global pending requests, it is safe to purge global callback stack and global counter - if(util.ScriptNodeDataSource._nPending === 0) { - util.ScriptNodeDataSource.callbacks = []; - util.ScriptNodeDataSource._nId = 0; - } - - // ID for this request - var id = util.ScriptNodeDataSource._nId; - util.ScriptNodeDataSource._nId++; - - // Dynamically add handler function with a closure to the callback stack - var oSelf = this; - util.ScriptNodeDataSource.callbacks[id] = function(oRawResponse) { - if((oSelf.asyncMode !== "ignoreStaleResponses")|| - (id === util.ScriptNodeDataSource.callbacks.length-1)) { // Must ignore stale responses - - // Try to sniff data type if it has not been defined - if(oSelf.responseType === DS.TYPE_UNKNOWN) { - if(YAHOO.lang.isArray(oRawResponse)) { // array - oSelf.responseType = DS.TYPE_JSARRAY; - } - // xml - else if(oRawResponse.nodeType && oRawResponse.nodeType == 9) { - oSelf.responseType = DS.TYPE_XML; - } - else if(oRawResponse.nodeName && (oRawResponse.nodeName.toLowerCase() == "table")) { // table - oSelf.responseType = DS.TYPE_HTMLTABLE; - } - else if(YAHOO.lang.isObject(oRawResponse)) { // json - oSelf.responseType = DS.TYPE_JSON; - } - else if(YAHOO.lang.isString(oRawResponse)) { // text - oSelf.responseType = DS.TYPE_TEXT; - } - } - - oSelf.handleResponse(oRequest, oRawResponse, oCallback, oCaller, tId); - } - else { - YAHOO.log("DataSource ignored stale response for tId " + tId + "(" + oRequest + ")", "info", oSelf.toString()); - } - - delete util.ScriptNodeDataSource.callbacks[id]; - }; - - // We are now creating a request - util.ScriptNodeDataSource._nPending++; - var sUri = this.liveData + oRequest + this.generateRequestCallback(id); - sUri = this.doBeforeGetScriptNode(sUri); - YAHOO.log("DataSource is querying URL " + sUri, "info", this.toString()); - this.getUtility.script(sUri, - {autopurge: true, - onsuccess: util.ScriptNodeDataSource._bumpPendingDown, - onfail: util.ScriptNodeDataSource._bumpPendingDown}); - - return tId; -} - -}); - -// Copy static members to ScriptNodeDataSource class -lang.augmentObject(util.ScriptNodeDataSource, DS); - -// Copy static members to ScriptNodeDataSource class -lang.augmentObject(util.ScriptNodeDataSource, { - -///////////////////////////////////////////////////////////////////////////// -// -// ScriptNodeDataSource private static properties -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Unique ID to track requests. - * - * @property _nId - * @type Number - * @private - * @static - */ -_nId : 0, - -/** - * Counter for pending requests. When this is 0, it is safe to purge callbacks - * array. - * - * @property _nPending - * @type Number - * @private - * @static - */ -_nPending : 0, - -/** - * Global array of callback functions, one for each request sent. - * - * @property callbacks - * @type Function[] - * @static - */ -callbacks : [] - -}); - - - - - - - - - - - - - - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -/** - * XHRDataSource class for accessing remote data via the YUI Connection Manager - * Utility - * - * @namespace YAHOO.util - * @class YAHOO.util.XHRDataSource - * @extends YAHOO.util.DataSourceBase - * @constructor - * @param oLiveData {HTMLElement} Pointer to live data. - * @param oConfigs {object} (optional) Object literal of configuration values. - */ -util.XHRDataSource = function(oLiveData, oConfigs) { - this.dataType = DS.TYPE_XHR; - this.connMgr = this.connMgr || util.Connect; - oLiveData = oLiveData || ""; - - util.XHRDataSource.superclass.constructor.call(this, oLiveData, oConfigs); -}; - -// XHRDataSource extends DataSourceBase -lang.extend(util.XHRDataSource, DS, { - -///////////////////////////////////////////////////////////////////////////// -// -// XHRDataSource public properties -// -///////////////////////////////////////////////////////////////////////////// - - /** - * Alias to YUI Connection Manager, to allow implementers to use a custom class. - * - * @property connMgr - * @type Object - * @default YAHOO.util.Connect - */ -connMgr: null, - - /** - * Defines request/response management in the following manner: - *
    - *
    queueRequests
    - *
    If a request is already in progress, wait until response is returned - * before sending the next request.
    - * - *
    cancelStaleRequests
    - *
    If a request is already in progress, cancel it before sending the next - * request.
    - * - *
    ignoreStaleResponses
    - *
    Send all requests, but handle only the response for the most recently - * sent request.
    - * - *
    allowAll
    - *
    Send all requests and handle all responses.
    - * - *
    - * - * @property connXhrMode - * @type String - * @default "allowAll" - */ -connXhrMode: "allowAll", - - /** - * True if data is to be sent via POST. By default, data will be sent via GET. - * - * @property connMethodPost - * @type Boolean - * @default false - */ -connMethodPost: false, - - /** - * The connection timeout defines how many milliseconds the XHR connection will - * wait for a server response. Any non-zero value will enable the Connection Manager's - * Auto-Abort feature. - * - * @property connTimeout - * @type Number - * @default 0 - */ -connTimeout: 0, - -///////////////////////////////////////////////////////////////////////////// -// -// XHRDataSource public methods -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Overriding method passes query to Connection Manager. The returned - * response is then forwarded to the handleResponse function. - * - * @method makeConnection - * @param oRequest {Object} Request object. - * @param oCallback {Object} Callback object literal. - * @param oCaller {Object} (deprecated) Use oCallback.scope. - * @return {Number} Transaction ID. - */ -makeConnection : function(oRequest, oCallback, oCaller) { - - var oRawResponse = null; - var tId = DS._nTransactionId++; - this.fireEvent("requestEvent", {tId:tId,request:oRequest,callback:oCallback,caller:oCaller}); - - // Set up the callback object and - // pass the request in as a URL query and - // forward the response to the handler - var oSelf = this; - var oConnMgr = this.connMgr; - var oQueue = this._oQueue; - - /** - * Define Connection Manager success handler - * - * @method _xhrSuccess - * @param oResponse {Object} HTTPXMLRequest object - * @private - */ - var _xhrSuccess = function(oResponse) { - // If response ID does not match last made request ID, - // silently fail and wait for the next response - if(oResponse && (this.connXhrMode == "ignoreStaleResponses") && - (oResponse.tId != oQueue.conn.tId)) { - YAHOO.log("Ignored stale response", "warn", this.toString()); - return null; - } - // Error if no response - else if(!oResponse) { - this.fireEvent("dataErrorEvent", {request:oRequest, response:null, - callback:oCallback, caller:oCaller, - message:DS.ERROR_DATANULL}); - YAHOO.log(DS.ERROR_DATANULL, "error", this.toString()); - - // Send error response back to the caller with the error flag on - DS.issueCallback(oCallback,[oRequest, {error:true}], true, oCaller); - - return null; - } - // Forward to handler - else { - // Try to sniff data type if it has not been defined - if(this.responseType === DS.TYPE_UNKNOWN) { - var ctype = (oResponse.getResponseHeader) ? oResponse.getResponseHeader["Content-Type"] : null; - if(ctype) { - // xml - if(ctype.indexOf("text/xml") > -1) { - this.responseType = DS.TYPE_XML; - } - else if(ctype.indexOf("application/json") > -1) { // json - this.responseType = DS.TYPE_JSON; - } - else if(ctype.indexOf("text/plain") > -1) { // text - this.responseType = DS.TYPE_TEXT; - } - } - } - this.handleResponse(oRequest, oResponse, oCallback, oCaller, tId); - } - }; - - /** - * Define Connection Manager failure handler - * - * @method _xhrFailure - * @param oResponse {Object} HTTPXMLRequest object - * @private - */ - var _xhrFailure = function(oResponse) { - this.fireEvent("dataErrorEvent", {request:oRequest, response: oResponse, - callback:oCallback, caller:oCaller, - message:DS.ERROR_DATAINVALID}); - YAHOO.log(DS.ERROR_DATAINVALID + ": " + - oResponse.statusText, "error", this.toString()); - - // Backward compatibility - if(lang.isString(this.liveData) && lang.isString(oRequest) && - (this.liveData.lastIndexOf("?") !== this.liveData.length-1) && - (oRequest.indexOf("?") !== 0)){ - YAHOO.log("DataSources using XHR no longer automatically supply " + - "a \"?\" between the host and query parameters" + - " -- please check that the request URL is correct", "warn", this.toString()); - } - - // Send failure response back to the caller with the error flag on - oResponse = oResponse || {}; - oResponse.error = true; - DS.issueCallback(oCallback,[oRequest,oResponse],true, oCaller); - - return null; - }; - - /** - * Define Connection Manager callback object - * - * @property _xhrCallback - * @param oResponse {Object} HTTPXMLRequest object - * @private - */ - var _xhrCallback = { - success:_xhrSuccess, - failure:_xhrFailure, - scope: this - }; - - // Apply Connection Manager timeout - if(lang.isNumber(this.connTimeout)) { - _xhrCallback.timeout = this.connTimeout; - } - - // Cancel stale requests - if(this.connXhrMode == "cancelStaleRequests") { - // Look in queue for stale requests - if(oQueue.conn) { - if(oConnMgr.abort) { - oConnMgr.abort(oQueue.conn); - oQueue.conn = null; - YAHOO.log("Canceled stale request", "warn", this.toString()); - } - else { - YAHOO.log("Could not find Connection Manager abort() function", "error", this.toString()); - } - } - } - - // Get ready to send the request URL - if(oConnMgr && oConnMgr.asyncRequest) { - var sLiveData = this.liveData; - var isPost = this.connMethodPost; - var sMethod = (isPost) ? "POST" : "GET"; - // Validate request - var sUri = (isPost || !lang.isValue(oRequest)) ? sLiveData : sLiveData+oRequest; - var sRequest = (isPost) ? oRequest : null; - - // Send the request right away - if(this.connXhrMode != "queueRequests") { - oQueue.conn = oConnMgr.asyncRequest(sMethod, sUri, _xhrCallback, sRequest); - } - // Queue up then send the request - else { - // Found a request already in progress - if(oQueue.conn) { - var allRequests = oQueue.requests; - // Add request to queue - allRequests.push({request:oRequest, callback:_xhrCallback}); - - // Interval needs to be started - if(!oQueue.interval) { - oQueue.interval = setInterval(function() { - // Connection is in progress - if(oConnMgr.isCallInProgress(oQueue.conn)) { - return; - } - else { - // Send next request - if(allRequests.length > 0) { - // Validate request - sUri = (isPost || !lang.isValue(allRequests[0].request)) ? sLiveData : sLiveData+allRequests[0].request; - sRequest = (isPost) ? allRequests[0].request : null; - oQueue.conn = oConnMgr.asyncRequest(sMethod, sUri, allRequests[0].callback, sRequest); - - // Remove request from queue - allRequests.shift(); - } - // No more requests - else { - clearInterval(oQueue.interval); - oQueue.interval = null; - } - } - }, 50); - } - } - // Nothing is in progress - else { - oQueue.conn = oConnMgr.asyncRequest(sMethod, sUri, _xhrCallback, sRequest); - } - } - } - else { - YAHOO.log("Could not find Connection Manager asyncRequest() function", "error", this.toString()); - // Send null response back to the caller with the error flag on - DS.issueCallback(oCallback,[oRequest,{error:true}],true,oCaller); - } - - return tId; -} - -}); - -// Copy static members to XHRDataSource class -lang.augmentObject(util.XHRDataSource, DS); - - - - - - - - - - - - - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -/** - * Factory class for creating a BaseDataSource subclass instance. The sublcass is - * determined by oLiveData's type, unless the dataType config is explicitly passed in. - * - * @namespace YAHOO.util - * @class YAHOO.util.DataSource - * @constructor - * @param oLiveData {HTMLElement} Pointer to live data. - * @param oConfigs {object} (optional) Object literal of configuration values. - */ -util.DataSource = function(oLiveData, oConfigs) { - oConfigs = oConfigs || {}; - - // Point to one of the subclasses, first by dataType if given, then by sniffing oLiveData type. - var dataType = oConfigs.dataType; - if(dataType) { - if(dataType == DS.TYPE_LOCAL) { - lang.augmentObject(util.DataSource, util.LocalDataSource); - return new util.LocalDataSource(oLiveData, oConfigs); - } - else if(dataType == DS.TYPE_XHR) { - lang.augmentObject(util.DataSource, util.XHRDataSource); - return new util.XHRDataSource(oLiveData, oConfigs); - } - else if(dataType == DS.TYPE_SCRIPTNODE) { - lang.augmentObject(util.DataSource, util.ScriptNodeDataSource); - return new util.ScriptNodeDataSource(oLiveData, oConfigs); - } - else if(dataType == DS.TYPE_JSFUNCTION) { - lang.augmentObject(util.DataSource, util.FunctionDataSource); - return new util.FunctionDataSource(oLiveData, oConfigs); - } - } - - if(YAHOO.lang.isString(oLiveData)) { // strings default to xhr - lang.augmentObject(util.DataSource, util.XHRDataSource); - return new util.XHRDataSource(oLiveData, oConfigs); - } - else if(YAHOO.lang.isFunction(oLiveData)) { - lang.augmentObject(util.DataSource, util.FunctionDataSource); - return new util.FunctionDataSource(oLiveData, oConfigs); - } - else { // ultimate default is local - lang.augmentObject(util.DataSource, util.LocalDataSource); - return new util.LocalDataSource(oLiveData, oConfigs); - } -}; - -// Copy static members to DataSource class -lang.augmentObject(util.DataSource, DS); - -})(); - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -/** - * The static Number class provides helper functions to deal with data of type - * Number. - * - * @namespace YAHOO.util - * @requires yahoo - * @class Number - * @static - */ - YAHOO.util.Number = { - - /** - * Takes a native JavaScript Number and formats to string for display to user. - * - * @method format - * @param nData {Number} Number. - * @param oConfig {Object} (Optional) Optional configuration values: - *
    - *
    prefix {String} - *
    String prepended before each number, like a currency designator "$"
    - *
    decimalPlaces {Number} - *
    Number of decimal places to round.
    - *
    decimalSeparator {String} - *
    Decimal separator
    - *
    thousandsSeparator {String} - *
    Thousands separator
    - *
    suffix {String} - *
    String appended after each number, like " items" (note the space)
    - *
    negativeFormat
    - *
    String used as a guide for how to indicate negative numbers. The first '#' character in the string will be replaced by the number. Default '-#'.
    - *
    - * @return {String} Formatted number for display. Note, the following values - * return as "": null, undefined, NaN, "". - */ - format : function(n, cfg) { - if (!isFinite(+n)) { - return ''; - } - - n = !isFinite(+n) ? 0 : +n; - cfg = YAHOO.lang.merge(YAHOO.util.Number.format.defaults, (cfg || {})); - - var neg = n < 0, absN = Math.abs(n), - places = cfg.decimalPlaces, - sep = cfg.thousandsSeparator, - s, bits, i; - - if (places < 0) { - // Get rid of the decimal info - s = absN - (absN % 1) + ''; - i = s.length + places; - - // avoid 123 vs decimalPlaces -4 (should return "0") - if (i > 0) { - // leverage toFixed by making 123 => 0.123 for the rounding - // operation, then add the appropriate number of zeros back on - s = Number('.' + s).toFixed(i).slice(2) + - new Array(s.length - i + 1).join('0'); - } else { - s = "0"; - } - } else { // There is a bug in IE's toFixed implementation: - // for n in {(-0.94, -0.5], [0.5, 0.94)} n.toFixed() returns 0 - // instead of -1 and 1. Manually handle that case. - s = absN < 1 && absN >= 0.5 && !places ? '1' : absN.toFixed(places); - } - - if (absN > 1000) { - bits = s.split(/\D/); - i = bits[0].length % 3 || 3; - - bits[0] = bits[0].slice(0,i) + - bits[0].slice(i).replace(/(\d{3})/g, sep + '$1'); - - s = bits.join(cfg.decimalSeparator); - } - - s = cfg.prefix + s + cfg.suffix; - - return neg ? cfg.negativeFormat.replace(/#/,s) : s; - } -}; -YAHOO.util.Number.format.defaults = { - decimalSeparator : '.', - decimalPlaces : null, - thousandsSeparator : '', - prefix : '', - suffix : '', - negativeFormat : '-#' -}; - - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -(function () { - -var xPad=function (x, pad, r) -{ - if(typeof r === 'undefined') - { - r=10; - } - for( ; parseInt(x, 10)1; r/=10) { - x = pad.toString() + x; - } - return x.toString(); -}; - - -/** - * The static Date class provides helper functions to deal with data of type Date. - * - * @namespace YAHOO.util - * @requires yahoo - * @class Date - * @static - */ - var Dt = { - formats: { - a: function (d, l) { return l.a[d.getDay()]; }, - A: function (d, l) { return l.A[d.getDay()]; }, - b: function (d, l) { return l.b[d.getMonth()]; }, - B: function (d, l) { return l.B[d.getMonth()]; }, - C: function (d) { return xPad(parseInt(d.getFullYear()/100, 10), 0); }, - d: ['getDate', '0'], - e: ['getDate', ' '], - g: function (d) { return xPad(parseInt(Dt.formats.G(d)%100, 10), 0); }, - G: function (d) { - var y = d.getFullYear(); - var V = parseInt(Dt.formats.V(d), 10); - var W = parseInt(Dt.formats.W(d), 10); - - if(W > V) { - y++; - } else if(W===0 && V>=52) { - y--; - } - - return y; - }, - H: ['getHours', '0'], - I: function (d) { var I=d.getHours()%12; return xPad(I===0?12:I, 0); }, - j: function (d) { - var gmd_1 = new Date('' + d.getFullYear() + '/1/1 GMT'); - var gmdate = new Date('' + d.getFullYear() + '/' + (d.getMonth()+1) + '/' + d.getDate() + ' GMT'); - var ms = gmdate - gmd_1; - var doy = parseInt(ms/60000/60/24, 10)+1; - return xPad(doy, 0, 100); - }, - k: ['getHours', ' '], - l: function (d) { var I=d.getHours()%12; return xPad(I===0?12:I, ' '); }, - m: function (d) { return xPad(d.getMonth()+1, 0); }, - M: ['getMinutes', '0'], - p: function (d, l) { return l.p[d.getHours() >= 12 ? 1 : 0 ]; }, - P: function (d, l) { return l.P[d.getHours() >= 12 ? 1 : 0 ]; }, - s: function (d, l) { return parseInt(d.getTime()/1000, 10); }, - S: ['getSeconds', '0'], - u: function (d) { var dow = d.getDay(); return dow===0?7:dow; }, - U: function (d) { - var doy = parseInt(Dt.formats.j(d), 10); - var rdow = 6-d.getDay(); - var woy = parseInt((doy+rdow)/7, 10); - return xPad(woy, 0); - }, - V: function (d) { - var woy = parseInt(Dt.formats.W(d), 10); - var dow1_1 = (new Date('' + d.getFullYear() + '/1/1')).getDay(); - // First week is 01 and not 00 as in the case of %U and %W, - // so we add 1 to the final result except if day 1 of the year - // is a Monday (then %W returns 01). - // We also need to subtract 1 if the day 1 of the year is - // Friday-Sunday, so the resulting equation becomes: - var idow = woy + (dow1_1 > 4 || dow1_1 <= 1 ? 0 : 1); - if(idow === 53 && (new Date('' + d.getFullYear() + '/12/31')).getDay() < 4) - { - idow = 1; - } - else if(idow === 0) - { - idow = Dt.formats.V(new Date('' + (d.getFullYear()-1) + '/12/31')); - } - - return xPad(idow, 0); - }, - w: 'getDay', - W: function (d) { - var doy = parseInt(Dt.formats.j(d), 10); - var rdow = 7-Dt.formats.u(d); - var woy = parseInt((doy+rdow)/7, 10); - return xPad(woy, 0, 10); - }, - y: function (d) { return xPad(d.getFullYear()%100, 0); }, - Y: 'getFullYear', - z: function (d) { - var o = d.getTimezoneOffset(); - var H = xPad(parseInt(Math.abs(o/60), 10), 0); - var M = xPad(Math.abs(o%60), 0); - return (o>0?'-':'+') + H + M; - }, - Z: function (d) { - var tz = d.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/, '$2').replace(/[a-z ]/g, ''); - if(tz.length > 4) { - tz = Dt.formats.z(d); - } - return tz; - }, - '%': function (d) { return '%'; } - }, - - aggregates: { - c: 'locale', - D: '%m/%d/%y', - F: '%Y-%m-%d', - h: '%b', - n: '\n', - r: 'locale', - R: '%H:%M', - t: '\t', - T: '%H:%M:%S', - x: 'locale', - X: 'locale' - //'+': '%a %b %e %T %Z %Y' - }, - - /** - * Takes a native JavaScript Date and formats to string for display to user. - * - * @method format - * @param oDate {Date} Date. - * @param oConfig {Object} (Optional) Object literal of configuration values: - *
    - *
    format <String>
    - *
    - *

    - * Any strftime string is supported, such as "%I:%M:%S %p". strftime has several format specifiers defined by the Open group at - * http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html - *

    - *

    - * PHP added a few of its own, defined at http://www.php.net/strftime - *

    - *

    - * This javascript implementation supports all the PHP specifiers and a few more. The full list is below: - *

    - *
    - *
    %a
    abbreviated weekday name according to the current locale
    - *
    %A
    full weekday name according to the current locale
    - *
    %b
    abbreviated month name according to the current locale
    - *
    %B
    full month name according to the current locale
    - *
    %c
    preferred date and time representation for the current locale
    - *
    %C
    century number (the year divided by 100 and truncated to an integer, range 00 to 99)
    - *
    %d
    day of the month as a decimal number (range 01 to 31)
    - *
    %D
    same as %m/%d/%y
    - *
    %e
    day of the month as a decimal number, a single digit is preceded by a space (range ' 1' to '31')
    - *
    %F
    same as %Y-%m-%d (ISO 8601 date format)
    - *
    %g
    like %G, but without the century
    - *
    %G
    The 4-digit year corresponding to the ISO week number
    - *
    %h
    same as %b
    - *
    %H
    hour as a decimal number using a 24-hour clock (range 00 to 23)
    - *
    %I
    hour as a decimal number using a 12-hour clock (range 01 to 12)
    - *
    %j
    day of the year as a decimal number (range 001 to 366)
    - *
    %k
    hour as a decimal number using a 24-hour clock (range 0 to 23); single digits are preceded by a blank. (See also %H.)
    - *
    %l
    hour as a decimal number using a 12-hour clock (range 1 to 12); single digits are preceded by a blank. (See also %I.)
    - *
    %m
    month as a decimal number (range 01 to 12)
    - *
    %M
    minute as a decimal number
    - *
    %n
    newline character
    - *
    %p
    either `AM' or `PM' according to the given time value, or the corresponding strings for the current locale
    - *
    %P
    like %p, but lower case
    - *
    %r
    time in a.m. and p.m. notation equal to %I:%M:%S %p
    - *
    %R
    time in 24 hour notation equal to %H:%M
    - *
    %s
    number of seconds since the Epoch, ie, since 1970-01-01 00:00:00 UTC
    - *
    %S
    second as a decimal number
    - *
    %t
    tab character
    - *
    %T
    current time, equal to %H:%M:%S
    - *
    %u
    weekday as a decimal number [1,7], with 1 representing Monday
    - *
    %U
    week number of the current year as a decimal number, starting with the - * first Sunday as the first day of the first week
    - *
    %V
    The ISO 8601:1988 week number of the current year as a decimal number, - * range 01 to 53, where week 1 is the first week that has at least 4 days - * in the current year, and with Monday as the first day of the week.
    - *
    %w
    day of the week as a decimal, Sunday being 0
    - *
    %W
    week number of the current year as a decimal number, starting with the - * first Monday as the first day of the first week
    - *
    %x
    preferred date representation for the current locale without the time
    - *
    %X
    preferred time representation for the current locale without the date
    - *
    %y
    year as a decimal number without a century (range 00 to 99)
    - *
    %Y
    year as a decimal number including the century
    - *
    %z
    numerical time zone representation
    - *
    %Z
    time zone name or abbreviation
    - *
    %%
    a literal `%' character
    - *
    - *
    - *
    - * @param sLocale {String} (Optional) The locale to use when displaying days of week, - * months of the year, and other locale specific strings. The following locales are - * built in: - *
    - *
    en
    - *
    English
    - *
    en-US
    - *
    US English
    - *
    en-GB
    - *
    British English
    - *
    en-AU
    - *
    Australian English (identical to British English)
    - *
    - * More locales may be added by subclassing of YAHOO.util.DateLocale. - * See YAHOO.util.DateLocale for more information. - * @return {String} Formatted date for display. - * @sa YAHOO.util.DateLocale - */ - format : function (oDate, oConfig, sLocale) { - oConfig = oConfig || {}; - - if(!(oDate instanceof Date)) { - return YAHOO.lang.isValue(oDate) ? oDate : ""; - } - - var format = oConfig.format || "%m/%d/%Y"; - - // Be backwards compatible, support strings that are - // exactly equal to YYYY/MM/DD, DD/MM/YYYY and MM/DD/YYYY - if(format === 'YYYY/MM/DD') { - format = '%Y/%m/%d'; - } else if(format === 'DD/MM/YYYY') { - format = '%d/%m/%Y'; - } else if(format === 'MM/DD/YYYY') { - format = '%m/%d/%Y'; - } - // end backwards compatibility block - - sLocale = sLocale || "en"; - - // Make sure we have a definition for the requested locale, or default to en. - if(!(sLocale in YAHOO.util.DateLocale)) { - if(sLocale.replace(/-[a-zA-Z]+$/, '') in YAHOO.util.DateLocale) { - sLocale = sLocale.replace(/-[a-zA-Z]+$/, ''); - } else { - sLocale = "en"; - } - } - - var aLocale = YAHOO.util.DateLocale[sLocale]; - - var replace_aggs = function (m0, m1) { - var f = Dt.aggregates[m1]; - return (f === 'locale' ? aLocale[m1] : f); - }; - - var replace_formats = function (m0, m1) { - var f = Dt.formats[m1]; - if(typeof f === 'string') { // string => built in date function - return oDate[f](); - } else if(typeof f === 'function') { // function => our own function - return f.call(oDate, oDate, aLocale); - } else if(typeof f === 'object' && typeof f[0] === 'string') { // built in function with padding - return xPad(oDate[f[0]](), f[1]); - } else { - return m1; - } - }; - - // First replace aggregates (run in a loop because an agg may be made up of other aggs) - while(format.match(/%[cDFhnrRtTxX]/)) { - format = format.replace(/%([cDFhnrRtTxX])/g, replace_aggs); - } - - // Now replace formats (do not run in a loop otherwise %%a will be replace with the value of %a) - var str = format.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g, replace_formats); - - replace_aggs = replace_formats = undefined; - - return str; - } - }; - - YAHOO.namespace("YAHOO.util"); - YAHOO.util.Date = Dt; - -/** - * The DateLocale class is a container and base class for all - * localised date strings used by YAHOO.util.Date. It is used - * internally, but may be extended to provide new date localisations. - * - * To create your own DateLocale, follow these steps: - *
      - *
    1. Find an existing locale that matches closely with your needs
    2. - *
    3. Use this as your base class. Use YAHOO.util.DateLocale if nothing - * matches.
    4. - *
    5. Create your own class as an extension of the base class using - * YAHOO.lang.merge, and add your own localisations where needed.
    6. - *
    - * See the YAHOO.util.DateLocale['en-US'] and YAHOO.util.DateLocale['en-GB'] - * classes which extend YAHOO.util.DateLocale['en']. - * - * For example, to implement locales for French french and Canadian french, - * we would do the following: - *
      - *
    1. For French french, we have no existing similar locale, so use - * YAHOO.util.DateLocale as the base, and extend it: - *
      - *      YAHOO.util.DateLocale['fr'] = YAHOO.lang.merge(YAHOO.util.DateLocale, {
      - *          a: ['dim', 'lun', 'mar', 'mer', 'jeu', 'ven', 'sam'],
      - *          A: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
      - *          b: ['jan', 'fév', 'mar', 'avr', 'mai', 'jun', 'jui', 'aoû', 'sep', 'oct', 'nov', 'déc'],
      - *          B: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],
      - *          c: '%a %d %b %Y %T %Z',
      - *          p: ['', ''],
      - *          P: ['', ''],
      - *          x: '%d.%m.%Y',
      - *          X: '%T'
      - *      });
      - *   
      - *
    2. - *
    3. For Canadian french, we start with French french and change the meaning of \%x: - *
      - *      YAHOO.util.DateLocale['fr-CA'] = YAHOO.lang.merge(YAHOO.util.DateLocale['fr'], {
      - *          x: '%Y-%m-%d'
      - *      });
      - *   
      - *
    4. - *
    - * - * With that, you can use your new locales: - *
    - *    var d = new Date("2008/04/22");
    - *    YAHOO.util.Date.format(d, {format: "%A, %d %B == %x"}, "fr");
    - * 
    - * will return: - *
    - *    mardi, 22 avril == 22.04.2008
    - * 
    - * And - *
    - *    YAHOO.util.Date.format(d, {format: "%A, %d %B == %x"}, "fr-CA");
    - * 
    - * Will return: - *
    - *   mardi, 22 avril == 2008-04-22
    - * 
    - * @namespace YAHOO.util - * @requires yahoo - * @class DateLocale - */ - YAHOO.util.DateLocale = { - a: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], - A: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], - b: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - B: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], - c: '%a %d %b %Y %T %Z', - p: ['AM', 'PM'], - P: ['am', 'pm'], - r: '%I:%M:%S %p', - x: '%d/%m/%y', - X: '%T' - }; - - YAHOO.util.DateLocale['en'] = YAHOO.lang.merge(YAHOO.util.DateLocale, {}); - - YAHOO.util.DateLocale['en-US'] = YAHOO.lang.merge(YAHOO.util.DateLocale['en'], { - c: '%a %d %b %Y %I:%M:%S %p %Z', - x: '%m/%d/%Y', - X: '%I:%M:%S %p' - }); - - YAHOO.util.DateLocale['en-GB'] = YAHOO.lang.merge(YAHOO.util.DateLocale['en'], { - r: '%l:%M:%S %P %Z' - }); - YAHOO.util.DateLocale['en-AU'] = YAHOO.lang.merge(YAHOO.util.DateLocale['en']); - -})(); - -YAHOO.register("datasource", YAHOO.util.DataSource, {version: "2.8.0r4", build: "2449"}); diff --git a/koha-tmpl/intranet-tmpl/prog/en/lib/yui/datasource/datasource-min.js b/koha-tmpl/intranet-tmpl/prog/en/lib/yui/datasource/datasource-min.js deleted file mode 100644 index 0be5a00..0000000 --- a/koha-tmpl/intranet-tmpl/prog/en/lib/yui/datasource/datasource-min.js +++ /dev/null @@ -1,12 +0,0 @@ -/* -Copyright (c) 2009, Yahoo! Inc. All rights reserved. -Code licensed under the BSD License: -http://developer.yahoo.net/yui/license.txt -version: 2.8.0r4 -*/ -(function(){var lang=YAHOO.lang,util=YAHOO.util,Ev=util.Event;util.DataSourceBase=function(oLiveData,oConfigs){if(oLiveData===null||oLiveData===undefined){return;}this.liveData=oLiveData;this._oQueue={interval:null,conn:null,requests:[]};this.responseSchema={};if(oConfigs&&(oConfigs.constructor==Object)){for(var sConfig in oConfigs){if(sConfig){this[sConfig]=oConfigs[sConfig];}}}var maxCacheEntries=this.maxCacheEntries;if(!lang.isNumber(maxCacheEntries)||(maxCacheEntries<0)){maxCacheEntries=0;}this._aIntervals=[];this.createEvent("cacheRequestEvent");this.createEvent("cacheResponseEvent");this.createEvent("requestEvent");this.createEvent("responseEvent");this.createEvent("responseParseEvent");this.createEvent("responseCacheEvent");this.createEvent("dataErrorEvent");this.createEvent("cacheFlushEvent");var DS=util.DataSourceBase;this._sName="DataSource instance"+DS._nIndex;DS._nIndex++;};var DS=util.DataSourceBase;lang.augmentObject(DS,{TYPE_UNKNOWN:-1,TYPE_JSARRAY:0,TYPE_JSFUNCTION:1,TYPE_XHR:2,TYPE_JSON:3,TYPE_XML:4,TYPE_TEXT:5,TYPE_HTMLTABLE:6,TYPE_SCRIPTNODE:7,TYPE_LOCAL:8,ERROR_DATAINVALID:"Invalid data",ERROR_DATANULL:"Null data",_nIndex:0,_nTransactionId:0,_getLocationValue:function(field,context){var locator=field.locator||field.key||field,xmldoc=context.ownerDocument||context,result,res,value=null;try{if(!lang.isUndefined(xmldoc.evaluate)){result=xmldoc.evaluate(locator,context,xmldoc.createNSResolver(!context.ownerDocument?context.documentElement:context.ownerDocument.documentElement),0,null);while(res=result.iterateNext()){value=res.textContent;}}else{xmldoc.setProperty("SelectionLanguage","XPath");result=context.selectNodes(locator)[0];value=result.value||result.text||null;}return value;}catch(e){}},issueCallback:function(callback,params,error,scope){if(lang.isFunction(callback)){callback.apply(scope,params);}else{if(lang.isObject(callback)){scope=callback.scope||scope||window;var callbackFunc=callback.success;if(error){callbackFunc=callback.failure;}if(callbackFunc){callbackFunc.apply(scope,params.concat([callback.argument]));}}}},parseString:function(oData){if(!lang.isValue(oData)){return null;}var string=oData+"";if(lang.isString(string)){return string;}else{return null;}},parseNumber:function(oData){if(!lang.isValue(oData)||(oData==="")){return null;}var number=oData*1;if(lang.isNumber(number)){return number;}else{return null;}},convertNumber:function(oData){return DS.parseNumber(oData);},parseDate:function(oData){var date=null;if(!(oData instanceof Date)){date=new Date(oData);}else{return oData;}if(date instanceof Date){return date;}else{return null;}},convertDate:function(oData){return DS.parseDate(oData);}});DS.Parser={string:DS.parseString,number:DS.parseNumber,date:DS.parseDate};DS.prototype={_sName:null,_aCache:null,_oQueue:null,_aIntervals:null,maxCacheEntries:0,liveData:null,dataType:DS.TYPE_UNKNOWN,responseType:DS.TYPE_UNKNOWN,responseSchema:null,useXPath:false,toString:function(){return this._sName;},getCachedResponse:function(oRequest,oCallback,oCaller){var aCache=this._aCache;if(this.maxCacheEntries>0){if(!aCache){this._aCache=[];}else{var nCacheLength=aCache.length;if(nCacheLength>0){var oResponse=null;this.fireEvent("cacheRequestEvent",{request:oRequest,callback:oCallback,caller:oCaller});for(var i=nCacheLength-1;i>=0;i--){var oCacheElem=aCache[i];if(this.isCacheHit(oRequest,oCacheElem.request)){oResponse=oCacheElem.response;this.fireEvent("cacheResponseEvent",{request:oRequest,response:oResponse,callback:oCallback,caller:oCaller});if(i=this.maxCacheEntries){aCache.shift();}var oCacheElem={request:oRequest,response:oResponse};aCache[aCache.length]=oCacheElem;this.fireEvent("responseCacheEvent",{request:oRequest,response:oResponse});},flushCache:function(){if(this._aCache){this._aCache=[];this.fireEvent("cacheFlushEvent");}},setInterval:function(nMsec,oRequest,oCallback,oCaller){if(lang.isNumber(nMsec)&&(nMsec>=0)){var oSelf=this;var nId=setInterval(function(){oSelf.makeConnection(oRequest,oCallback,oCaller);},nMsec);this._aIntervals.push(nId);return nId;}else{}},clearInterval:function(nId){var tracker=this._aIntervals||[];for(var i=tracker.length-1;i>-1;i--){if(tracker[i]===nId){tracker.splice(i,1);clearInterval(nId);}}},clearAllIntervals:function(){var tracker=this._aIntervals||[];for(var i=tracker.length-1;i>-1;i--){clearInterval(tracker[i]);}tracker=[];},sendRequest:function(oRequest,oCallback,oCaller){var oCachedResponse=this.getCachedResponse(oRequest,oCallback,oCaller);if(oCachedResponse){DS.issueCallback(oCallback,[oRequest,oCachedResponse],false,oCaller);return null;}return this.makeConnection(oRequest,oCallback,oCaller);},makeConnection:function(oRequest,oCallback,oCaller){var tId=DS._nTransactionId++;this.fireEvent("requestEvent",{tId:tId,request:oRequest,callback:oCallback,caller:oCaller});var oRawResponse=this.liveData;this.handleResponse(oRequest,oRawResponse,oCallback,oCaller,tId);return tId;},handleResponse:function(oRequest,oRawResponse,oCallback,oCaller,tId){this.fireEvent("responseEvent",{tId:tId,request:oRequest,response:oRawResponse,callback:oCallback,caller:oCaller});var xhr=(this.dataType==DS.TYPE_XHR)?true:false;var oParsedResponse=null;var oFullResponse=oRawResponse;if(this.responseType===DS.TYPE_UNKNOWN){var ctype=(oRawResponse&&oRawResponse.getResponseHeader)?oRawResponse.getResponseHeader["Content-Type"]:null;if(ctype){if(ctype.indexOf("text/xml")>-1){this.responseType=DS.TYPE_XML;}else{if(ctype.indexOf("application/json")>-1){this.responseType=DS.TYPE_JSON;}else{if(ctype.indexOf("text/plain")>-1){this.responseType=DS.TYPE_TEXT;}}}}else{if(YAHOO.lang.isArray(oRawResponse)){this.responseType=DS.TYPE_JSARRAY; -}else{if(oRawResponse&&oRawResponse.nodeType&&(oRawResponse.nodeType===9||oRawResponse.nodeType===1||oRawResponse.nodeType===11)){this.responseType=DS.TYPE_XML;}else{if(oRawResponse&&oRawResponse.nodeName&&(oRawResponse.nodeName.toLowerCase()=="table")){this.responseType=DS.TYPE_HTMLTABLE;}else{if(YAHOO.lang.isObject(oRawResponse)){this.responseType=DS.TYPE_JSON;}else{if(YAHOO.lang.isString(oRawResponse)){this.responseType=DS.TYPE_TEXT;}}}}}}}switch(this.responseType){case DS.TYPE_JSARRAY:if(xhr&&oRawResponse&&oRawResponse.responseText){oFullResponse=oRawResponse.responseText;}try{if(lang.isString(oFullResponse)){var parseArgs=[oFullResponse].concat(this.parseJSONArgs);if(lang.JSON){oFullResponse=lang.JSON.parse.apply(lang.JSON,parseArgs);}else{if(window.JSON&&JSON.parse){oFullResponse=JSON.parse.apply(JSON,parseArgs);}else{if(oFullResponse.parseJSON){oFullResponse=oFullResponse.parseJSON.apply(oFullResponse,parseArgs.slice(1));}else{while(oFullResponse.length>0&&(oFullResponse.charAt(0)!="{")&&(oFullResponse.charAt(0)!="[")){oFullResponse=oFullResponse.substring(1,oFullResponse.length);}if(oFullResponse.length>0){var arrayEnd=Math.max(oFullResponse.lastIndexOf("]"),oFullResponse.lastIndexOf("}"));oFullResponse=oFullResponse.substring(0,arrayEnd+1);oFullResponse=eval("("+oFullResponse+")");}}}}}}catch(e1){}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseArrayData(oRequest,oFullResponse);break;case DS.TYPE_JSON:if(xhr&&oRawResponse&&oRawResponse.responseText){oFullResponse=oRawResponse.responseText;}try{if(lang.isString(oFullResponse)){var parseArgs=[oFullResponse].concat(this.parseJSONArgs);if(lang.JSON){oFullResponse=lang.JSON.parse.apply(lang.JSON,parseArgs);}else{if(window.JSON&&JSON.parse){oFullResponse=JSON.parse.apply(JSON,parseArgs);}else{if(oFullResponse.parseJSON){oFullResponse=oFullResponse.parseJSON.apply(oFullResponse,parseArgs.slice(1));}else{while(oFullResponse.length>0&&(oFullResponse.charAt(0)!="{")&&(oFullResponse.charAt(0)!="[")){oFullResponse=oFullResponse.substring(1,oFullResponse.length);}if(oFullResponse.length>0){var objEnd=Math.max(oFullResponse.lastIndexOf("]"),oFullResponse.lastIndexOf("}"));oFullResponse=oFullResponse.substring(0,objEnd+1);oFullResponse=eval("("+oFullResponse+")");}}}}}}catch(e){}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseJSONData(oRequest,oFullResponse);break;case DS.TYPE_HTMLTABLE:if(xhr&&oRawResponse.responseText){var el=document.createElement("div");el.innerHTML=oRawResponse.responseText;oFullResponse=el.getElementsByTagName("table")[0];}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseHTMLTableData(oRequest,oFullResponse);break;case DS.TYPE_XML:if(xhr&&oRawResponse.responseXML){oFullResponse=oRawResponse.responseXML;}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseXMLData(oRequest,oFullResponse);break;case DS.TYPE_TEXT:if(xhr&&lang.isString(oRawResponse.responseText)){oFullResponse=oRawResponse.responseText;}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseTextData(oRequest,oFullResponse);break;default:oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseData(oRequest,oFullResponse);break;}oParsedResponse=oParsedResponse||{};if(!oParsedResponse.results){oParsedResponse.results=[];}if(!oParsedResponse.meta){oParsedResponse.meta={};}if(!oParsedResponse.error){oParsedResponse=this.doBeforeCallback(oRequest,oFullResponse,oParsedResponse,oCallback);this.fireEvent("responseParseEvent",{request:oRequest,response:oParsedResponse,callback:oCallback,caller:oCaller});this.addToCache(oRequest,oParsedResponse);}else{oParsedResponse.error=true;this.fireEvent("dataErrorEvent",{request:oRequest,response:oRawResponse,callback:oCallback,caller:oCaller,message:DS.ERROR_DATANULL});}oParsedResponse.tId=tId;DS.issueCallback(oCallback,[oRequest,oParsedResponse],oParsedResponse.error,oCaller);},doBeforeParseData:function(oRequest,oFullResponse,oCallback){return oFullResponse;},doBeforeCallback:function(oRequest,oFullResponse,oParsedResponse,oCallback){return oParsedResponse;},parseData:function(oRequest,oFullResponse){if(lang.isValue(oFullResponse)){var oParsedResponse={results:oFullResponse,meta:{}};return oParsedResponse;}return null;},parseArrayData:function(oRequest,oFullResponse){if(lang.isArray(oFullResponse)){var results=[],i,j,rec,field,data;if(lang.isArray(this.responseSchema.fields)){var fields=this.responseSchema.fields;for(i=fields.length-1;i>=0;--i){if(typeof fields[i]!=="object"){fields[i]={key:fields[i]};}}var parsers={},p;for(i=fields.length-1;i>=0;--i){p=(typeof fields[i].parser==="function"?fields[i].parser:DS.Parser[fields[i].parser+""])||fields[i].converter;if(p){parsers[fields[i].key]=p;}}var arrType=lang.isArray(oFullResponse[0]);for(i=oFullResponse.length-1;i>-1;i--){var oResult={};rec=oFullResponse[i];if(typeof rec==="object"){for(j=fields.length-1;j>-1;j--){field=fields[j];data=arrType?rec[j]:rec[field.key];if(parsers[field.key]){data=parsers[field.key].call(this,data);}if(data===undefined){data=null;}oResult[field.key]=data;}}else{if(lang.isString(rec)){for(j=fields.length-1;j>-1;j--){field=fields[j];data=rec;if(parsers[field.key]){data=parsers[field.key].call(this,data);}if(data===undefined){data=null;}oResult[field.key]=data;}}}results[i]=oResult;}}else{results=oFullResponse;}var oParsedResponse={results:results};return oParsedResponse;}return null;},parseTextData:function(oRequest,oFullResponse){if(lang.isString(oFullResponse)){if(lang.isString(this.responseSchema.recordDelim)&&lang.isString(this.responseSchema.fieldDelim)){var oParsedResponse={results:[]};var recDelim=this.responseSchema.recordDelim;var fieldDelim=this.responseSchema.fieldDelim;if(oFullResponse.length>0){var newLength=oFullResponse.length-recDelim.length;if(oFullResponse.substr(newLength)==recDelim){oFullResponse=oFullResponse.substr(0,newLength); -}if(oFullResponse.length>0){var recordsarray=oFullResponse.split(recDelim);for(var i=0,len=recordsarray.length,recIdx=0;i0)){var fielddataarray=recordsarray[i].split(fieldDelim);var oResult={};if(lang.isArray(this.responseSchema.fields)){var fields=this.responseSchema.fields;for(var j=fields.length-1;j>-1;j--){try{var data=fielddataarray[j];if(lang.isString(data)){if(data.charAt(0)=='"'){data=data.substr(1);}if(data.charAt(data.length-1)=='"'){data=data.substr(0,data.length-1);}var field=fields[j];var key=(lang.isValue(field.key))?field.key:field;if(!field.parser&&field.converter){field.parser=field.converter;}var parser=(typeof field.parser==="function")?field.parser:DS.Parser[field.parser+""];if(parser){data=parser.call(this,data);}if(data===undefined){data=null;}oResult[key]=data;}else{bError=true;}}catch(e){bError=true;}}}else{oResult=fielddataarray;}if(!bError){oParsedResponse.results[recIdx++]=oResult;}}}}}return oParsedResponse;}}return null;},parseXMLResult:function(result){var oResult={},schema=this.responseSchema;try{for(var m=schema.fields.length-1;m>=0;m--){var field=schema.fields[m];var key=(lang.isValue(field.key))?field.key:field;var data=null;if(this.useXPath){data=YAHOO.util.DataSource._getLocationValue(field,result);}else{var xmlAttr=result.attributes.getNamedItem(key);if(xmlAttr){data=xmlAttr.value;}else{var xmlNode=result.getElementsByTagName(key);if(xmlNode&&xmlNode.item(0)){var item=xmlNode.item(0);data=(item)?((item.text)?item.text:(item.textContent)?item.textContent:null):null;if(!data){var datapieces=[];for(var j=0,len=item.childNodes.length;j0){data=datapieces.join("");}}}}}if(data===null){data="";}if(!field.parser&&field.converter){field.parser=field.converter;}var parser=(typeof field.parser==="function")?field.parser:DS.Parser[field.parser+""];if(parser){data=parser.call(this,data);}if(data===undefined){data=null;}oResult[key]=data;}}catch(e){}return oResult;},parseXMLData:function(oRequest,oFullResponse){var bError=false,schema=this.responseSchema,oParsedResponse={meta:{}},xmlList=null,metaNode=schema.metaNode,metaLocators=schema.metaFields||{},i,k,loc,v;try{if(this.useXPath){for(k in metaLocators){oParsedResponse.meta[k]=YAHOO.util.DataSource._getLocationValue(metaLocators[k],oFullResponse);}}else{metaNode=metaNode?oFullResponse.getElementsByTagName(metaNode)[0]:oFullResponse;if(metaNode){for(k in metaLocators){if(lang.hasOwnProperty(metaLocators,k)){loc=metaLocators[k];v=metaNode.getElementsByTagName(loc)[0];if(v){v=v.firstChild.nodeValue;}else{v=metaNode.attributes.getNamedItem(loc);if(v){v=v.value;}}if(lang.isValue(v)){oParsedResponse.meta[k]=v;}}}}}xmlList=(schema.resultNode)?oFullResponse.getElementsByTagName(schema.resultNode):null;}catch(e){}if(!xmlList||!lang.isArray(schema.fields)){bError=true;}else{oParsedResponse.results=[];for(i=xmlList.length-1;i>=0;--i){var oResult=this.parseXMLResult(xmlList.item(i));oParsedResponse.results[i]=oResult;}}if(bError){oParsedResponse.error=true;}else{}return oParsedResponse;},parseJSONData:function(oRequest,oFullResponse){var oParsedResponse={results:[],meta:{}};if(lang.isObject(oFullResponse)&&this.responseSchema.resultsList){var schema=this.responseSchema,fields=schema.fields,resultsList=oFullResponse,results=[],metaFields=schema.metaFields||{},fieldParsers=[],fieldPaths=[],simpleFields=[],bError=false,i,len,j,v,key,parser,path;var buildPath=function(needle){var path=null,keys=[],i=0;if(needle){needle=needle.replace(/\[(['"])(.*?)\1\]/g,function(x,$1,$2){keys[i]=$2;return".@"+(i++);}).replace(/\[(\d+)\]/g,function(x,$1){keys[i]=parseInt($1,10)|0;return".@"+(i++);}).replace(/^\./,"");if(!/[^\w\.\$@]/.test(needle)){path=needle.split(".");for(i=path.length-1;i>=0;--i){if(path[i].charAt(0)==="@"){path[i]=keys[parseInt(path[i].substr(1),10)];}}}else{}}return path;};var walkPath=function(path,origin){var v=origin,i=0,len=path.length;for(;i1){fieldPaths[fieldPaths.length]={key:key,path:path};}else{simpleFields[simpleFields.length]={key:key,path:path[0]};}}else{}}for(i=resultsList.length-1;i>=0;--i){var r=resultsList[i],rec={};if(r){for(j=simpleFields.length-1;j>=0;--j){rec[simpleFields[j].key]=(r[simpleFields[j].path]!==undefined)?r[simpleFields[j].path]:r[j];}for(j=fieldPaths.length-1;j>=0;--j){rec[fieldPaths[j].key]=walkPath(fieldPaths[j].path,r);}for(j=fieldParsers.length-1;j>=0;--j){var p=fieldParsers[j].key;rec[p]=fieldParsers[j].parser(rec[p]);if(rec[p]===undefined){rec[p]=null;}}}results[i]=rec;}}else{results=resultsList;}for(key in metaFields){if(lang.hasOwnProperty(metaFields,key)){path=buildPath(metaFields[key]);if(path){v=walkPath(path,oFullResponse);oParsedResponse.meta[key]=v;}}}}else{oParsedResponse.error=true;}oParsedResponse.results=results;}else{oParsedResponse.error=true;}return oParsedResponse;},parseHTMLTableData:function(oRequest,oFullResponse){var bError=false;var elTable=oFullResponse;var fields=this.responseSchema.fields;var oParsedResponse={results:[]};if(lang.isArray(fields)){for(var i=0;i-1;j--){var elRow=elTbody.rows[j];var oResult={};for(var k=fields.length-1;k>-1;k--){var field=fields[k];var key=(lang.isValue(field.key))?field.key:field; -var data=elRow.cells[k].innerHTML;if(!field.parser&&field.converter){field.parser=field.converter;}var parser=(typeof field.parser==="function")?field.parser:DS.Parser[field.parser+""];if(parser){data=parser.call(this,data);}if(data===undefined){data=null;}oResult[key]=data;}oParsedResponse.results[j]=oResult;}}}else{bError=true;}if(bError){oParsedResponse.error=true;}else{}return oParsedResponse;}};lang.augmentProto(DS,util.EventProvider);util.LocalDataSource=function(oLiveData,oConfigs){this.dataType=DS.TYPE_LOCAL;if(oLiveData){if(YAHOO.lang.isArray(oLiveData)){this.responseType=DS.TYPE_JSARRAY;}else{if(oLiveData.nodeType&&oLiveData.nodeType==9){this.responseType=DS.TYPE_XML;}else{if(oLiveData.nodeName&&(oLiveData.nodeName.toLowerCase()=="table")){this.responseType=DS.TYPE_HTMLTABLE;oLiveData=oLiveData.cloneNode(true);}else{if(YAHOO.lang.isString(oLiveData)){this.responseType=DS.TYPE_TEXT;}else{if(YAHOO.lang.isObject(oLiveData)){this.responseType=DS.TYPE_JSON;}}}}}}else{oLiveData=[];this.responseType=DS.TYPE_JSARRAY;}util.LocalDataSource.superclass.constructor.call(this,oLiveData,oConfigs);};lang.extend(util.LocalDataSource,DS);lang.augmentObject(util.LocalDataSource,DS);util.FunctionDataSource=function(oLiveData,oConfigs){this.dataType=DS.TYPE_JSFUNCTION;oLiveData=oLiveData||function(){};util.FunctionDataSource.superclass.constructor.call(this,oLiveData,oConfigs);};lang.extend(util.FunctionDataSource,DS,{scope:null,makeConnection:function(oRequest,oCallback,oCaller){var tId=DS._nTransactionId++;this.fireEvent("requestEvent",{tId:tId,request:oRequest,callback:oCallback,caller:oCaller});var oRawResponse=(this.scope)?this.liveData.call(this.scope,oRequest,this):this.liveData(oRequest);if(this.responseType===DS.TYPE_UNKNOWN){if(YAHOO.lang.isArray(oRawResponse)){this.responseType=DS.TYPE_JSARRAY;}else{if(oRawResponse&&oRawResponse.nodeType&&oRawResponse.nodeType==9){this.responseType=DS.TYPE_XML;}else{if(oRawResponse&&oRawResponse.nodeName&&(oRawResponse.nodeName.toLowerCase()=="table")){this.responseType=DS.TYPE_HTMLTABLE;}else{if(YAHOO.lang.isObject(oRawResponse)){this.responseType=DS.TYPE_JSON;}else{if(YAHOO.lang.isString(oRawResponse)){this.responseType=DS.TYPE_TEXT;}}}}}}this.handleResponse(oRequest,oRawResponse,oCallback,oCaller,tId);return tId;}});lang.augmentObject(util.FunctionDataSource,DS);util.ScriptNodeDataSource=function(oLiveData,oConfigs){this.dataType=DS.TYPE_SCRIPTNODE;oLiveData=oLiveData||"";util.ScriptNodeDataSource.superclass.constructor.call(this,oLiveData,oConfigs);};lang.extend(util.ScriptNodeDataSource,DS,{getUtility:util.Get,asyncMode:"allowAll",scriptCallbackParam:"callback",generateRequestCallback:function(id){return"&"+this.scriptCallbackParam+"=YAHOO.util.ScriptNodeDataSource.callbacks["+id+"]";},doBeforeGetScriptNode:function(sUri){return sUri;},makeConnection:function(oRequest,oCallback,oCaller){var tId=DS._nTransactionId++;this.fireEvent("requestEvent",{tId:tId,request:oRequest,callback:oCallback,caller:oCaller});if(util.ScriptNodeDataSource._nPending===0){util.ScriptNodeDataSource.callbacks=[];util.ScriptNodeDataSource._nId=0;}var id=util.ScriptNodeDataSource._nId;util.ScriptNodeDataSource._nId++;var oSelf=this;util.ScriptNodeDataSource.callbacks[id]=function(oRawResponse){if((oSelf.asyncMode!=="ignoreStaleResponses")||(id===util.ScriptNodeDataSource.callbacks.length-1)){if(oSelf.responseType===DS.TYPE_UNKNOWN){if(YAHOO.lang.isArray(oRawResponse)){oSelf.responseType=DS.TYPE_JSARRAY;}else{if(oRawResponse.nodeType&&oRawResponse.nodeType==9){oSelf.responseType=DS.TYPE_XML;}else{if(oRawResponse.nodeName&&(oRawResponse.nodeName.toLowerCase()=="table")){oSelf.responseType=DS.TYPE_HTMLTABLE;}else{if(YAHOO.lang.isObject(oRawResponse)){oSelf.responseType=DS.TYPE_JSON;}else{if(YAHOO.lang.isString(oRawResponse)){oSelf.responseType=DS.TYPE_TEXT;}}}}}}oSelf.handleResponse(oRequest,oRawResponse,oCallback,oCaller,tId);}else{}delete util.ScriptNodeDataSource.callbacks[id];};util.ScriptNodeDataSource._nPending++;var sUri=this.liveData+oRequest+this.generateRequestCallback(id);sUri=this.doBeforeGetScriptNode(sUri);this.getUtility.script(sUri,{autopurge:true,onsuccess:util.ScriptNodeDataSource._bumpPendingDown,onfail:util.ScriptNodeDataSource._bumpPendingDown});return tId;}});lang.augmentObject(util.ScriptNodeDataSource,DS);lang.augmentObject(util.ScriptNodeDataSource,{_nId:0,_nPending:0,callbacks:[]});util.XHRDataSource=function(oLiveData,oConfigs){this.dataType=DS.TYPE_XHR;this.connMgr=this.connMgr||util.Connect;oLiveData=oLiveData||"";util.XHRDataSource.superclass.constructor.call(this,oLiveData,oConfigs);};lang.extend(util.XHRDataSource,DS,{connMgr:null,connXhrMode:"allowAll",connMethodPost:false,connTimeout:0,makeConnection:function(oRequest,oCallback,oCaller){var oRawResponse=null;var tId=DS._nTransactionId++;this.fireEvent("requestEvent",{tId:tId,request:oRequest,callback:oCallback,caller:oCaller});var oSelf=this;var oConnMgr=this.connMgr;var oQueue=this._oQueue;var _xhrSuccess=function(oResponse){if(oResponse&&(this.connXhrMode=="ignoreStaleResponses")&&(oResponse.tId!=oQueue.conn.tId)){return null;}else{if(!oResponse){this.fireEvent("dataErrorEvent",{request:oRequest,response:null,callback:oCallback,caller:oCaller,message:DS.ERROR_DATANULL});DS.issueCallback(oCallback,[oRequest,{error:true}],true,oCaller);return null;}else{if(this.responseType===DS.TYPE_UNKNOWN){var ctype=(oResponse.getResponseHeader)?oResponse.getResponseHeader["Content-Type"]:null;if(ctype){if(ctype.indexOf("text/xml")>-1){this.responseType=DS.TYPE_XML;}else{if(ctype.indexOf("application/json")>-1){this.responseType=DS.TYPE_JSON;}else{if(ctype.indexOf("text/plain")>-1){this.responseType=DS.TYPE_TEXT;}}}}}this.handleResponse(oRequest,oResponse,oCallback,oCaller,tId);}}};var _xhrFailure=function(oResponse){this.fireEvent("dataErrorEvent",{request:oRequest,response:oResponse,callback:oCallback,caller:oCaller,message:DS.ERROR_DATAINVALID});if(lang.isString(this.liveData)&&lang.isString(oRequest)&&(this.liveData.lastIndexOf("?")!==this.liveData.length-1)&&(oRequest.indexOf("?")!==0)){}oResponse=oResponse||{}; -oResponse.error=true;DS.issueCallback(oCallback,[oRequest,oResponse],true,oCaller);return null;};var _xhrCallback={success:_xhrSuccess,failure:_xhrFailure,scope:this};if(lang.isNumber(this.connTimeout)){_xhrCallback.timeout=this.connTimeout;}if(this.connXhrMode=="cancelStaleRequests"){if(oQueue.conn){if(oConnMgr.abort){oConnMgr.abort(oQueue.conn);oQueue.conn=null;}else{}}}if(oConnMgr&&oConnMgr.asyncRequest){var sLiveData=this.liveData;var isPost=this.connMethodPost;var sMethod=(isPost)?"POST":"GET";var sUri=(isPost||!lang.isValue(oRequest))?sLiveData:sLiveData+oRequest;var sRequest=(isPost)?oRequest:null;if(this.connXhrMode!="queueRequests"){oQueue.conn=oConnMgr.asyncRequest(sMethod,sUri,_xhrCallback,sRequest);}else{if(oQueue.conn){var allRequests=oQueue.requests;allRequests.push({request:oRequest,callback:_xhrCallback});if(!oQueue.interval){oQueue.interval=setInterval(function(){if(oConnMgr.isCallInProgress(oQueue.conn)){return;}else{if(allRequests.length>0){sUri=(isPost||!lang.isValue(allRequests[0].request))?sLiveData:sLiveData+allRequests[0].request;sRequest=(isPost)?allRequests[0].request:null;oQueue.conn=oConnMgr.asyncRequest(sMethod,sUri,allRequests[0].callback,sRequest);allRequests.shift();}else{clearInterval(oQueue.interval);oQueue.interval=null;}}},50);}}else{oQueue.conn=oConnMgr.asyncRequest(sMethod,sUri,_xhrCallback,sRequest);}}}else{DS.issueCallback(oCallback,[oRequest,{error:true}],true,oCaller);}return tId;}});lang.augmentObject(util.XHRDataSource,DS);util.DataSource=function(oLiveData,oConfigs){oConfigs=oConfigs||{};var dataType=oConfigs.dataType;if(dataType){if(dataType==DS.TYPE_LOCAL){lang.augmentObject(util.DataSource,util.LocalDataSource);return new util.LocalDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_XHR){lang.augmentObject(util.DataSource,util.XHRDataSource);return new util.XHRDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_SCRIPTNODE){lang.augmentObject(util.DataSource,util.ScriptNodeDataSource);return new util.ScriptNodeDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_JSFUNCTION){lang.augmentObject(util.DataSource,util.FunctionDataSource);return new util.FunctionDataSource(oLiveData,oConfigs);}}}}}if(YAHOO.lang.isString(oLiveData)){lang.augmentObject(util.DataSource,util.XHRDataSource);return new util.XHRDataSource(oLiveData,oConfigs);}else{if(YAHOO.lang.isFunction(oLiveData)){lang.augmentObject(util.DataSource,util.FunctionDataSource);return new util.FunctionDataSource(oLiveData,oConfigs);}else{lang.augmentObject(util.DataSource,util.LocalDataSource);return new util.LocalDataSource(oLiveData,oConfigs);}}};lang.augmentObject(util.DataSource,DS);})();YAHOO.util.Number={format:function(B,E){if(!isFinite(+B)){return"";}B=!isFinite(+B)?0:+B;E=YAHOO.lang.merge(YAHOO.util.Number.format.defaults,(E||{}));var C=B<0,F=Math.abs(B),A=E.decimalPlaces,I=E.thousandsSeparator,H,G,D;if(A<0){H=F-(F%1)+"";D=H.length+A;if(D>0){H=Number("."+H).toFixed(D).slice(2)+new Array(H.length-D+1).join("0");}else{H="0";}}else{H=F<1&&F>=0.5&&!A?"1":F.toFixed(A);}if(F>1000){G=H.split(/\D/);D=G[0].length%3||3;G[0]=G[0].slice(0,D)+G[0].slice(D).replace(/(\d{3})/g,I+"$1");H=G.join(E.decimalSeparator);}H=E.prefix+H+E.suffix;return C?E.negativeFormat.replace(/#/,H):H;}};YAHOO.util.Number.format.defaults={decimalSeparator:".",decimalPlaces:null,thousandsSeparator:"",prefix:"",suffix:"",negativeFormat:"-#"};(function(){var A=function(C,E,D){if(typeof D==="undefined"){D=10;}for(;parseInt(C,10)1;D/=10){C=E.toString()+C;}return C.toString();};var B={formats:{a:function(D,C){return C.a[D.getDay()];},A:function(D,C){return C.A[D.getDay()];},b:function(D,C){return C.b[D.getMonth()];},B:function(D,C){return C.B[D.getMonth()];},C:function(C){return A(parseInt(C.getFullYear()/100,10),0);},d:["getDate","0"],e:["getDate"," "],g:function(C){return A(parseInt(B.formats.G(C)%100,10),0);},G:function(E){var F=E.getFullYear();var D=parseInt(B.formats.V(E),10);var C=parseInt(B.formats.W(E),10);if(C>D){F++;}else{if(C===0&&D>=52){F--;}}return F;},H:["getHours","0"],I:function(D){var C=D.getHours()%12;return A(C===0?12:C,0);},j:function(G){var F=new Date(""+G.getFullYear()+"/1/1 GMT");var D=new Date(""+G.getFullYear()+"/"+(G.getMonth()+1)+"/"+G.getDate()+" GMT");var C=D-F;var E=parseInt(C/60000/60/24,10)+1;return A(E,0,100);},k:["getHours"," "],l:function(D){var C=D.getHours()%12;return A(C===0?12:C," ");},m:function(C){return A(C.getMonth()+1,0);},M:["getMinutes","0"],p:function(D,C){return C.p[D.getHours()>=12?1:0];},P:function(D,C){return C.P[D.getHours()>=12?1:0];},s:function(D,C){return parseInt(D.getTime()/1000,10);},S:["getSeconds","0"],u:function(C){var D=C.getDay();return D===0?7:D;},U:function(F){var C=parseInt(B.formats.j(F),10);var E=6-F.getDay();var D=parseInt((C+E)/7,10);return A(D,0);},V:function(F){var E=parseInt(B.formats.W(F),10);var C=(new Date(""+F.getFullYear()+"/1/1")).getDay();var D=E+(C>4||C<=1?0:1);if(D===53&&(new Date(""+F.getFullYear()+"/12/31")).getDay()<4){D=1;}else{if(D===0){D=B.formats.V(new Date(""+(F.getFullYear()-1)+"/12/31"));}}return A(D,0);},w:"getDay",W:function(F){var C=parseInt(B.formats.j(F),10);var E=7-B.formats.u(F);var D=parseInt((C+E)/7,10);return A(D,0,10);},y:function(C){return A(C.getFullYear()%100,0);},Y:"getFullYear",z:function(E){var D=E.getTimezoneOffset();var C=A(parseInt(Math.abs(D/60),10),0);var F=A(Math.abs(D%60),0);return(D>0?"-":"+")+C+F;},Z:function(C){var D=C.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/,"$2").replace(/[a-z ]/g,"");if(D.length>4){D=B.formats.z(C);}return D;},"%":function(C){return"%";}},aggregates:{c:"locale",D:"%m/%d/%y",F:"%Y-%m-%d",h:"%b",n:"\n",r:"locale",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"},format:function(G,F,D){F=F||{};if(!(G instanceof Date)){return YAHOO.lang.isValue(G)?G:"";}var H=F.format||"%m/%d/%Y";if(H==="YYYY/MM/DD"){H="%Y/%m/%d";}else{if(H==="DD/MM/YYYY"){H="%d/%m/%Y";}else{if(H==="MM/DD/YYYY"){H="%m/%d/%Y";}}}D=D||"en";if(!(D in YAHOO.util.DateLocale)){if(D.replace(/-[a-zA-Z]+$/,"") in YAHOO.util.DateLocale){D=D.replace(/-[a-zA-Z]+$/,""); -}else{D="en";}}var J=YAHOO.util.DateLocale[D];var C=function(L,K){var M=B.aggregates[K];return(M==="locale"?J[K]:M);};var E=function(L,K){var M=B.formats[K];if(typeof M==="string"){return G[M]();}else{if(typeof M==="function"){return M.call(G,G,J);}else{if(typeof M==="object"&&typeof M[0]==="string"){return A(G[M[0]](),M[1]);}else{return K;}}}};while(H.match(/%[cDFhnrRtTxX]/)){H=H.replace(/%([cDFhnrRtTxX])/g,C);}var I=H.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g,E);C=E=undefined;return I;}};YAHOO.namespace("YAHOO.util");YAHOO.util.Date=B;YAHOO.util.DateLocale={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],r:"%I:%M:%S %p",x:"%d/%m/%y",X:"%T"};YAHOO.util.DateLocale["en"]=YAHOO.lang.merge(YAHOO.util.DateLocale,{});YAHOO.util.DateLocale["en-US"]=YAHOO.lang.merge(YAHOO.util.DateLocale["en"],{c:"%a %d %b %Y %I:%M:%S %p %Z",x:"%m/%d/%Y",X:"%I:%M:%S %p"});YAHOO.util.DateLocale["en-GB"]=YAHOO.lang.merge(YAHOO.util.DateLocale["en"],{r:"%l:%M:%S %P %Z"});YAHOO.util.DateLocale["en-AU"]=YAHOO.lang.merge(YAHOO.util.DateLocale["en"]);})();YAHOO.register("datasource",YAHOO.util.DataSource,{version:"2.8.0r4",build:"2449"}); \ No newline at end of file diff --git a/koha-tmpl/intranet-tmpl/prog/en/lib/yui/datasource/datasource.js b/koha-tmpl/intranet-tmpl/prog/en/lib/yui/datasource/datasource.js deleted file mode 100644 index 92d8155..0000000 --- a/koha-tmpl/intranet-tmpl/prog/en/lib/yui/datasource/datasource.js +++ /dev/null @@ -1,2996 +0,0 @@ -/* -Copyright (c) 2009, Yahoo! Inc. All rights reserved. -Code licensed under the BSD License: -http://developer.yahoo.net/yui/license.txt -version: 2.8.0r4 -*/ -(function () { - -var lang = YAHOO.lang, - util = YAHOO.util, - Ev = util.Event; - -/** - * The DataSource utility provides a common configurable interface for widgets to - * access a variety of data, from JavaScript arrays to online database servers. - * - * @module datasource - * @requires yahoo, event - * @optional json, get, connection - * @title DataSource Utility - */ - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -/** - * Base class for the YUI DataSource utility. - * - * @namespace YAHOO.util - * @class YAHOO.util.DataSourceBase - * @constructor - * @param oLiveData {HTMLElement} Pointer to live data. - * @param oConfigs {object} (optional) Object literal of configuration values. - */ -util.DataSourceBase = function(oLiveData, oConfigs) { - if(oLiveData === null || oLiveData === undefined) { - return; - } - - this.liveData = oLiveData; - this._oQueue = {interval:null, conn:null, requests:[]}; - this.responseSchema = {}; - - // Set any config params passed in to override defaults - if(oConfigs && (oConfigs.constructor == Object)) { - for(var sConfig in oConfigs) { - if(sConfig) { - this[sConfig] = oConfigs[sConfig]; - } - } - } - - // Validate and initialize public configs - var maxCacheEntries = this.maxCacheEntries; - if(!lang.isNumber(maxCacheEntries) || (maxCacheEntries < 0)) { - maxCacheEntries = 0; - } - - // Initialize interval tracker - this._aIntervals = []; - - ///////////////////////////////////////////////////////////////////////////// - // - // Custom Events - // - ///////////////////////////////////////////////////////////////////////////// - - /** - * Fired when a request is made to the local cache. - * - * @event cacheRequestEvent - * @param oArgs.request {Object} The request object. - * @param oArgs.callback {Object} The callback object. - * @param oArgs.caller {Object} (deprecated) Use callback.scope. - */ - this.createEvent("cacheRequestEvent"); - - /** - * Fired when data is retrieved from the local cache. - * - * @event cacheResponseEvent - * @param oArgs.request {Object} The request object. - * @param oArgs.response {Object} The response object. - * @param oArgs.callback {Object} The callback object. - * @param oArgs.caller {Object} (deprecated) Use callback.scope. - */ - this.createEvent("cacheResponseEvent"); - - /** - * Fired when a request is sent to the live data source. - * - * @event requestEvent - * @param oArgs.request {Object} The request object. - * @param oArgs.callback {Object} The callback object. - * @param oArgs.tId {Number} Transaction ID. - * @param oArgs.caller {Object} (deprecated) Use callback.scope. - */ - this.createEvent("requestEvent"); - - /** - * Fired when live data source sends response. - * - * @event responseEvent - * @param oArgs.request {Object} The request object. - * @param oArgs.response {Object} The raw response object. - * @param oArgs.callback {Object} The callback object. - * @param oArgs.tId {Number} Transaction ID. - * @param oArgs.caller {Object} (deprecated) Use callback.scope. - */ - this.createEvent("responseEvent"); - - /** - * Fired when response is parsed. - * - * @event responseParseEvent - * @param oArgs.request {Object} The request object. - * @param oArgs.response {Object} The parsed response object. - * @param oArgs.callback {Object} The callback object. - * @param oArgs.caller {Object} (deprecated) Use callback.scope. - */ - this.createEvent("responseParseEvent"); - - /** - * Fired when response is cached. - * - * @event responseCacheEvent - * @param oArgs.request {Object} The request object. - * @param oArgs.response {Object} The parsed response object. - * @param oArgs.callback {Object} The callback object. - * @param oArgs.caller {Object} (deprecated) Use callback.scope. - */ - this.createEvent("responseCacheEvent"); - /** - * Fired when an error is encountered with the live data source. - * - * @event dataErrorEvent - * @param oArgs.request {Object} The request object. - * @param oArgs.response {String} The response object (if available). - * @param oArgs.callback {Object} The callback object. - * @param oArgs.caller {Object} (deprecated) Use callback.scope. - * @param oArgs.message {String} The error message. - */ - this.createEvent("dataErrorEvent"); - - /** - * Fired when the local cache is flushed. - * - * @event cacheFlushEvent - */ - this.createEvent("cacheFlushEvent"); - - var DS = util.DataSourceBase; - this._sName = "DataSource instance" + DS._nIndex; - DS._nIndex++; -}; - -var DS = util.DataSourceBase; - -lang.augmentObject(DS, { - -///////////////////////////////////////////////////////////////////////////// -// -// DataSourceBase public constants -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Type is unknown. - * - * @property TYPE_UNKNOWN - * @type Number - * @final - * @default -1 - */ -TYPE_UNKNOWN : -1, - -/** - * Type is a JavaScript Array. - * - * @property TYPE_JSARRAY - * @type Number - * @final - * @default 0 - */ -TYPE_JSARRAY : 0, - -/** - * Type is a JavaScript Function. - * - * @property TYPE_JSFUNCTION - * @type Number - * @final - * @default 1 - */ -TYPE_JSFUNCTION : 1, - -/** - * Type is hosted on a server via an XHR connection. - * - * @property TYPE_XHR - * @type Number - * @final - * @default 2 - */ -TYPE_XHR : 2, - -/** - * Type is JSON. - * - * @property TYPE_JSON - * @type Number - * @final - * @default 3 - */ -TYPE_JSON : 3, - -/** - * Type is XML. - * - * @property TYPE_XML - * @type Number - * @final - * @default 4 - */ -TYPE_XML : 4, - -/** - * Type is plain text. - * - * @property TYPE_TEXT - * @type Number - * @final - * @default 5 - */ -TYPE_TEXT : 5, - -/** - * Type is an HTML TABLE element. Data is parsed out of TR elements from all TBODY elements. - * - * @property TYPE_HTMLTABLE - * @type Number - * @final - * @default 6 - */ -TYPE_HTMLTABLE : 6, - -/** - * Type is hosted on a server via a dynamic script node. - * - * @property TYPE_SCRIPTNODE - * @type Number - * @final - * @default 7 - */ -TYPE_SCRIPTNODE : 7, - -/** - * Type is local. - * - * @property TYPE_LOCAL - * @type Number - * @final - * @default 8 - */ -TYPE_LOCAL : 8, - -/** - * Error message for invalid dataresponses. - * - * @property ERROR_DATAINVALID - * @type String - * @final - * @default "Invalid data" - */ -ERROR_DATAINVALID : "Invalid data", - -/** - * Error message for null data responses. - * - * @property ERROR_DATANULL - * @type String - * @final - * @default "Null data" - */ -ERROR_DATANULL : "Null data", - -///////////////////////////////////////////////////////////////////////////// -// -// DataSourceBase private static properties -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Internal class variable to index multiple DataSource instances. - * - * @property DataSourceBase._nIndex - * @type Number - * @private - * @static - */ -_nIndex : 0, - -/** - * Internal class variable to assign unique transaction IDs. - * - * @property DataSourceBase._nTransactionId - * @type Number - * @private - * @static - */ -_nTransactionId : 0, - -///////////////////////////////////////////////////////////////////////////// -// -// DataSourceBase private static methods -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Get an XPath-specified value for a given field from an XML node or document. - * - * @method _getLocationValue - * @param field {String | Object} Field definition. - * @param context {Object} XML node or document to search within. - * @return {Object} Data value or null. - * @static - * @private - */ -_getLocationValue: function(field, context) { - var locator = field.locator || field.key || field, - xmldoc = context.ownerDocument || context, - result, res, value = null; - - try { - // Standards mode - if(!lang.isUndefined(xmldoc.evaluate)) { - result = xmldoc.evaluate(locator, context, xmldoc.createNSResolver(!context.ownerDocument ? context.documentElement : context.ownerDocument.documentElement), 0, null); - while(res = result.iterateNext()) { - value = res.textContent; - } - } - // IE mode - else { - xmldoc.setProperty("SelectionLanguage", "XPath"); - result = context.selectNodes(locator)[0]; - value = result.value || result.text || null; - } - return value; - - } - catch(e) { - } -}, - -///////////////////////////////////////////////////////////////////////////// -// -// DataSourceBase public static methods -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Executes a configured callback. For object literal callbacks, the third - * param determines whether to execute the success handler or failure handler. - * - * @method issueCallback - * @param callback {Function|Object} the callback to execute - * @param params {Array} params to be passed to the callback method - * @param error {Boolean} whether an error occurred - * @param scope {Object} the scope from which to execute the callback - * (deprecated - use an object literal callback) - * @static - */ -issueCallback : function (callback,params,error,scope) { - if (lang.isFunction(callback)) { - callback.apply(scope, params); - } else if (lang.isObject(callback)) { - scope = callback.scope || scope || window; - var callbackFunc = callback.success; - if (error) { - callbackFunc = callback.failure; - } - if (callbackFunc) { - callbackFunc.apply(scope, params.concat([callback.argument])); - } - } -}, - -/** - * Converts data to type String. - * - * @method DataSourceBase.parseString - * @param oData {String | Number | Boolean | Date | Array | Object} Data to parse. - * The special values null and undefined will return null. - * @return {String} A string, or null. - * @static - */ -parseString : function(oData) { - // Special case null and undefined - if(!lang.isValue(oData)) { - return null; - } - - //Convert to string - var string = oData + ""; - - // Validate - if(lang.isString(string)) { - return string; - } - else { - return null; - } -}, - -/** - * Converts data to type Number. - * - * @method DataSourceBase.parseNumber - * @param oData {String | Number | Boolean} Data to convert. Note, the following - * values return as null: null, undefined, NaN, "". - * @return {Number} A number, or null. - * @static - */ -parseNumber : function(oData) { - if(!lang.isValue(oData) || (oData === "")) { - return null; - } - - //Convert to number - var number = oData * 1; - - // Validate - if(lang.isNumber(number)) { - return number; - } - else { - return null; - } -}, -// Backward compatibility -convertNumber : function(oData) { - return DS.parseNumber(oData); -}, - -/** - * Converts data to type Date. - * - * @method DataSourceBase.parseDate - * @param oData {Date | String | Number} Data to convert. - * @return {Date} A Date instance. - * @static - */ -parseDate : function(oData) { - var date = null; - - //Convert to date - if(!(oData instanceof Date)) { - date = new Date(oData); - } - else { - return oData; - } - - // Validate - if(date instanceof Date) { - return date; - } - else { - return null; - } -}, -// Backward compatibility -convertDate : function(oData) { - return DS.parseDate(oData); -} - -}); - -// Done in separate step so referenced functions are defined. -/** - * Data parsing functions. - * @property DataSource.Parser - * @type Object - * @static - */ -DS.Parser = { - string : DS.parseString, - number : DS.parseNumber, - date : DS.parseDate -}; - -// Prototype properties and methods -DS.prototype = { - -///////////////////////////////////////////////////////////////////////////// -// -// DataSourceBase private properties -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Name of DataSource instance. - * - * @property _sName - * @type String - * @private - */ -_sName : null, - -/** - * Local cache of data result object literals indexed chronologically. - * - * @property _aCache - * @type Object[] - * @private - */ -_aCache : null, - -/** - * Local queue of request connections, enabled if queue needs to be managed. - * - * @property _oQueue - * @type Object - * @private - */ -_oQueue : null, - -/** - * Array of polling interval IDs that have been enabled, needed to clear all intervals. - * - * @property _aIntervals - * @type Array - * @private - */ -_aIntervals : null, - -///////////////////////////////////////////////////////////////////////////// -// -// DataSourceBase public properties -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Max size of the local cache. Set to 0 to turn off caching. Caching is - * useful to reduce the number of server connections. Recommended only for data - * sources that return comprehensive results for queries or when stale data is - * not an issue. - * - * @property maxCacheEntries - * @type Number - * @default 0 - */ -maxCacheEntries : 0, - - /** - * Pointer to live database. - * - * @property liveData - * @type Object - */ -liveData : null, - -/** - * Where the live data is held: - * - *
    - *
    TYPE_UNKNOWN
    - *
    TYPE_LOCAL
    - *
    TYPE_XHR
    - *
    TYPE_SCRIPTNODE
    - *
    TYPE_JSFUNCTION
    - *
    - * - * @property dataType - * @type Number - * @default YAHOO.util.DataSourceBase.TYPE_UNKNOWN - * - */ -dataType : DS.TYPE_UNKNOWN, - -/** - * Format of response: - * - *
    - *
    TYPE_UNKNOWN
    - *
    TYPE_JSARRAY
    - *
    TYPE_JSON
    - *
    TYPE_XML
    - *
    TYPE_TEXT
    - *
    TYPE_HTMLTABLE
    - *
    - * - * @property responseType - * @type Number - * @default YAHOO.util.DataSourceBase.TYPE_UNKNOWN - */ -responseType : DS.TYPE_UNKNOWN, - -/** - * Response schema object literal takes a combination of the following properties: - * - *
    - *
    resultsList
    Pointer to array of tabular data
    - *
    resultNode
    Pointer to node name of row data (XML data only)
    - *
    recordDelim
    Record delimiter (text data only)
    - *
    fieldDelim
    Field delimiter (text data only)
    - *
    fields
    Array of field names (aka keys), or array of object literals - * such as: {key:"fieldname",parser:YAHOO.util.DataSourceBase.parseDate}
    - *
    metaFields
    Object literal of keys to include in the oParsedResponse.meta collection
    - *
    metaNode
    Name of the node under which to search for meta information in XML response data
    - *
    - * - * @property responseSchema - * @type Object - */ -responseSchema : null, - -/** - * Additional arguments passed to the JSON parse routine. The JSON string - * is the assumed first argument (where applicable). This property is not - * set by default, but the parse methods will use it if present. - * - * @property parseJSONArgs - * @type {MIXED|Array} If an Array, contents are used as individual arguments. - * Otherwise, value is used as an additional argument. - */ -// property intentionally undefined - -/** - * When working with XML data, setting this property to true enables support for - * XPath-syntaxed locators in schema definitions. - * - * @property useXPath - * @type Boolean - * @default false - */ -useXPath : false, - -///////////////////////////////////////////////////////////////////////////// -// -// DataSourceBase public methods -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Public accessor to the unique name of the DataSource instance. - * - * @method toString - * @return {String} Unique name of the DataSource instance. - */ -toString : function() { - return this._sName; -}, - -/** - * Overridable method passes request to cache and returns cached response if any, - * refreshing the hit in the cache as the newest item. Returns null if there is - * no cache hit. - * - * @method getCachedResponse - * @param oRequest {Object} Request object. - * @param oCallback {Object} Callback object. - * @param oCaller {Object} (deprecated) Use callback object. - * @return {Object} Cached response object or null. - */ -getCachedResponse : function(oRequest, oCallback, oCaller) { - var aCache = this._aCache; - - // If cache is enabled... - if(this.maxCacheEntries > 0) { - // Initialize local cache - if(!aCache) { - this._aCache = []; - } - // Look in local cache - else { - var nCacheLength = aCache.length; - if(nCacheLength > 0) { - var oResponse = null; - this.fireEvent("cacheRequestEvent", {request:oRequest,callback:oCallback,caller:oCaller}); - - // Loop through each cached element - for(var i = nCacheLength-1; i >= 0; i--) { - var oCacheElem = aCache[i]; - - // Defer cache hit logic to a public overridable method - if(this.isCacheHit(oRequest,oCacheElem.request)) { - // The cache returned a hit! - // Grab the cached response - oResponse = oCacheElem.response; - this.fireEvent("cacheResponseEvent", {request:oRequest,response:oResponse,callback:oCallback,caller:oCaller}); - - // Refresh the position of the cache hit - if(i < nCacheLength-1) { - // Remove element from its original location - aCache.splice(i,1); - // Add as newest - this.addToCache(oRequest, oResponse); - } - - // Add a cache flag - oResponse.cached = true; - break; - } - } - return oResponse; - } - } - } - else if(aCache) { - this._aCache = null; - } - return null; -}, - -/** - * Default overridable method matches given request to given cached request. - * Returns true if is a hit, returns false otherwise. Implementers should - * override this method to customize the cache-matching algorithm. - * - * @method isCacheHit - * @param oRequest {Object} Request object. - * @param oCachedRequest {Object} Cached request object. - * @return {Boolean} True if given request matches cached request, false otherwise. - */ -isCacheHit : function(oRequest, oCachedRequest) { - return (oRequest === oCachedRequest); -}, - -/** - * Adds a new item to the cache. If cache is full, evicts the stalest item - * before adding the new item. - * - * @method addToCache - * @param oRequest {Object} Request object. - * @param oResponse {Object} Response object to cache. - */ -addToCache : function(oRequest, oResponse) { - var aCache = this._aCache; - if(!aCache) { - return; - } - - // If the cache is full, make room by removing stalest element (index=0) - while(aCache.length >= this.maxCacheEntries) { - aCache.shift(); - } - - // Add to cache in the newest position, at the end of the array - var oCacheElem = {request:oRequest,response:oResponse}; - aCache[aCache.length] = oCacheElem; - this.fireEvent("responseCacheEvent", {request:oRequest,response:oResponse}); -}, - -/** - * Flushes cache. - * - * @method flushCache - */ -flushCache : function() { - if(this._aCache) { - this._aCache = []; - this.fireEvent("cacheFlushEvent"); - } -}, - -/** - * Sets up a polling mechanism to send requests at set intervals and forward - * responses to given callback. - * - * @method setInterval - * @param nMsec {Number} Length of interval in milliseconds. - * @param oRequest {Object} Request object. - * @param oCallback {Function} Handler function to receive the response. - * @param oCaller {Object} (deprecated) Use oCallback.scope. - * @return {Number} Interval ID. - */ -setInterval : function(nMsec, oRequest, oCallback, oCaller) { - if(lang.isNumber(nMsec) && (nMsec >= 0)) { - var oSelf = this; - var nId = setInterval(function() { - oSelf.makeConnection(oRequest, oCallback, oCaller); - }, nMsec); - this._aIntervals.push(nId); - return nId; - } - else { - } -}, - -/** - * Disables polling mechanism associated with the given interval ID. - * - * @method clearInterval - * @param nId {Number} Interval ID. - */ -clearInterval : function(nId) { - // Remove from tracker if there - var tracker = this._aIntervals || []; - for(var i=tracker.length-1; i>-1; i--) { - if(tracker[i] === nId) { - tracker.splice(i,1); - clearInterval(nId); - } - } -}, - -/** - * Disables all known polling intervals. - * - * @method clearAllIntervals - */ -clearAllIntervals : function() { - var tracker = this._aIntervals || []; - for(var i=tracker.length-1; i>-1; i--) { - clearInterval(tracker[i]); - } - tracker = []; -}, - -/** - * First looks for cached response, then sends request to live data. The - * following arguments are passed to the callback function: - *
    - *
    oRequest
    - *
    The same value that was passed in as the first argument to sendRequest.
    - *
    oParsedResponse
    - *
    An object literal containing the following properties: - *
    - *
    tId
    - *
    Unique transaction ID number.
    - *
    results
    - *
    Schema-parsed data results.
    - *
    error
    - *
    True in cases of data error.
    - *
    cached
    - *
    True when response is returned from DataSource cache.
    - *
    meta
    - *
    Schema-parsed meta data.
    - *
    - *
    oPayload
    - *
    The same value as was passed in as argument in the oCallback object literal.
    - *
    - * - * @method sendRequest - * @param oRequest {Object} Request object. - * @param oCallback {Object} An object literal with the following properties: - *
    - *
    success
    - *
    The function to call when the data is ready.
    - *
    failure
    - *
    The function to call upon a response failure condition.
    - *
    scope
    - *
    The object to serve as the scope for the success and failure handlers.
    - *
    argument
    - *
    Arbitrary data that will be passed back to the success and failure handlers.
    - *
    - * @param oCaller {Object} (deprecated) Use oCallback.scope. - * @return {Number} Transaction ID, or null if response found in cache. - */ -sendRequest : function(oRequest, oCallback, oCaller) { - // First look in cache - var oCachedResponse = this.getCachedResponse(oRequest, oCallback, oCaller); - if(oCachedResponse) { - DS.issueCallback(oCallback,[oRequest,oCachedResponse],false,oCaller); - return null; - } - - - // Not in cache, so forward request to live data - return this.makeConnection(oRequest, oCallback, oCaller); -}, - -/** - * Overridable default method generates a unique transaction ID and passes - * the live data reference directly to the handleResponse function. This - * method should be implemented by subclasses to achieve more complex behavior - * or to access remote data. - * - * @method makeConnection - * @param oRequest {Object} Request object. - * @param oCallback {Object} Callback object literal. - * @param oCaller {Object} (deprecated) Use oCallback.scope. - * @return {Number} Transaction ID. - */ -makeConnection : function(oRequest, oCallback, oCaller) { - var tId = DS._nTransactionId++; - this.fireEvent("requestEvent", {tId:tId, request:oRequest,callback:oCallback,caller:oCaller}); - - /* accounts for the following cases: - YAHOO.util.DataSourceBase.TYPE_UNKNOWN - YAHOO.util.DataSourceBase.TYPE_JSARRAY - YAHOO.util.DataSourceBase.TYPE_JSON - YAHOO.util.DataSourceBase.TYPE_HTMLTABLE - YAHOO.util.DataSourceBase.TYPE_XML - YAHOO.util.DataSourceBase.TYPE_TEXT - */ - var oRawResponse = this.liveData; - - this.handleResponse(oRequest, oRawResponse, oCallback, oCaller, tId); - return tId; -}, - -/** - * Receives raw data response and type converts to XML, JSON, etc as necessary. - * Forwards oFullResponse to appropriate parsing function to get turned into - * oParsedResponse. Calls doBeforeCallback() and adds oParsedResponse to - * the cache when appropriate before calling issueCallback(). - * - * The oParsedResponse object literal has the following properties: - *
    - *
    tId {Number}
    Unique transaction ID - *
    results {Array}
    Array of parsed data results - *
    meta {Object}
    Object literal of meta values - *
    error {Boolean}
    (optional) True if there was an error - *
    cached {Boolean}
    (optional) True if response was cached - *
    - * - * @method handleResponse - * @param oRequest {Object} Request object - * @param oRawResponse {Object} The raw response from the live database. - * @param oCallback {Object} Callback object literal. - * @param oCaller {Object} (deprecated) Use oCallback.scope. - * @param tId {Number} Transaction ID. - */ -handleResponse : function(oRequest, oRawResponse, oCallback, oCaller, tId) { - this.fireEvent("responseEvent", {tId:tId, request:oRequest, response:oRawResponse, - callback:oCallback, caller:oCaller}); - var xhr = (this.dataType == DS.TYPE_XHR) ? true : false; - var oParsedResponse = null; - var oFullResponse = oRawResponse; - - // Try to sniff data type if it has not been defined - if(this.responseType === DS.TYPE_UNKNOWN) { - var ctype = (oRawResponse && oRawResponse.getResponseHeader) ? oRawResponse.getResponseHeader["Content-Type"] : null; - if(ctype) { - // xml - if(ctype.indexOf("text/xml") > -1) { - this.responseType = DS.TYPE_XML; - } - else if(ctype.indexOf("application/json") > -1) { // json - this.responseType = DS.TYPE_JSON; - } - else if(ctype.indexOf("text/plain") > -1) { // text - this.responseType = DS.TYPE_TEXT; - } - } - else { - if(YAHOO.lang.isArray(oRawResponse)) { // array - this.responseType = DS.TYPE_JSARRAY; - } - // xml - else if(oRawResponse && oRawResponse.nodeType && (oRawResponse.nodeType === 9 || oRawResponse.nodeType === 1 || oRawResponse.nodeType === 11)) { - this.responseType = DS.TYPE_XML; - } - else if(oRawResponse && oRawResponse.nodeName && (oRawResponse.nodeName.toLowerCase() == "table")) { // table - this.responseType = DS.TYPE_HTMLTABLE; - } - else if(YAHOO.lang.isObject(oRawResponse)) { // json - this.responseType = DS.TYPE_JSON; - } - else if(YAHOO.lang.isString(oRawResponse)) { // text - this.responseType = DS.TYPE_TEXT; - } - } - } - - switch(this.responseType) { - case DS.TYPE_JSARRAY: - if(xhr && oRawResponse && oRawResponse.responseText) { - oFullResponse = oRawResponse.responseText; - } - try { - // Convert to JS array if it's a string - if(lang.isString(oFullResponse)) { - var parseArgs = [oFullResponse].concat(this.parseJSONArgs); - // Check for YUI JSON Util - if(lang.JSON) { - oFullResponse = lang.JSON.parse.apply(lang.JSON,parseArgs); - } - // Look for JSON parsers using an API similar to json2.js - else if(window.JSON && JSON.parse) { - oFullResponse = JSON.parse.apply(JSON,parseArgs); - } - // Look for JSON parsers using an API similar to json.js - else if(oFullResponse.parseJSON) { - oFullResponse = oFullResponse.parseJSON.apply(oFullResponse,parseArgs.slice(1)); - } - // No JSON lib found so parse the string - else { - // Trim leading spaces - while (oFullResponse.length > 0 && - (oFullResponse.charAt(0) != "{") && - (oFullResponse.charAt(0) != "[")) { - oFullResponse = oFullResponse.substring(1, oFullResponse.length); - } - - if(oFullResponse.length > 0) { - // Strip extraneous stuff at the end - var arrayEnd = -Math.max(oFullResponse.lastIndexOf("]"),oFullResponse.lastIndexOf("}")); - oFullResponse = oFullResponse.substring(0,arrayEnd+1); - - // Turn the string into an object literal... - // ...eval is necessary here - oFullResponse = eval("(" + oFullResponse + ")"); - - } - } - } - } - catch(e1) { - } - oFullResponse = this.doBeforeParseData(oRequest, oFullResponse, oCallback); - oParsedResponse = this.parseArrayData(oRequest, oFullResponse); - break; - case DS.TYPE_JSON: - if(xhr && oRawResponse && oRawResponse.responseText) { - oFullResponse = oRawResponse.responseText; - } - try { - // Convert to JSON object if it's a string - if(lang.isString(oFullResponse)) { - var parseArgs = [oFullResponse].concat(this.parseJSONArgs); - // Check for YUI JSON Util - if(lang.JSON) { - oFullResponse = lang.JSON.parse.apply(lang.JSON,parseArgs); - } - // Look for JSON parsers using an API similar to json2.js - else if(window.JSON && JSON.parse) { - oFullResponse = JSON.parse.apply(JSON,parseArgs); - } - // Look for JSON parsers using an API similar to json.js - else if(oFullResponse.parseJSON) { - oFullResponse = oFullResponse.parseJSON.apply(oFullResponse,parseArgs.slice(1)); - } - // No JSON lib found so parse the string - else { - // Trim leading spaces - while (oFullResponse.length > 0 && - (oFullResponse.charAt(0) != "{") && - (oFullResponse.charAt(0) != "[")) { - oFullResponse = oFullResponse.substring(1, oFullResponse.length); - } - - if(oFullResponse.length > 0) { - // Strip extraneous stuff at the end - var objEnd = Math.max(oFullResponse.lastIndexOf("]"),oFullResponse.lastIndexOf("}")); - oFullResponse = oFullResponse.substring(0,objEnd+1); - - // Turn the string into an object literal... - // ...eval is necessary here - oFullResponse = eval("(" + oFullResponse + ")"); - - } - } - } - } - catch(e) { - } - - oFullResponse = this.doBeforeParseData(oRequest, oFullResponse, oCallback); - oParsedResponse = this.parseJSONData(oRequest, oFullResponse); - break; - case DS.TYPE_HTMLTABLE: - if(xhr && oRawResponse.responseText) { - var el = document.createElement('div'); - el.innerHTML = oRawResponse.responseText; - oFullResponse = el.getElementsByTagName('table')[0]; - } - oFullResponse = this.doBeforeParseData(oRequest, oFullResponse, oCallback); - oParsedResponse = this.parseHTMLTableData(oRequest, oFullResponse); - break; - case DS.TYPE_XML: - if(xhr && oRawResponse.responseXML) { - oFullResponse = oRawResponse.responseXML; - } - oFullResponse = this.doBeforeParseData(oRequest, oFullResponse, oCallback); - oParsedResponse = this.parseXMLData(oRequest, oFullResponse); - break; - case DS.TYPE_TEXT: - if(xhr && lang.isString(oRawResponse.responseText)) { - oFullResponse = oRawResponse.responseText; - } - oFullResponse = this.doBeforeParseData(oRequest, oFullResponse, oCallback); - oParsedResponse = this.parseTextData(oRequest, oFullResponse); - break; - default: - oFullResponse = this.doBeforeParseData(oRequest, oFullResponse, oCallback); - oParsedResponse = this.parseData(oRequest, oFullResponse); - break; - } - - - // Clean up for consistent signature - oParsedResponse = oParsedResponse || {}; - if(!oParsedResponse.results) { - oParsedResponse.results = []; - } - if(!oParsedResponse.meta) { - oParsedResponse.meta = {}; - } - - // Success - if(!oParsedResponse.error) { - // Last chance to touch the raw response or the parsed response - oParsedResponse = this.doBeforeCallback(oRequest, oFullResponse, oParsedResponse, oCallback); - this.fireEvent("responseParseEvent", {request:oRequest, - response:oParsedResponse, callback:oCallback, caller:oCaller}); - // Cache the response - this.addToCache(oRequest, oParsedResponse); - } - // Error - else { - // Be sure the error flag is on - oParsedResponse.error = true; - this.fireEvent("dataErrorEvent", {request:oRequest, response: oRawResponse, callback:oCallback, - caller:oCaller, message:DS.ERROR_DATANULL}); - } - - // Send the response back to the caller - oParsedResponse.tId = tId; - DS.issueCallback(oCallback,[oRequest,oParsedResponse],oParsedResponse.error,oCaller); -}, - -/** - * Overridable method gives implementers access to the original full response - * before the data gets parsed. Implementers should take care not to return an - * unparsable or otherwise invalid response. - * - * @method doBeforeParseData - * @param oRequest {Object} Request object. - * @param oFullResponse {Object} The full response from the live database. - * @param oCallback {Object} The callback object. - * @return {Object} Full response for parsing. - - */ -doBeforeParseData : function(oRequest, oFullResponse, oCallback) { - return oFullResponse; -}, - -/** - * Overridable method gives implementers access to the original full response and - * the parsed response (parsed against the given schema) before the data - * is added to the cache (if applicable) and then sent back to callback function. - * This is your chance to access the raw response and/or populate the parsed - * response with any custom data. - * - * @method doBeforeCallback - * @param oRequest {Object} Request object. - * @param oFullResponse {Object} The full response from the live database. - * @param oParsedResponse {Object} The parsed response to return to calling object. - * @param oCallback {Object} The callback object. - * @return {Object} Parsed response object. - */ -doBeforeCallback : function(oRequest, oFullResponse, oParsedResponse, oCallback) { - return oParsedResponse; -}, - -/** - * Overridable method parses data of generic RESPONSE_TYPE into a response object. - * - * @method parseData - * @param oRequest {Object} Request object. - * @param oFullResponse {Object} The full Array from the live database. - * @return {Object} Parsed response object with the following properties:
    - * - results {Array} Array of parsed data results
    - * - meta {Object} Object literal of meta values
    - * - error {Boolean} (optional) True if there was an error
    - */ -parseData : function(oRequest, oFullResponse) { - if(lang.isValue(oFullResponse)) { - var oParsedResponse = {results:oFullResponse,meta:{}}; - return oParsedResponse; - - } - return null; -}, - -/** - * Overridable method parses Array data into a response object. - * - * @method parseArrayData - * @param oRequest {Object} Request object. - * @param oFullResponse {Object} The full Array from the live database. - * @return {Object} Parsed response object with the following properties:
    - * - results (Array) Array of parsed data results
    - * - error (Boolean) True if there was an error - */ -parseArrayData : function(oRequest, oFullResponse) { - if(lang.isArray(oFullResponse)) { - var results = [], - i, j, - rec, field, data; - - // Parse for fields - if(lang.isArray(this.responseSchema.fields)) { - var fields = this.responseSchema.fields; - for (i = fields.length - 1; i >= 0; --i) { - if (typeof fields[i] !== 'object') { - fields[i] = { key : fields[i] }; - } - } - - var parsers = {}, p; - for (i = fields.length - 1; i >= 0; --i) { - p = (typeof fields[i].parser === 'function' ? - fields[i].parser : - DS.Parser[fields[i].parser+'']) || fields[i].converter; - if (p) { - parsers[fields[i].key] = p; - } - } - - var arrType = lang.isArray(oFullResponse[0]); - for(i=oFullResponse.length-1; i>-1; i--) { - var oResult = {}; - rec = oFullResponse[i]; - if (typeof rec === 'object') { - for(j=fields.length-1; j>-1; j--) { - field = fields[j]; - data = arrType ? rec[j] : rec[field.key]; - - if (parsers[field.key]) { - data = parsers[field.key].call(this,data); - } - - // Safety measure - if(data === undefined) { - data = null; - } - - oResult[field.key] = data; - } - } - else if (lang.isString(rec)) { - for(j=fields.length-1; j>-1; j--) { - field = fields[j]; - data = rec; - - if (parsers[field.key]) { - data = parsers[field.key].call(this,data); - } - - // Safety measure - if(data === undefined) { - data = null; - } - - oResult[field.key] = data; - } - } - results[i] = oResult; - } - } - // Return entire data set - else { - results = oFullResponse; - } - var oParsedResponse = {results:results}; - return oParsedResponse; - - } - return null; -}, - -/** - * Overridable method parses plain text data into a response object. - * - * @method parseTextData - * @param oRequest {Object} Request object. - * @param oFullResponse {Object} The full text response from the live database. - * @return {Object} Parsed response object with the following properties:
    - * - results (Array) Array of parsed data results
    - * - error (Boolean) True if there was an error - */ -parseTextData : function(oRequest, oFullResponse) { - if(lang.isString(oFullResponse)) { - if(lang.isString(this.responseSchema.recordDelim) && - lang.isString(this.responseSchema.fieldDelim)) { - var oParsedResponse = {results:[]}; - var recDelim = this.responseSchema.recordDelim; - var fieldDelim = this.responseSchema.fieldDelim; - if(oFullResponse.length > 0) { - // Delete the last line delimiter at the end of the data if it exists - var newLength = oFullResponse.length-recDelim.length; - if(oFullResponse.substr(newLength) == recDelim) { - oFullResponse = oFullResponse.substr(0, newLength); - } - if(oFullResponse.length > 0) { - // Split along record delimiter to get an array of strings - var recordsarray = oFullResponse.split(recDelim); - // Cycle through each record - for(var i = 0, len = recordsarray.length, recIdx = 0; i < len; ++i) { - var bError = false, - sRecord = recordsarray[i]; - if (lang.isString(sRecord) && (sRecord.length > 0)) { - // Split each record along field delimiter to get data - var fielddataarray = recordsarray[i].split(fieldDelim); - var oResult = {}; - - // Filter for fields data - if(lang.isArray(this.responseSchema.fields)) { - var fields = this.responseSchema.fields; - for(var j=fields.length-1; j>-1; j--) { - try { - // Remove quotation marks from edges, if applicable - var data = fielddataarray[j]; - if (lang.isString(data)) { - if(data.charAt(0) == "\"") { - data = data.substr(1); - } - if(data.charAt(data.length-1) == "\"") { - data = data.substr(0,data.length-1); - } - var field = fields[j]; - var key = (lang.isValue(field.key)) ? field.key : field; - // Backward compatibility - if(!field.parser && field.converter) { - field.parser = field.converter; - } - var parser = (typeof field.parser === 'function') ? - field.parser : - DS.Parser[field.parser+'']; - if(parser) { - data = parser.call(this, data); - } - // Safety measure - if(data === undefined) { - data = null; - } - oResult[key] = data; - } - else { - bError = true; - } - } - catch(e) { - bError = true; - } - } - } - // No fields defined so pass along all data as an array - else { - oResult = fielddataarray; - } - if(!bError) { - oParsedResponse.results[recIdx++] = oResult; - } - } - } - } - } - return oParsedResponse; - } - } - return null; - -}, - -/** - * Overridable method parses XML data for one result into an object literal. - * - * @method parseXMLResult - * @param result {XML} XML for one result. - * @return {Object} Object literal of data for one result. - */ -parseXMLResult : function(result) { - var oResult = {}, - schema = this.responseSchema; - - try { - // Loop through each data field in each result using the schema - for(var m = schema.fields.length-1; m >= 0 ; m--) { - var field = schema.fields[m]; - var key = (lang.isValue(field.key)) ? field.key : field; - var data = null; - - if(this.useXPath) { - data = YAHOO.util.DataSource._getLocationValue(field, result); - } - else { - // Values may be held in an attribute... - var xmlAttr = result.attributes.getNamedItem(key); - if(xmlAttr) { - data = xmlAttr.value; - } - // ...or in a node - else { - var xmlNode = result.getElementsByTagName(key); - if(xmlNode && xmlNode.item(0)) { - var item = xmlNode.item(0); - // For IE, then DOM... - data = (item) ? ((item.text) ? item.text : (item.textContent) ? item.textContent : null) : null; - // ...then fallback, but check for multiple child nodes - if(!data) { - var datapieces = []; - for(var j=0, len=item.childNodes.length; j 0) { - data = datapieces.join(""); - } - } - } - } - } - - - // Safety net - if(data === null) { - data = ""; - } - // Backward compatibility - if(!field.parser && field.converter) { - field.parser = field.converter; - } - var parser = (typeof field.parser === 'function') ? - field.parser : - DS.Parser[field.parser+'']; - if(parser) { - data = parser.call(this, data); - } - // Safety measure - if(data === undefined) { - data = null; - } - oResult[key] = data; - } - } - catch(e) { - } - - return oResult; -}, - - - -/** - * Overridable method parses XML data into a response object. - * - * @method parseXMLData - * @param oRequest {Object} Request object. - * @param oFullResponse {Object} The full XML response from the live database. - * @return {Object} Parsed response object with the following properties
    - * - results (Array) Array of parsed data results
    - * - error (Boolean) True if there was an error - */ -parseXMLData : function(oRequest, oFullResponse) { - var bError = false, - schema = this.responseSchema, - oParsedResponse = {meta:{}}, - xmlList = null, - metaNode = schema.metaNode, - metaLocators = schema.metaFields || {}, - i,k,loc,v; - - // In case oFullResponse is something funky - try { - // Pull any meta identified - if(this.useXPath) { - for (k in metaLocators) { - oParsedResponse.meta[k] = YAHOO.util.DataSource._getLocationValue(metaLocators[k], oFullResponse); - } - } - else { - metaNode = metaNode ? oFullResponse.getElementsByTagName(metaNode)[0] : - oFullResponse; - - if (metaNode) { - for (k in metaLocators) { - if (lang.hasOwnProperty(metaLocators, k)) { - loc = metaLocators[k]; - // Look for a node - v = metaNode.getElementsByTagName(loc)[0]; - - if (v) { - v = v.firstChild.nodeValue; - } else { - // Look for an attribute - v = metaNode.attributes.getNamedItem(loc); - if (v) { - v = v.value; - } - } - - if (lang.isValue(v)) { - oParsedResponse.meta[k] = v; - } - } - } - } - } - - // For result data - xmlList = (schema.resultNode) ? - oFullResponse.getElementsByTagName(schema.resultNode) : - null; - } - catch(e) { - } - if(!xmlList || !lang.isArray(schema.fields)) { - bError = true; - } - // Loop through each result - else { - oParsedResponse.results = []; - for(i = xmlList.length-1; i >= 0 ; --i) { - var oResult = this.parseXMLResult(xmlList.item(i)); - // Capture each array of values into an array of results - oParsedResponse.results[i] = oResult; - } - } - if(bError) { - oParsedResponse.error = true; - } - else { - } - return oParsedResponse; -}, - -/** - * Overridable method parses JSON data into a response object. - * - * @method parseJSONData - * @param oRequest {Object} Request object. - * @param oFullResponse {Object} The full JSON from the live database. - * @return {Object} Parsed response object with the following properties
    - * - results (Array) Array of parsed data results
    - * - error (Boolean) True if there was an error - */ -parseJSONData : function(oRequest, oFullResponse) { - var oParsedResponse = {results:[],meta:{}}; - - if(lang.isObject(oFullResponse) && this.responseSchema.resultsList) { - var schema = this.responseSchema, - fields = schema.fields, - resultsList = oFullResponse, - results = [], - metaFields = schema.metaFields || {}, - fieldParsers = [], - fieldPaths = [], - simpleFields = [], - bError = false, - i,len,j,v,key,parser,path; - - // Function to convert the schema's fields into walk paths - var buildPath = function (needle) { - var path = null, keys = [], i = 0; - if (needle) { - // Strip the ["string keys"] and [1] array indexes - needle = needle. - replace(/\[(['"])(.*?)\1\]/g, - function (x,$1,$2) {keys[i]=$2;return '.@'+(i++);}). - replace(/\[(\d+)\]/g, - function (x,$1) {keys[i]=parseInt($1,10)|0;return '.@'+(i++);}). - replace(/^\./,''); // remove leading dot - - // If the cleaned needle contains invalid characters, the - // path is invalid - if (!/[^\w\.\$@]/.test(needle)) { - path = needle.split('.'); - for (i=path.length-1; i >= 0; --i) { - if (path[i].charAt(0) === '@') { - path[i] = keys[parseInt(path[i].substr(1),10)]; - } - } - } - else { - } - } - return path; - }; - - - // Function to walk a path and return the pot of gold - var walkPath = function (path, origin) { - var v=origin,i=0,len=path.length; - for (;i 1) { - fieldPaths[fieldPaths.length] = {key:key,path:path}; - } else { - simpleFields[simpleFields.length] = {key:key,path:path[0]}; - } - } else { - } - } - - // Process the results, flattening the records and/or applying parsers if needed - for (i = resultsList.length - 1; i >= 0; --i) { - var r = resultsList[i], rec = {}; - if(r) { - for (j = simpleFields.length - 1; j >= 0; --j) { - // Bug 1777850: data might be held in an array - rec[simpleFields[j].key] = - (r[simpleFields[j].path] !== undefined) ? - r[simpleFields[j].path] : r[j]; - } - - for (j = fieldPaths.length - 1; j >= 0; --j) { - rec[fieldPaths[j].key] = walkPath(fieldPaths[j].path,r); - } - - for (j = fieldParsers.length - 1; j >= 0; --j) { - var p = fieldParsers[j].key; - rec[p] = fieldParsers[j].parser(rec[p]); - if (rec[p] === undefined) { - rec[p] = null; - } - } - } - results[i] = rec; - } - } - else { - results = resultsList; - } - - for (key in metaFields) { - if (lang.hasOwnProperty(metaFields,key)) { - path = buildPath(metaFields[key]); - if (path) { - v = walkPath(path, oFullResponse); - oParsedResponse.meta[key] = v; - } - } - } - - } else { - - oParsedResponse.error = true; - } - - oParsedResponse.results = results; - } - else { - oParsedResponse.error = true; - } - - return oParsedResponse; -}, - -/** - * Overridable method parses an HTML TABLE element reference into a response object. - * Data is parsed out of TR elements from all TBODY elements. - * - * @method parseHTMLTableData - * @param oRequest {Object} Request object. - * @param oFullResponse {Object} The full HTML element reference from the live database. - * @return {Object} Parsed response object with the following properties
    - * - results (Array) Array of parsed data results
    - * - error (Boolean) True if there was an error - */ -parseHTMLTableData : function(oRequest, oFullResponse) { - var bError = false; - var elTable = oFullResponse; - var fields = this.responseSchema.fields; - var oParsedResponse = {results:[]}; - - if(lang.isArray(fields)) { - // Iterate through each TBODY - for(var i=0; i-1; j--) { - var elRow = elTbody.rows[j]; - var oResult = {}; - - for(var k=fields.length-1; k>-1; k--) { - var field = fields[k]; - var key = (lang.isValue(field.key)) ? field.key : field; - var data = elRow.cells[k].innerHTML; - - // Backward compatibility - if(!field.parser && field.converter) { - field.parser = field.converter; - } - var parser = (typeof field.parser === 'function') ? - field.parser : - DS.Parser[field.parser+'']; - if(parser) { - data = parser.call(this, data); - } - // Safety measure - if(data === undefined) { - data = null; - } - oResult[key] = data; - } - oParsedResponse.results[j] = oResult; - } - } - } - else { - bError = true; - } - - if(bError) { - oParsedResponse.error = true; - } - else { - } - return oParsedResponse; -} - -}; - -// DataSourceBase uses EventProvider -lang.augmentProto(DS, util.EventProvider); - - - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -/** - * LocalDataSource class for in-memory data structs including JavaScript arrays, - * JavaScript object literals (JSON), XML documents, and HTML tables. - * - * @namespace YAHOO.util - * @class YAHOO.util.LocalDataSource - * @extends YAHOO.util.DataSourceBase - * @constructor - * @param oLiveData {HTMLElement} Pointer to live data. - * @param oConfigs {object} (optional) Object literal of configuration values. - */ -util.LocalDataSource = function(oLiveData, oConfigs) { - this.dataType = DS.TYPE_LOCAL; - - if(oLiveData) { - if(YAHOO.lang.isArray(oLiveData)) { // array - this.responseType = DS.TYPE_JSARRAY; - } - // xml - else if(oLiveData.nodeType && oLiveData.nodeType == 9) { - this.responseType = DS.TYPE_XML; - } - else if(oLiveData.nodeName && (oLiveData.nodeName.toLowerCase() == "table")) { // table - this.responseType = DS.TYPE_HTMLTABLE; - oLiveData = oLiveData.cloneNode(true); - } - else if(YAHOO.lang.isString(oLiveData)) { // text - this.responseType = DS.TYPE_TEXT; - } - else if(YAHOO.lang.isObject(oLiveData)) { // json - this.responseType = DS.TYPE_JSON; - } - } - else { - oLiveData = []; - this.responseType = DS.TYPE_JSARRAY; - } - - util.LocalDataSource.superclass.constructor.call(this, oLiveData, oConfigs); -}; - -// LocalDataSource extends DataSourceBase -lang.extend(util.LocalDataSource, DS); - -// Copy static members to LocalDataSource class -lang.augmentObject(util.LocalDataSource, DS); - - - - - - - - - - - - - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -/** - * FunctionDataSource class for JavaScript functions. - * - * @namespace YAHOO.util - * @class YAHOO.util.FunctionDataSource - * @extends YAHOO.util.DataSourceBase - * @constructor - * @param oLiveData {HTMLElement} Pointer to live data. - * @param oConfigs {object} (optional) Object literal of configuration values. - */ -util.FunctionDataSource = function(oLiveData, oConfigs) { - this.dataType = DS.TYPE_JSFUNCTION; - oLiveData = oLiveData || function() {}; - - util.FunctionDataSource.superclass.constructor.call(this, oLiveData, oConfigs); -}; - -// FunctionDataSource extends DataSourceBase -lang.extend(util.FunctionDataSource, DS, { - -///////////////////////////////////////////////////////////////////////////// -// -// FunctionDataSource public properties -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Context in which to execute the function. By default, is the DataSource - * instance itself. If set, the function will receive the DataSource instance - * as an additional argument. - * - * @property scope - * @type Object - * @default null - */ -scope : null, - - -///////////////////////////////////////////////////////////////////////////// -// -// FunctionDataSource public methods -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Overriding method passes query to a function. The returned response is then - * forwarded to the handleResponse function. - * - * @method makeConnection - * @param oRequest {Object} Request object. - * @param oCallback {Object} Callback object literal. - * @param oCaller {Object} (deprecated) Use oCallback.scope. - * @return {Number} Transaction ID. - */ -makeConnection : function(oRequest, oCallback, oCaller) { - var tId = DS._nTransactionId++; - this.fireEvent("requestEvent", {tId:tId,request:oRequest,callback:oCallback,caller:oCaller}); - - // Pass the request in as a parameter and - // forward the return value to the handler - - - var oRawResponse = (this.scope) ? this.liveData.call(this.scope, oRequest, this) : this.liveData(oRequest); - - // Try to sniff data type if it has not been defined - if(this.responseType === DS.TYPE_UNKNOWN) { - if(YAHOO.lang.isArray(oRawResponse)) { // array - this.responseType = DS.TYPE_JSARRAY; - } - // xml - else if(oRawResponse && oRawResponse.nodeType && oRawResponse.nodeType == 9) { - this.responseType = DS.TYPE_XML; - } - else if(oRawResponse && oRawResponse.nodeName && (oRawResponse.nodeName.toLowerCase() == "table")) { // table - this.responseType = DS.TYPE_HTMLTABLE; - } - else if(YAHOO.lang.isObject(oRawResponse)) { // json - this.responseType = DS.TYPE_JSON; - } - else if(YAHOO.lang.isString(oRawResponse)) { // text - this.responseType = DS.TYPE_TEXT; - } - } - - this.handleResponse(oRequest, oRawResponse, oCallback, oCaller, tId); - return tId; -} - -}); - -// Copy static members to FunctionDataSource class -lang.augmentObject(util.FunctionDataSource, DS); - - - - - - - - - - - - - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -/** - * ScriptNodeDataSource class for accessing remote data via the YUI Get Utility. - * - * @namespace YAHOO.util - * @class YAHOO.util.ScriptNodeDataSource - * @extends YAHOO.util.DataSourceBase - * @constructor - * @param oLiveData {HTMLElement} Pointer to live data. - * @param oConfigs {object} (optional) Object literal of configuration values. - */ -util.ScriptNodeDataSource = function(oLiveData, oConfigs) { - this.dataType = DS.TYPE_SCRIPTNODE; - oLiveData = oLiveData || ""; - - util.ScriptNodeDataSource.superclass.constructor.call(this, oLiveData, oConfigs); -}; - -// ScriptNodeDataSource extends DataSourceBase -lang.extend(util.ScriptNodeDataSource, DS, { - -///////////////////////////////////////////////////////////////////////////// -// -// ScriptNodeDataSource public properties -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Alias to YUI Get Utility, to allow implementers to use a custom class. - * - * @property getUtility - * @type Object - * @default YAHOO.util.Get - */ -getUtility : util.Get, - -/** - * Defines request/response management in the following manner: - *
    - * - *
    ignoreStaleResponses
    - *
    Send all requests, but handle only the response for the most recently sent request.
    - *
    allowAll
    - *
    Send all requests and handle all responses.
    - *
    - * - * @property asyncMode - * @type String - * @default "allowAll" - */ -asyncMode : "allowAll", - -/** - * Callback string parameter name sent to the remote script. By default, - * requests are sent to - * <URI>?<scriptCallbackParam>=callbackFunction - * - * @property scriptCallbackParam - * @type String - * @default "callback" - */ -scriptCallbackParam : "callback", - - -///////////////////////////////////////////////////////////////////////////// -// -// ScriptNodeDataSource public methods -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Creates a request callback that gets appended to the script URI. Implementers - * can customize this string to match their server's query syntax. - * - * @method generateRequestCallback - * @return {String} String fragment that gets appended to script URI that - * specifies the callback function - */ -generateRequestCallback : function(id) { - return "&" + this.scriptCallbackParam + "=YAHOO.util.ScriptNodeDataSource.callbacks["+id+"]" ; -}, - -/** - * Overridable method gives implementers access to modify the URI before the dynamic - * script node gets inserted. Implementers should take care not to return an - * invalid URI. - * - * @method doBeforeGetScriptNode - * @param {String} URI to the script - * @return {String} URI to the script - */ -doBeforeGetScriptNode : function(sUri) { - return sUri; -}, - -/** - * Overriding method passes query to Get Utility. The returned - * response is then forwarded to the handleResponse function. - * - * @method makeConnection - * @param oRequest {Object} Request object. - * @param oCallback {Object} Callback object literal. - * @param oCaller {Object} (deprecated) Use oCallback.scope. - * @return {Number} Transaction ID. - */ -makeConnection : function(oRequest, oCallback, oCaller) { - var tId = DS._nTransactionId++; - this.fireEvent("requestEvent", {tId:tId,request:oRequest,callback:oCallback,caller:oCaller}); - - // If there are no global pending requests, it is safe to purge global callback stack and global counter - if(util.ScriptNodeDataSource._nPending === 0) { - util.ScriptNodeDataSource.callbacks = []; - util.ScriptNodeDataSource._nId = 0; - } - - // ID for this request - var id = util.ScriptNodeDataSource._nId; - util.ScriptNodeDataSource._nId++; - - // Dynamically add handler function with a closure to the callback stack - var oSelf = this; - util.ScriptNodeDataSource.callbacks[id] = function(oRawResponse) { - if((oSelf.asyncMode !== "ignoreStaleResponses")|| - (id === util.ScriptNodeDataSource.callbacks.length-1)) { // Must ignore stale responses - - // Try to sniff data type if it has not been defined - if(oSelf.responseType === DS.TYPE_UNKNOWN) { - if(YAHOO.lang.isArray(oRawResponse)) { // array - oSelf.responseType = DS.TYPE_JSARRAY; - } - // xml - else if(oRawResponse.nodeType && oRawResponse.nodeType == 9) { - oSelf.responseType = DS.TYPE_XML; - } - else if(oRawResponse.nodeName && (oRawResponse.nodeName.toLowerCase() == "table")) { // table - oSelf.responseType = DS.TYPE_HTMLTABLE; - } - else if(YAHOO.lang.isObject(oRawResponse)) { // json - oSelf.responseType = DS.TYPE_JSON; - } - else if(YAHOO.lang.isString(oRawResponse)) { // text - oSelf.responseType = DS.TYPE_TEXT; - } - } - - oSelf.handleResponse(oRequest, oRawResponse, oCallback, oCaller, tId); - } - else { - } - - delete util.ScriptNodeDataSource.callbacks[id]; - }; - - // We are now creating a request - util.ScriptNodeDataSource._nPending++; - var sUri = this.liveData + oRequest + this.generateRequestCallback(id); - sUri = this.doBeforeGetScriptNode(sUri); - this.getUtility.script(sUri, - {autopurge: true, - onsuccess: util.ScriptNodeDataSource._bumpPendingDown, - onfail: util.ScriptNodeDataSource._bumpPendingDown}); - - return tId; -} - -}); - -// Copy static members to ScriptNodeDataSource class -lang.augmentObject(util.ScriptNodeDataSource, DS); - -// Copy static members to ScriptNodeDataSource class -lang.augmentObject(util.ScriptNodeDataSource, { - -///////////////////////////////////////////////////////////////////////////// -// -// ScriptNodeDataSource private static properties -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Unique ID to track requests. - * - * @property _nId - * @type Number - * @private - * @static - */ -_nId : 0, - -/** - * Counter for pending requests. When this is 0, it is safe to purge callbacks - * array. - * - * @property _nPending - * @type Number - * @private - * @static - */ -_nPending : 0, - -/** - * Global array of callback functions, one for each request sent. - * - * @property callbacks - * @type Function[] - * @static - */ -callbacks : [] - -}); - - - - - - - - - - - - - - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -/** - * XHRDataSource class for accessing remote data via the YUI Connection Manager - * Utility - * - * @namespace YAHOO.util - * @class YAHOO.util.XHRDataSource - * @extends YAHOO.util.DataSourceBase - * @constructor - * @param oLiveData {HTMLElement} Pointer to live data. - * @param oConfigs {object} (optional) Object literal of configuration values. - */ -util.XHRDataSource = function(oLiveData, oConfigs) { - this.dataType = DS.TYPE_XHR; - this.connMgr = this.connMgr || util.Connect; - oLiveData = oLiveData || ""; - - util.XHRDataSource.superclass.constructor.call(this, oLiveData, oConfigs); -}; - -// XHRDataSource extends DataSourceBase -lang.extend(util.XHRDataSource, DS, { - -///////////////////////////////////////////////////////////////////////////// -// -// XHRDataSource public properties -// -///////////////////////////////////////////////////////////////////////////// - - /** - * Alias to YUI Connection Manager, to allow implementers to use a custom class. - * - * @property connMgr - * @type Object - * @default YAHOO.util.Connect - */ -connMgr: null, - - /** - * Defines request/response management in the following manner: - *
    - *
    queueRequests
    - *
    If a request is already in progress, wait until response is returned - * before sending the next request.
    - * - *
    cancelStaleRequests
    - *
    If a request is already in progress, cancel it before sending the next - * request.
    - * - *
    ignoreStaleResponses
    - *
    Send all requests, but handle only the response for the most recently - * sent request.
    - * - *
    allowAll
    - *
    Send all requests and handle all responses.
    - * - *
    - * - * @property connXhrMode - * @type String - * @default "allowAll" - */ -connXhrMode: "allowAll", - - /** - * True if data is to be sent via POST. By default, data will be sent via GET. - * - * @property connMethodPost - * @type Boolean - * @default false - */ -connMethodPost: false, - - /** - * The connection timeout defines how many milliseconds the XHR connection will - * wait for a server response. Any non-zero value will enable the Connection Manager's - * Auto-Abort feature. - * - * @property connTimeout - * @type Number - * @default 0 - */ -connTimeout: 0, - -///////////////////////////////////////////////////////////////////////////// -// -// XHRDataSource public methods -// -///////////////////////////////////////////////////////////////////////////// - -/** - * Overriding method passes query to Connection Manager. The returned - * response is then forwarded to the handleResponse function. - * - * @method makeConnection - * @param oRequest {Object} Request object. - * @param oCallback {Object} Callback object literal. - * @param oCaller {Object} (deprecated) Use oCallback.scope. - * @return {Number} Transaction ID. - */ -makeConnection : function(oRequest, oCallback, oCaller) { - - var oRawResponse = null; - var tId = DS._nTransactionId++; - this.fireEvent("requestEvent", {tId:tId,request:oRequest,callback:oCallback,caller:oCaller}); - - // Set up the callback object and - // pass the request in as a URL query and - // forward the response to the handler - var oSelf = this; - var oConnMgr = this.connMgr; - var oQueue = this._oQueue; - - /** - * Define Connection Manager success handler - * - * @method _xhrSuccess - * @param oResponse {Object} HTTPXMLRequest object - * @private - */ - var _xhrSuccess = function(oResponse) { - // If response ID does not match last made request ID, - // silently fail and wait for the next response - if(oResponse && (this.connXhrMode == "ignoreStaleResponses") && - (oResponse.tId != oQueue.conn.tId)) { - return null; - } - // Error if no response - else if(!oResponse) { - this.fireEvent("dataErrorEvent", {request:oRequest, response:null, - callback:oCallback, caller:oCaller, - message:DS.ERROR_DATANULL}); - - // Send error response back to the caller with the error flag on - DS.issueCallback(oCallback,[oRequest, {error:true}], true, oCaller); - - return null; - } - // Forward to handler - else { - // Try to sniff data type if it has not been defined - if(this.responseType === DS.TYPE_UNKNOWN) { - var ctype = (oResponse.getResponseHeader) ? oResponse.getResponseHeader["Content-Type"] : null; - if(ctype) { - // xml - if(ctype.indexOf("text/xml") > -1) { - this.responseType = DS.TYPE_XML; - } - else if(ctype.indexOf("application/json") > -1) { // json - this.responseType = DS.TYPE_JSON; - } - else if(ctype.indexOf("text/plain") > -1) { // text - this.responseType = DS.TYPE_TEXT; - } - } - } - this.handleResponse(oRequest, oResponse, oCallback, oCaller, tId); - } - }; - - /** - * Define Connection Manager failure handler - * - * @method _xhrFailure - * @param oResponse {Object} HTTPXMLRequest object - * @private - */ - var _xhrFailure = function(oResponse) { - this.fireEvent("dataErrorEvent", {request:oRequest, response: oResponse, - callback:oCallback, caller:oCaller, - message:DS.ERROR_DATAINVALID}); - - // Backward compatibility - if(lang.isString(this.liveData) && lang.isString(oRequest) && - (this.liveData.lastIndexOf("?") !== this.liveData.length-1) && - (oRequest.indexOf("?") !== 0)){ - } - - // Send failure response back to the caller with the error flag on - oResponse = oResponse || {}; - oResponse.error = true; - DS.issueCallback(oCallback,[oRequest,oResponse],true, oCaller); - - return null; - }; - - /** - * Define Connection Manager callback object - * - * @property _xhrCallback - * @param oResponse {Object} HTTPXMLRequest object - * @private - */ - var _xhrCallback = { - success:_xhrSuccess, - failure:_xhrFailure, - scope: this - }; - - // Apply Connection Manager timeout - if(lang.isNumber(this.connTimeout)) { - _xhrCallback.timeout = this.connTimeout; - } - - // Cancel stale requests - if(this.connXhrMode == "cancelStaleRequests") { - // Look in queue for stale requests - if(oQueue.conn) { - if(oConnMgr.abort) { - oConnMgr.abort(oQueue.conn); - oQueue.conn = null; - } - else { - } - } - } - - // Get ready to send the request URL - if(oConnMgr && oConnMgr.asyncRequest) { - var sLiveData = this.liveData; - var isPost = this.connMethodPost; - var sMethod = (isPost) ? "POST" : "GET"; - // Validate request - var sUri = (isPost || !lang.isValue(oRequest)) ? sLiveData : sLiveData+oRequest; - var sRequest = (isPost) ? oRequest : null; - - // Send the request right away - if(this.connXhrMode != "queueRequests") { - oQueue.conn = oConnMgr.asyncRequest(sMethod, sUri, _xhrCallback, sRequest); - } - // Queue up then send the request - else { - // Found a request already in progress - if(oQueue.conn) { - var allRequests = oQueue.requests; - // Add request to queue - allRequests.push({request:oRequest, callback:_xhrCallback}); - - // Interval needs to be started - if(!oQueue.interval) { - oQueue.interval = setInterval(function() { - // Connection is in progress - if(oConnMgr.isCallInProgress(oQueue.conn)) { - return; - } - else { - // Send next request - if(allRequests.length > 0) { - // Validate request - sUri = (isPost || !lang.isValue(allRequests[0].request)) ? sLiveData : sLiveData+allRequests[0].request; - sRequest = (isPost) ? allRequests[0].request : null; - oQueue.conn = oConnMgr.asyncRequest(sMethod, sUri, allRequests[0].callback, sRequest); - - // Remove request from queue - allRequests.shift(); - } - // No more requests - else { - clearInterval(oQueue.interval); - oQueue.interval = null; - } - } - }, 50); - } - } - // Nothing is in progress - else { - oQueue.conn = oConnMgr.asyncRequest(sMethod, sUri, _xhrCallback, sRequest); - } - } - } - else { - // Send null response back to the caller with the error flag on - DS.issueCallback(oCallback,[oRequest,{error:true}],true,oCaller); - } - - return tId; -} - -}); - -// Copy static members to XHRDataSource class -lang.augmentObject(util.XHRDataSource, DS); - - - - - - - - - - - - - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -/** - * Factory class for creating a BaseDataSource subclass instance. The sublcass is - * determined by oLiveData's type, unless the dataType config is explicitly passed in. - * - * @namespace YAHOO.util - * @class YAHOO.util.DataSource - * @constructor - * @param oLiveData {HTMLElement} Pointer to live data. - * @param oConfigs {object} (optional) Object literal of configuration values. - */ -util.DataSource = function(oLiveData, oConfigs) { - oConfigs = oConfigs || {}; - - // Point to one of the subclasses, first by dataType if given, then by sniffing oLiveData type. - var dataType = oConfigs.dataType; - if(dataType) { - if(dataType == DS.TYPE_LOCAL) { - lang.augmentObject(util.DataSource, util.LocalDataSource); - return new util.LocalDataSource(oLiveData, oConfigs); - } - else if(dataType == DS.TYPE_XHR) { - lang.augmentObject(util.DataSource, util.XHRDataSource); - return new util.XHRDataSource(oLiveData, oConfigs); - } - else if(dataType == DS.TYPE_SCRIPTNODE) { - lang.augmentObject(util.DataSource, util.ScriptNodeDataSource); - return new util.ScriptNodeDataSource(oLiveData, oConfigs); - } - else if(dataType == DS.TYPE_JSFUNCTION) { - lang.augmentObject(util.DataSource, util.FunctionDataSource); - return new util.FunctionDataSource(oLiveData, oConfigs); - } - } - - if(YAHOO.lang.isString(oLiveData)) { // strings default to xhr - lang.augmentObject(util.DataSource, util.XHRDataSource); - return new util.XHRDataSource(oLiveData, oConfigs); - } - else if(YAHOO.lang.isFunction(oLiveData)) { - lang.augmentObject(util.DataSource, util.FunctionDataSource); - return new util.FunctionDataSource(oLiveData, oConfigs); - } - else { // ultimate default is local - lang.augmentObject(util.DataSource, util.LocalDataSource); - return new util.LocalDataSource(oLiveData, oConfigs); - } -}; - -// Copy static members to DataSource class -lang.augmentObject(util.DataSource, DS); - -})(); - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -/** - * The static Number class provides helper functions to deal with data of type - * Number. - * - * @namespace YAHOO.util - * @requires yahoo - * @class Number - * @static - */ - YAHOO.util.Number = { - - /** - * Takes a native JavaScript Number and formats to string for display to user. - * - * @method format - * @param nData {Number} Number. - * @param oConfig {Object} (Optional) Optional configuration values: - *
    - *
    prefix {String} - *
    String prepended before each number, like a currency designator "$"
    - *
    decimalPlaces {Number} - *
    Number of decimal places to round.
    - *
    decimalSeparator {String} - *
    Decimal separator
    - *
    thousandsSeparator {String} - *
    Thousands separator
    - *
    suffix {String} - *
    String appended after each number, like " items" (note the space)
    - *
    negativeFormat
    - *
    String used as a guide for how to indicate negative numbers. The first '#' character in the string will be replaced by the number. Default '-#'.
    - *
    - * @return {String} Formatted number for display. Note, the following values - * return as "": null, undefined, NaN, "". - */ - format : function(n, cfg) { - if (!isFinite(+n)) { - return ''; - } - - n = !isFinite(+n) ? 0 : +n; - cfg = YAHOO.lang.merge(YAHOO.util.Number.format.defaults, (cfg || {})); - - var neg = n < 0, absN = Math.abs(n), - places = cfg.decimalPlaces, - sep = cfg.thousandsSeparator, - s, bits, i; - - if (places < 0) { - // Get rid of the decimal info - s = absN - (absN % 1) + ''; - i = s.length + places; - - // avoid 123 vs decimalPlaces -4 (should return "0") - if (i > 0) { - // leverage toFixed by making 123 => 0.123 for the rounding - // operation, then add the appropriate number of zeros back on - s = Number('.' + s).toFixed(i).slice(2) + - new Array(s.length - i + 1).join('0'); - } else { - s = "0"; - } - } else { // There is a bug in IE's toFixed implementation: - // for n in {(-0.94, -0.5], [0.5, 0.94)} n.toFixed() returns 0 - // instead of -1 and 1. Manually handle that case. - s = absN < 1 && absN >= 0.5 && !places ? '1' : absN.toFixed(places); - } - - if (absN > 1000) { - bits = s.split(/\D/); - i = bits[0].length % 3 || 3; - - bits[0] = bits[0].slice(0,i) + - bits[0].slice(i).replace(/(\d{3})/g, sep + '$1'); - - s = bits.join(cfg.decimalSeparator); - } - - s = cfg.prefix + s + cfg.suffix; - - return neg ? cfg.negativeFormat.replace(/#/,s) : s; - } -}; -YAHOO.util.Number.format.defaults = { - decimalSeparator : '.', - decimalPlaces : null, - thousandsSeparator : '', - prefix : '', - suffix : '', - negativeFormat : '-#' -}; - - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -(function () { - -var xPad=function (x, pad, r) -{ - if(typeof r === 'undefined') - { - r=10; - } - for( ; parseInt(x, 10)1; r/=10) { - x = pad.toString() + x; - } - return x.toString(); -}; - - -/** - * The static Date class provides helper functions to deal with data of type Date. - * - * @namespace YAHOO.util - * @requires yahoo - * @class Date - * @static - */ - var Dt = { - formats: { - a: function (d, l) { return l.a[d.getDay()]; }, - A: function (d, l) { return l.A[d.getDay()]; }, - b: function (d, l) { return l.b[d.getMonth()]; }, - B: function (d, l) { return l.B[d.getMonth()]; }, - C: function (d) { return xPad(parseInt(d.getFullYear()/100, 10), 0); }, - d: ['getDate', '0'], - e: ['getDate', ' '], - g: function (d) { return xPad(parseInt(Dt.formats.G(d)%100, 10), 0); }, - G: function (d) { - var y = d.getFullYear(); - var V = parseInt(Dt.formats.V(d), 10); - var W = parseInt(Dt.formats.W(d), 10); - - if(W > V) { - y++; - } else if(W===0 && V>=52) { - y--; - } - - return y; - }, - H: ['getHours', '0'], - I: function (d) { var I=d.getHours()%12; return xPad(I===0?12:I, 0); }, - j: function (d) { - var gmd_1 = new Date('' + d.getFullYear() + '/1/1 GMT'); - var gmdate = new Date('' + d.getFullYear() + '/' + (d.getMonth()+1) + '/' + d.getDate() + ' GMT'); - var ms = gmdate - gmd_1; - var doy = parseInt(ms/60000/60/24, 10)+1; - return xPad(doy, 0, 100); - }, - k: ['getHours', ' '], - l: function (d) { var I=d.getHours()%12; return xPad(I===0?12:I, ' '); }, - m: function (d) { return xPad(d.getMonth()+1, 0); }, - M: ['getMinutes', '0'], - p: function (d, l) { return l.p[d.getHours() >= 12 ? 1 : 0 ]; }, - P: function (d, l) { return l.P[d.getHours() >= 12 ? 1 : 0 ]; }, - s: function (d, l) { return parseInt(d.getTime()/1000, 10); }, - S: ['getSeconds', '0'], - u: function (d) { var dow = d.getDay(); return dow===0?7:dow; }, - U: function (d) { - var doy = parseInt(Dt.formats.j(d), 10); - var rdow = 6-d.getDay(); - var woy = parseInt((doy+rdow)/7, 10); - return xPad(woy, 0); - }, - V: function (d) { - var woy = parseInt(Dt.formats.W(d), 10); - var dow1_1 = (new Date('' + d.getFullYear() + '/1/1')).getDay(); - // First week is 01 and not 00 as in the case of %U and %W, - // so we add 1 to the final result except if day 1 of the year - // is a Monday (then %W returns 01). - // We also need to subtract 1 if the day 1 of the year is - // Friday-Sunday, so the resulting equation becomes: - var idow = woy + (dow1_1 > 4 || dow1_1 <= 1 ? 0 : 1); - if(idow === 53 && (new Date('' + d.getFullYear() + '/12/31')).getDay() < 4) - { - idow = 1; - } - else if(idow === 0) - { - idow = Dt.formats.V(new Date('' + (d.getFullYear()-1) + '/12/31')); - } - - return xPad(idow, 0); - }, - w: 'getDay', - W: function (d) { - var doy = parseInt(Dt.formats.j(d), 10); - var rdow = 7-Dt.formats.u(d); - var woy = parseInt((doy+rdow)/7, 10); - return xPad(woy, 0, 10); - }, - y: function (d) { return xPad(d.getFullYear()%100, 0); }, - Y: 'getFullYear', - z: function (d) { - var o = d.getTimezoneOffset(); - var H = xPad(parseInt(Math.abs(o/60), 10), 0); - var M = xPad(Math.abs(o%60), 0); - return (o>0?'-':'+') + H + M; - }, - Z: function (d) { - var tz = d.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/, '$2').replace(/[a-z ]/g, ''); - if(tz.length > 4) { - tz = Dt.formats.z(d); - } - return tz; - }, - '%': function (d) { return '%'; } - }, - - aggregates: { - c: 'locale', - D: '%m/%d/%y', - F: '%Y-%m-%d', - h: '%b', - n: '\n', - r: 'locale', - R: '%H:%M', - t: '\t', - T: '%H:%M:%S', - x: 'locale', - X: 'locale' - //'+': '%a %b %e %T %Z %Y' - }, - - /** - * Takes a native JavaScript Date and formats to string for display to user. - * - * @method format - * @param oDate {Date} Date. - * @param oConfig {Object} (Optional) Object literal of configuration values: - *
    - *
    format <String>
    - *
    - *

    - * Any strftime string is supported, such as "%I:%M:%S %p". strftime has several format specifiers defined by the Open group at - * http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html - *

    - *

    - * PHP added a few of its own, defined at http://www.php.net/strftime - *

    - *

    - * This javascript implementation supports all the PHP specifiers and a few more. The full list is below: - *

    - *
    - *
    %a
    abbreviated weekday name according to the current locale
    - *
    %A
    full weekday name according to the current locale
    - *
    %b
    abbreviated month name according to the current locale
    - *
    %B
    full month name according to the current locale
    - *
    %c
    preferred date and time representation for the current locale
    - *
    %C
    century number (the year divided by 100 and truncated to an integer, range 00 to 99)
    - *
    %d
    day of the month as a decimal number (range 01 to 31)
    - *
    %D
    same as %m/%d/%y
    - *
    %e
    day of the month as a decimal number, a single digit is preceded by a space (range ' 1' to '31')
    - *
    %F
    same as %Y-%m-%d (ISO 8601 date format)
    - *
    %g
    like %G, but without the century
    - *
    %G
    The 4-digit year corresponding to the ISO week number
    - *
    %h
    same as %b
    - *
    %H
    hour as a decimal number using a 24-hour clock (range 00 to 23)
    - *
    %I
    hour as a decimal number using a 12-hour clock (range 01 to 12)
    - *
    %j
    day of the year as a decimal number (range 001 to 366)
    - *
    %k
    hour as a decimal number using a 24-hour clock (range 0 to 23); single digits are preceded by a blank. (See also %H.)
    - *
    %l
    hour as a decimal number using a 12-hour clock (range 1 to 12); single digits are preceded by a blank. (See also %I.)
    - *
    %m
    month as a decimal number (range 01 to 12)
    - *
    %M
    minute as a decimal number
    - *
    %n
    newline character
    - *
    %p
    either `AM' or `PM' according to the given time value, or the corresponding strings for the current locale
    - *
    %P
    like %p, but lower case
    - *
    %r
    time in a.m. and p.m. notation equal to %I:%M:%S %p
    - *
    %R
    time in 24 hour notation equal to %H:%M
    - *
    %s
    number of seconds since the Epoch, ie, since 1970-01-01 00:00:00 UTC
    - *
    %S
    second as a decimal number
    - *
    %t
    tab character
    - *
    %T
    current time, equal to %H:%M:%S
    - *
    %u
    weekday as a decimal number [1,7], with 1 representing Monday
    - *
    %U
    week number of the current year as a decimal number, starting with the - * first Sunday as the first day of the first week
    - *
    %V
    The ISO 8601:1988 week number of the current year as a decimal number, - * range 01 to 53, where week 1 is the first week that has at least 4 days - * in the current year, and with Monday as the first day of the week.
    - *
    %w
    day of the week as a decimal, Sunday being 0
    - *
    %W
    week number of the current year as a decimal number, starting with the - * first Monday as the first day of the first week
    - *
    %x
    preferred date representation for the current locale without the time
    - *
    %X
    preferred time representation for the current locale without the date
    - *
    %y
    year as a decimal number without a century (range 00 to 99)
    - *
    %Y
    year as a decimal number including the century
    - *
    %z
    numerical time zone representation
    - *
    %Z
    time zone name or abbreviation
    - *
    %%
    a literal `%' character
    - *
    - *
    - *
    - * @param sLocale {String} (Optional) The locale to use when displaying days of week, - * months of the year, and other locale specific strings. The following locales are - * built in: - *
    - *
    en
    - *
    English
    - *
    en-US
    - *
    US English
    - *
    en-GB
    - *
    British English
    - *
    en-AU
    - *
    Australian English (identical to British English)
    - *
    - * More locales may be added by subclassing of YAHOO.util.DateLocale. - * See YAHOO.util.DateLocale for more information. - * @return {String} Formatted date for display. - * @sa YAHOO.util.DateLocale - */ - format : function (oDate, oConfig, sLocale) { - oConfig = oConfig || {}; - - if(!(oDate instanceof Date)) { - return YAHOO.lang.isValue(oDate) ? oDate : ""; - } - - var format = oConfig.format || "%m/%d/%Y"; - - // Be backwards compatible, support strings that are - // exactly equal to YYYY/MM/DD, DD/MM/YYYY and MM/DD/YYYY - if(format === 'YYYY/MM/DD') { - format = '%Y/%m/%d'; - } else if(format === 'DD/MM/YYYY') { - format = '%d/%m/%Y'; - } else if(format === 'MM/DD/YYYY') { - format = '%m/%d/%Y'; - } - // end backwards compatibility block - - sLocale = sLocale || "en"; - - // Make sure we have a definition for the requested locale, or default to en. - if(!(sLocale in YAHOO.util.DateLocale)) { - if(sLocale.replace(/-[a-zA-Z]+$/, '') in YAHOO.util.DateLocale) { - sLocale = sLocale.replace(/-[a-zA-Z]+$/, ''); - } else { - sLocale = "en"; - } - } - - var aLocale = YAHOO.util.DateLocale[sLocale]; - - var replace_aggs = function (m0, m1) { - var f = Dt.aggregates[m1]; - return (f === 'locale' ? aLocale[m1] : f); - }; - - var replace_formats = function (m0, m1) { - var f = Dt.formats[m1]; - if(typeof f === 'string') { // string => built in date function - return oDate[f](); - } else if(typeof f === 'function') { // function => our own function - return f.call(oDate, oDate, aLocale); - } else if(typeof f === 'object' && typeof f[0] === 'string') { // built in function with padding - return xPad(oDate[f[0]](), f[1]); - } else { - return m1; - } - }; - - // First replace aggregates (run in a loop because an agg may be made up of other aggs) - while(format.match(/%[cDFhnrRtTxX]/)) { - format = format.replace(/%([cDFhnrRtTxX])/g, replace_aggs); - } - - // Now replace formats (do not run in a loop otherwise %%a will be replace with the value of %a) - var str = format.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g, replace_formats); - - replace_aggs = replace_formats = undefined; - - return str; - } - }; - - YAHOO.namespace("YAHOO.util"); - YAHOO.util.Date = Dt; - -/** - * The DateLocale class is a container and base class for all - * localised date strings used by YAHOO.util.Date. It is used - * internally, but may be extended to provide new date localisations. - * - * To create your own DateLocale, follow these steps: - *
      - *
    1. Find an existing locale that matches closely with your needs
    2. - *
    3. Use this as your base class. Use YAHOO.util.DateLocale if nothing - * matches.
    4. - *
    5. Create your own class as an extension of the base class using - * YAHOO.lang.merge, and add your own localisations where needed.
    6. - *
    - * See the YAHOO.util.DateLocale['en-US'] and YAHOO.util.DateLocale['en-GB'] - * classes which extend YAHOO.util.DateLocale['en']. - * - * For example, to implement locales for French french and Canadian french, - * we would do the following: - *
      - *
    1. For French french, we have no existing similar locale, so use - * YAHOO.util.DateLocale as the base, and extend it: - *
      - *      YAHOO.util.DateLocale['fr'] = YAHOO.lang.merge(YAHOO.util.DateLocale, {
      - *          a: ['dim', 'lun', 'mar', 'mer', 'jeu', 'ven', 'sam'],
      - *          A: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
      - *          b: ['jan', 'fév', 'mar', 'avr', 'mai', 'jun', 'jui', 'aoû', 'sep', 'oct', 'nov', 'déc'],
      - *          B: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],
      - *          c: '%a %d %b %Y %T %Z',
      - *          p: ['', ''],
      - *          P: ['', ''],
      - *          x: '%d.%m.%Y',
      - *          X: '%T'
      - *      });
      - *   
      - *
    2. - *
    3. For Canadian french, we start with French french and change the meaning of \%x: - *
      - *      YAHOO.util.DateLocale['fr-CA'] = YAHOO.lang.merge(YAHOO.util.DateLocale['fr'], {
      - *          x: '%Y-%m-%d'
      - *      });
      - *   
      - *
    4. - *
    - * - * With that, you can use your new locales: - *
    - *    var d = new Date("2008/04/22");
    - *    YAHOO.util.Date.format(d, {format: "%A, %d %B == %x"}, "fr");
    - * 
    - * will return: - *
    - *    mardi, 22 avril == 22.04.2008
    - * 
    - * And - *
    - *    YAHOO.util.Date.format(d, {format: "%A, %d %B == %x"}, "fr-CA");
    - * 
    - * Will return: - *
    - *   mardi, 22 avril == 2008-04-22
    - * 
    - * @namespace YAHOO.util - * @requires yahoo - * @class DateLocale - */ - YAHOO.util.DateLocale = { - a: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], - A: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], - b: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - B: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], - c: '%a %d %b %Y %T %Z', - p: ['AM', 'PM'], - P: ['am', 'pm'], - r: '%I:%M:%S %p', - x: '%d/%m/%y', - X: '%T' - }; - - YAHOO.util.DateLocale['en'] = YAHOO.lang.merge(YAHOO.util.DateLocale, {}); - - YAHOO.util.DateLocale['en-US'] = YAHOO.lang.merge(YAHOO.util.DateLocale['en'], { - c: '%a %d %b %Y %I:%M:%S %p %Z', - x: '%m/%d/%Y', - X: '%I:%M:%S %p' - }); - - YAHOO.util.DateLocale['en-GB'] = YAHOO.lang.merge(YAHOO.util.DateLocale['en'], { - r: '%l:%M:%S %P %Z' - }); - YAHOO.util.DateLocale['en-AU'] = YAHOO.lang.merge(YAHOO.util.DateLocale['en']); - -})(); - -YAHOO.register("datasource", YAHOO.util.DataSource, {version: "2.8.0r4", build: "2449"}); -- 1.7.2.5