From 81bea17aefb26859f825b9293c7c99192874806e Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Tue, 8 Nov 2011 20:40:44 +0400 Subject: upgrade Dojo to 1.6.1 --- lib/dijit/form/FilteringSelect.js | 301 +++++++++++++++++++++++++++----------- 1 file changed, 218 insertions(+), 83 deletions(-) (limited to 'lib/dijit/form/FilteringSelect.js') diff --git a/lib/dijit/form/FilteringSelect.js b/lib/dijit/form/FilteringSelect.js index 08703226c..81b44ff3b 100644 --- a/lib/dijit/form/FilteringSelect.js +++ b/lib/dijit/form/FilteringSelect.js @@ -1,92 +1,227 @@ /* - Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ -if(!dojo._hasResource["dijit.form.FilteringSelect"]){ -dojo._hasResource["dijit.form.FilteringSelect"]=true; +if(!dojo._hasResource["dijit.form.FilteringSelect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit.form.FilteringSelect"] = true; dojo.provide("dijit.form.FilteringSelect"); dojo.require("dijit.form.ComboBox"); -dojo.declare("dijit.form.FilteringSelect",[dijit.form.MappedTextBox,dijit.form.ComboBoxMixin],{_isvalid:true,required:true,_lastDisplayedValue:"",isValid:function(){ -return this._isvalid||(!this.required&&this.get("displayedValue")==""); -},_refreshState:function(){ -if(!this.searchTimer){ -this.inherited(arguments); -} -},_callbackSetLabel:function(_1,_2,_3){ -if((_2&&_2.query[this.searchAttr]!=this._lastQuery)||(!_2&&_1.length&&this.store.getIdentity(_1[0])!=this._lastQuery)){ -return; -} -if(!_1.length){ -this.valueNode.value=""; -dijit.form.TextBox.superclass._setValueAttr.call(this,"",_3||(_3===undefined&&!this._focused)); -this._isvalid=false; -this.validate(this._focused); -this.item=null; -}else{ -this.set("item",_1[0],_3); -} -},_openResultList:function(_4,_5){ -if(_5.query[this.searchAttr]!=this._lastQuery){ -return; -} -if(this.item===undefined){ -this._isvalid=_4.length!=0||this._maxOptions!=0; -this.validate(true); -} -dijit.form.ComboBoxMixin.prototype._openResultList.apply(this,arguments); -},_getValueAttr:function(){ -return this.valueNode.value; -},_getValueField:function(){ -return "value"; -},_setValueAttr:function(_6,_7){ -if(!this._onChangeActive){ -_7=null; -} -this._lastQuery=_6; -if(_6===null||_6===""){ -this._setDisplayedValueAttr("",_7); -return; -} -var _8=this; -this.store.fetchItemByIdentity({identity:_6,onItem:function(_9){ -_8._callbackSetLabel(_9?[_9]:[],undefined,_7); -}}); -},_setItemAttr:function(_a,_b,_c){ -this._isvalid=true; -this.inherited(arguments); -this.valueNode.value=this.value; -this._lastDisplayedValue=this.textbox.value; -},_getDisplayQueryString:function(_d){ -return _d.replace(/([\\\*\?])/g,"\\$1"); -},_setDisplayedValueAttr:function(_e,_f){ -if(!this._created){ -_f=false; -} -if(this.store){ -this._hideResultList(); -var _10=dojo.clone(this.query); -this._lastQuery=_10[this.searchAttr]=this._getDisplayQueryString(_e); -this.textbox.value=_e; -this._lastDisplayedValue=_e; -var _11=this; -var _12={query:_10,queryOptions:{ignoreCase:this.ignoreCase,deep:true},onComplete:function(_13,_14){ -_11._fetchHandle=null; -dojo.hitch(_11,"_callbackSetLabel")(_13,_14,_f); -},onError:function(_15){ -_11._fetchHandle=null; -console.error("dijit.form.FilteringSelect: "+_15); -dojo.hitch(_11,"_callbackSetLabel")([],undefined,false); -}}; -dojo.mixin(_12,this.fetchProperties); -this._fetchHandle=this.store.fetch(_12); -} -},postMixInProperties:function(){ -this.inherited(arguments); -this._isvalid=!this.required; -},undo:function(){ -this.set("displayedValue",this._lastDisplayedValue); -}}); + + +dojo.declare( + "dijit.form.FilteringSelect", + [dijit.form.MappedTextBox, dijit.form.ComboBoxMixin], + { + // summary: + // An enhanced version of the HTML SELECT tag, populated dynamically + // + // description: + // An enhanced version of the HTML SELECT tag, populated dynamically. It works + // very nicely with very large data sets because it can load and page data as needed. + // It also resembles ComboBox, but does not allow values outside of the provided ones. + // If OPTION tags are used as the data provider via markup, then the + // OPTION tag's child text node is used as the displayed value when selected + // while the OPTION tag's value attribute is used as the widget value on form submit. + // To set the default value when using OPTION tags, specify the selected + // attribute on 1 of the child OPTION tags. + // + // Similar features: + // - There is a drop down list of possible values. + // - You can only enter a value from the drop down list. (You can't + // enter an arbitrary value.) + // - The value submitted with the form is the hidden value (ex: CA), + // not the displayed value a.k.a. label (ex: California) + // + // Enhancements over plain HTML version: + // - If you type in some text then it will filter down the list of + // possible values in the drop down list. + // - List can be specified either as a static list or via a javascript + // function (that can get the list from a server) + + // required: Boolean + // True (default) if user is required to enter a value into this field. + required: true, + + _lastDisplayedValue: "", + + _isValidSubset: function(){ + return this._opened; + }, + + isValid: function(){ + // Overrides ValidationTextBox.isValid() + return this.item || (!this.required && this.get('displayedValue') == ""); // #5974 + }, + + _refreshState: function(){ + if(!this.searchTimer){ // state will be refreshed after results are returned + this.inherited(arguments); + } + }, + + _callbackSetLabel: function( + /*Array*/ result, + /*Object*/ dataObject, + /*Boolean?*/ priorityChange){ + // summary: + // Callback from dojo.data after lookup of user entered value finishes + + // setValue does a synchronous lookup, + // so it calls _callbackSetLabel directly, + // and so does not pass dataObject + // still need to test against _lastQuery in case it came too late + if((dataObject && dataObject.query[this.searchAttr] != this._lastQuery) || (!dataObject && result.length && this.store.getIdentity(result[0]) != this._lastQuery)){ + return; + } + if(!result.length){ + //#3268: don't modify display value on bad input + //#3285: change CSS to indicate error + this.valueNode.value = ""; + dijit.form.TextBox.superclass._setValueAttr.call(this, "", priorityChange || (priorityChange === undefined && !this._focused)); + this._set("item", null); + this.validate(this._focused); + }else{ + this.set('item', result[0], priorityChange); + } + }, + + _openResultList: function(/*Object*/ results, /*Object*/ dataObject){ + // Callback when a data store query completes. + // Overrides ComboBox._openResultList() + + // #3285: tap into search callback to see if user's query resembles a match + if(dataObject.query[this.searchAttr] != this._lastQuery){ + return; + } + dijit.form.ComboBoxMixin.prototype._openResultList.apply(this, arguments); + + if(this.item === undefined){ // item == undefined for keyboard search + // If the search returned no items that means that the user typed + // in something invalid (and they can't make it valid by typing more characters), + // so flag the FilteringSelect as being in an invalid state + this.validate(true); + } + }, + + _getValueAttr: function(){ + // summary: + // Hook for get('value') to work. + + // don't get the textbox value but rather the previously set hidden value. + // Use this.valueNode.value which isn't always set for other MappedTextBox widgets until blur + return this.valueNode.value; + }, + + _getValueField: function(){ + // Overrides ComboBox._getValueField() + return "value"; + }, + + _setValueAttr: function(/*String*/ value, /*Boolean?*/ priorityChange){ + // summary: + // Hook so set('value', value) works. + // description: + // Sets the value of the select. + // Also sets the label to the corresponding value by reverse lookup. + if(!this._onChangeActive){ priorityChange = null; } + this._lastQuery = value; + + if(value === null || value === ''){ + this._setDisplayedValueAttr('', priorityChange); + return; + } + + //#3347: fetchItemByIdentity if no keyAttr specified + var self = this; + this.store.fetchItemByIdentity({ + identity: value, + onItem: function(item){ + self._callbackSetLabel(item? [item] : [], undefined, priorityChange); + } + }); + }, + + _setItemAttr: function(/*item*/ item, /*Boolean?*/ priorityChange, /*String?*/ displayedValue){ + // summary: + // Set the displayed valued in the input box, and the hidden value + // that gets submitted, based on a dojo.data store item. + // description: + // Users shouldn't call this function; they should be calling + // set('item', value) + // tags: + // private + this.inherited(arguments); + this.valueNode.value = this.value; + this._lastDisplayedValue = this.textbox.value; + }, + + _getDisplayQueryString: function(/*String*/ text){ + return text.replace(/([\\\*\?])/g, "\\$1"); + }, + + _setDisplayedValueAttr: function(/*String*/ label, /*Boolean?*/ priorityChange){ + // summary: + // Hook so set('displayedValue', label) works. + // description: + // Sets textbox to display label. Also performs reverse lookup + // to set the hidden value. label should corresponding to item.searchAttr. + + if(label == null){ label = ''; } + + // This is called at initialization along with every custom setter. + // Usually (or always?) the call can be ignored. If it needs to be + // processed then at least make sure that the XHR request doesn't trigger an onChange() + // event, even if it returns after creation has finished + if(!this._created){ + if(!("displayedValue" in this.params)){ + return; + } + priorityChange = false; + } + + // Do a reverse lookup to map the specified displayedValue to the hidden value. + // Note that if there's a custom labelFunc() this code + if(this.store){ + this.closeDropDown(); + var query = dojo.clone(this.query); // #6196: populate query with user-specifics + // escape meta characters of dojo.data.util.filter.patternToRegExp(). + this._lastQuery = query[this.searchAttr] = this._getDisplayQueryString(label); + // If the label is not valid, the callback will never set it, + // so the last valid value will get the warning textbox. Set the + // textbox value now so that the impending warning will make + // sense to the user + this.textbox.value = label; + this._lastDisplayedValue = label; + this._set("displayedValue", label); // for watch("displayedValue") notification + var _this = this; + var fetch = { + query: query, + queryOptions: { + ignoreCase: this.ignoreCase, + deep: true + }, + onComplete: function(result, dataObject){ + _this._fetchHandle = null; + dojo.hitch(_this, "_callbackSetLabel")(result, dataObject, priorityChange); + }, + onError: function(errText){ + _this._fetchHandle = null; + console.error('dijit.form.FilteringSelect: ' + errText); + dojo.hitch(_this, "_callbackSetLabel")([], undefined, false); + } + }; + dojo.mixin(fetch, this.fetchProperties); + this._fetchHandle = this.store.fetch(fetch); + } + }, + + undo: function(){ + this.set('displayedValue', this._lastDisplayedValue); + } + } +); + } -- cgit v1.2.3