]>
git.wh0rd.org - tt-rss.git/blob - lib/dijit/form/FilteringSelect.js.uncompressed.js
1 define("dijit/form/FilteringSelect", [
2 "dojo/data/util/filter", // filter.patternToRegExp
3 "dojo/_base/declare", // declare
4 "dojo/_base/lang", // lang.mixin
8 ], function(filter
, declare
, lang
, when
, MappedTextBox
, ComboBoxMixin
){
11 // dijit/form/FilteringSelect
13 return declare("dijit.form.FilteringSelect", [MappedTextBox
, ComboBoxMixin
], {
15 // An enhanced version of the HTML SELECT tag, populated dynamically
18 // An enhanced version of the HTML SELECT tag, populated dynamically. It works
19 // very nicely with very large data sets because it can load and page data as needed.
20 // It also resembles ComboBox, but does not allow values outside of the provided ones.
21 // If OPTION tags are used as the data provider via markup, then the
22 // OPTION tag's child text node is used as the displayed value when selected
23 // while the OPTION tag's value attribute is used as the widget value on form submit.
24 // To set the default value when using OPTION tags, specify the selected
25 // attribute on 1 of the child OPTION tags.
29 // - There is a drop down list of possible values.
30 // - You can only enter a value from the drop down list. (You can't
31 // enter an arbitrary value.)
32 // - The value submitted with the form is the hidden value (ex: CA),
33 // not the displayed value a.k.a. label (ex: California)
35 // Enhancements over plain HTML version:
37 // - If you type in some text then it will filter down the list of
38 // possible values in the drop down list.
39 // - List can be specified either as a static list or via a javascript
40 // function (that can get the list from a server)
43 // True (default) if user is required to enter a value into this field.
46 _lastDisplayedValue
: "",
48 _isValidSubset: function(){
53 // Overrides ValidationTextBox.isValid()
54 return !!this.item
|| (!this.required
&& this.get('displayedValue') == ""); // #5974
57 _refreshState: function(){
58 if(!this.searchTimer
){ // state will be refreshed after results are returned
59 this.inherited(arguments
);
63 _callbackSetLabel: function(
67 /*Boolean?*/ priorityChange
){
69 // Callback from dojo.store after lookup of user entered value finishes
71 // setValue does a synchronous lookup,
72 // so it calls _callbackSetLabel directly,
73 // and so does not pass dataObject
74 // still need to test against _lastQuery in case it came too late
75 if((query
&& query
[this.searchAttr
] !== this._lastQuery
) || (!query
&& result
.length
&& this.store
.getIdentity(result
[0]) != this._lastQuery
)){
79 //#3268: don't modify display value on bad input
80 //#3285: change CSS to indicate error
81 this.set("value", '', priorityChange
|| (priorityChange
=== undefined && !this.focused
), this.textbox
.value
, null);
83 this.set('item', result
[0], priorityChange
);
87 _openResultList: function(/*Object*/ results
, /*Object*/ query
, /*Object*/ options
){
88 // Callback when a data store query completes.
89 // Overrides ComboBox._openResultList()
91 // #3285: tap into search callback to see if user's query resembles a match
92 if(query
[this.searchAttr
] !== this._lastQuery
){
95 this.inherited(arguments
);
97 if(this.item
=== undefined){ // item == undefined for keyboard search
98 // If the search returned no items that means that the user typed
99 // in something invalid (and they can't make it valid by typing more characters),
100 // so flag the FilteringSelect as being in an invalid state
105 _getValueAttr: function(){
107 // Hook for get('value') to work.
109 // don't get the textbox value but rather the previously set hidden value.
110 // Use this.valueNode.value which isn't always set for other MappedTextBox widgets until blur
111 return this.valueNode
.value
;
114 _getValueField: function(){
115 // Overrides ComboBox._getValueField()
119 _setValueAttr: function(/*String*/ value
, /*Boolean?*/ priorityChange
, /*String?*/ displayedValue
, /*item?*/ item
){
121 // Hook so set('value', value) works.
123 // Sets the value of the select.
124 // Also sets the label to the corresponding value by reverse lookup.
125 if(!this._onChangeActive
){ priorityChange
= null; }
127 if(item
=== undefined){
128 if(value
=== null || value
=== ''){
130 if(!lang
.isString(displayedValue
)){
131 this._setDisplayedValueAttr(displayedValue
||'', priorityChange
);
137 this._lastQuery
= value
;
138 when(this.store
.get(value
), function(item
){
139 self
._callbackSetLabel(item
? [item
] : [], undefined, undefined, priorityChange
);
142 this.valueNode
.value
= value
;
143 this.inherited(arguments
);
147 _setItemAttr: function(/*item*/ item
, /*Boolean?*/ priorityChange
, /*String?*/ displayedValue
){
149 // Set the displayed valued in the input box, and the hidden value
150 // that gets submitted, based on a dojo.data store item.
152 // Users shouldn't call this function; they should be calling
153 // set('item', value)
156 this.inherited(arguments
);
157 this._lastDisplayedValue
= this.textbox
.value
;
160 _getDisplayQueryString: function(/*String*/ text
){
161 return text
.replace(/([\\\*\?])/g, "\\$1");
164 _setDisplayedValueAttr: function(/*String*/ label
, /*Boolean?*/ priorityChange
){
166 // Hook so set('displayedValue', label) works.
168 // Sets textbox to display label. Also performs reverse lookup
169 // to set the hidden value. label should corresponding to item.searchAttr.
171 if(label
== null){ label
= ''; }
173 // This is called at initialization along with every custom setter.
174 // Usually (or always?) the call can be ignored. If it needs to be
175 // processed then at least make sure that the XHR request doesn't trigger an onChange()
176 // event, even if it returns after creation has finished
178 if(!("displayedValue" in this.params
)){
181 priorityChange
= false;
184 // Do a reverse lookup to map the specified displayedValue to the hidden value.
185 // Note that if there's a custom labelFunc() this code
187 this.closeDropDown();
188 var query
= lang
.clone(this.query
); // #6196: populate query with user-specifics
191 var qs
= this._getDisplayQueryString(label
), q
;
192 if(this.store
._oldAPI
){
193 // remove this branch for 2.0
196 // Query on searchAttr is a regex for benefit of dojo/store/Memory,
197 // but with a toString() method to help dojo/store/JsonRest.
198 // Search string like "Co*" converted to regex like /^Co.*$/i.
199 q
= filter
.patternToRegExp(qs
, this.ignoreCase
);
200 q
.toString = function(){ return qs
; };
202 this._lastQuery
= query
[this.searchAttr
] = q
;
204 // If the label is not valid, the callback will never set it,
205 // so the last valid value will get the warning textbox. Set the
206 // textbox value now so that the impending warning will make
208 this.textbox
.value
= label
;
209 this._lastDisplayedValue
= label
;
210 this._set("displayedValue", label
); // for watch("displayedValue") notification
213 ignoreCase
: this.ignoreCase
,
216 lang
.mixin(options
, this.fetchProperties
);
217 this._fetchHandle
= this.store
.query(query
, options
);
218 when(this._fetchHandle
, function(result
){
219 _this
._fetchHandle
= null;
220 _this
._callbackSetLabel(result
|| [], query
, options
, priorityChange
);
222 _this
._fetchHandle
= null;
223 if(!_this
._cancelingQuery
){ // don't treat canceled query as an error
224 console
.error('dijit.form.FilteringSelect: ' + err
.toString());
231 this.set('displayedValue', this._lastDisplayedValue
);