]> git.wh0rd.org - tt-rss.git/blame - lib/dijit/form/FilteringSelect.js.uncompressed.js
modify dojo rebuild script to remove uncompressed files
[tt-rss.git] / lib / dijit / form / FilteringSelect.js.uncompressed.js
CommitLineData
f0cfe83e
AD
1define("dijit/form/FilteringSelect", [
2 "dojo/data/util/filter", // filter.patternToRegExp
3 "dojo/_base/declare", // declare
4 "dojo/_base/lang", // lang.mixin
5 "dojo/when",
6 "./MappedTextBox",
7 "./ComboBoxMixin"
8], function(filter, declare, lang, when, MappedTextBox, ComboBoxMixin){
9
10 // module:
11 // dijit/form/FilteringSelect
12
13 return declare("dijit.form.FilteringSelect", [MappedTextBox, ComboBoxMixin], {
14 // summary:
15 // An enhanced version of the HTML SELECT tag, populated dynamically
16 //
17 // description:
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.
26 //
27 // Similar features:
28 //
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)
34 //
35 // Enhancements over plain HTML version:
36 //
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)
41
42 // required: Boolean
43 // True (default) if user is required to enter a value into this field.
44 required: true,
45
46 _lastDisplayedValue: "",
47
48 _isValidSubset: function(){
49 return this._opened;
50 },
51
52 isValid: function(){
53 // Overrides ValidationTextBox.isValid()
54 return !!this.item || (!this.required && this.get('displayedValue') == ""); // #5974
55 },
56
57 _refreshState: function(){
58 if(!this.searchTimer){ // state will be refreshed after results are returned
59 this.inherited(arguments);
60 }
61 },
62
63 _callbackSetLabel: function(
64 /*Array*/ result,
65 /*Object*/ query,
66 /*Object*/ options,
67 /*Boolean?*/ priorityChange){
68 // summary:
69 // Callback from dojo.store after lookup of user entered value finishes
70
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)){
76 return;
77 }
78 if(!result.length){
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);
82 }else{
83 this.set('item', result[0], priorityChange);
84 }
85 },
86
87 _openResultList: function(/*Object*/ results, /*Object*/ query, /*Object*/ options){
88 // Callback when a data store query completes.
89 // Overrides ComboBox._openResultList()
90
91 // #3285: tap into search callback to see if user's query resembles a match
92 if(query[this.searchAttr] !== this._lastQuery){
93 return;
94 }
95 this.inherited(arguments);
96
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
101 this.validate(true);
102 }
103 },
104
105 _getValueAttr: function(){
106 // summary:
107 // Hook for get('value') to work.
108
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;
112 },
113
114 _getValueField: function(){
115 // Overrides ComboBox._getValueField()
116 return "value";
117 },
118
119 _setValueAttr: function(/*String*/ value, /*Boolean?*/ priorityChange, /*String?*/ displayedValue, /*item?*/ item){
120 // summary:
121 // Hook so set('value', value) works.
122 // description:
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; }
126
127 if(item === undefined){
128 if(value === null || value === ''){
129 value = '';
130 if(!lang.isString(displayedValue)){
131 this._setDisplayedValueAttr(displayedValue||'', priorityChange);
132 return;
133 }
134 }
135
136 var self = this;
137 this._lastQuery = value;
138 when(this.store.get(value), function(item){
139 self._callbackSetLabel(item? [item] : [], undefined, undefined, priorityChange);
140 });
141 }else{
142 this.valueNode.value = value;
143 this.inherited(arguments);
144 }
145 },
146
147 _setItemAttr: function(/*item*/ item, /*Boolean?*/ priorityChange, /*String?*/ displayedValue){
148 // summary:
149 // Set the displayed valued in the input box, and the hidden value
150 // that gets submitted, based on a dojo.data store item.
151 // description:
152 // Users shouldn't call this function; they should be calling
153 // set('item', value)
154 // tags:
155 // private
156 this.inherited(arguments);
157 this._lastDisplayedValue = this.textbox.value;
158 },
159
160 _getDisplayQueryString: function(/*String*/ text){
161 return text.replace(/([\\\*\?])/g, "\\$1");
162 },
163
164 _setDisplayedValueAttr: function(/*String*/ label, /*Boolean?*/ priorityChange){
165 // summary:
166 // Hook so set('displayedValue', label) works.
167 // description:
168 // Sets textbox to display label. Also performs reverse lookup
169 // to set the hidden value. label should corresponding to item.searchAttr.
170
171 if(label == null){ label = ''; }
172
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
177 if(!this._created){
178 if(!("displayedValue" in this.params)){
179 return;
180 }
181 priorityChange = false;
182 }
183
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
186 if(this.store){
187 this.closeDropDown();
188 var query = lang.clone(this.query); // #6196: populate query with user-specifics
189
190 // Generate query
191 var qs = this._getDisplayQueryString(label), q;
192 if(this.store._oldAPI){
193 // remove this branch for 2.0
194 q = qs;
195 }else{
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; };
201 }
202 this._lastQuery = query[this.searchAttr] = q;
203
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
207 // sense to the user
208 this.textbox.value = label;
209 this._lastDisplayedValue = label;
210 this._set("displayedValue", label); // for watch("displayedValue") notification
211 var _this = this;
212 var options = {
213 ignoreCase: this.ignoreCase,
214 deep: true
215 };
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);
221 }, function(err){
222 _this._fetchHandle = null;
223 if(!_this._cancelingQuery){ // don't treat canceled query as an error
224 console.error('dijit.form.FilteringSelect: ' + err.toString());
225 }
226 });
227 }
228 },
229
230 undo: function(){
231 this.set('displayedValue', this._lastDisplayedValue);
232 }
233 });
234});