]>
git.wh0rd.org - tt-rss.git/blob - lib/dijit/form/_SearchMixin.js.uncompressed.js
1 define("dijit/form/_SearchMixin", [
2 "dojo/data/util/filter", // patternToRegExp
3 "dojo/_base/declare", // declare
4 "dojo/_base/event", // event.stop
6 "dojo/_base/lang", // lang.clone lang.hitch
8 "dojo/sniff", // has("ie")
9 "dojo/string", // string.substitute
11 "../registry" // registry.byId
12 ], function(filter
, declare
, event
, keys
, lang
, query
, has
, string
, when
, registry
){
15 // dijit/form/_SearchMixin
18 return declare("dijit.form._SearchMixin", null, {
20 // A mixin that implements the base functionality to search a store based upon user-entered text such as
21 // with `dijit/form/ComboBox` or `dijit/form/FilteringSelect`
26 // Argument to data provider.
27 // Specifies maximum number of search results to return per query
30 // store: [const] dojo/store/api/Store
31 // Reference to data provider object used by this ComboBox.
32 // The store must accept an object hash of properties for its query. See `query` and `queryExpr` for details.
35 // fetchProperties: Object
36 // Mixin to the store's fetch.
37 // For example, to set the sort order of the ComboBox menu, pass:
38 // | { sort: [{attribute:"name",descending: true}] }
39 // To override the default queryOptions so that deep=false, do:
40 // | { queryOptions: {ignoreCase: true, deep: false} }
44 // A query that can be passed to `store` to initially filter the items.
45 // ComboBox overwrites any reference to the `searchAttr` and sets it to the `queryExpr` with the user's input substituted.
48 // searchDelay: Integer
49 // Delay in milliseconds between when user types something and we start
50 // searching based on that value
54 // Search for items in the data store where this attribute (in the item)
55 // matches what the user typed
59 // This specifies what query is sent to the data store,
60 // based on what the user has typed. Changing this expression will modify
61 // whether the results are only exact matches, a "starting with" match,
63 // dojo.data query expression pattern.
64 // `${0}` will be substituted for the user text.
65 // `*` is used for wildcards.
66 // `${0}*` means "starts with", `*${0}*` means "contains", `${0}` means "is"
69 // ignoreCase: Boolean
70 // Set true if the query should ignore case when matching possible items
73 _abortQuery: function(){
74 // stop in-progress query
76 this.searchTimer
= this.searchTimer
.remove();
78 if(this._queryDeferHandle
){
79 this._queryDeferHandle
= this._queryDeferHandle
.remove();
81 if(this._fetchHandle
){
82 if(this._fetchHandle
.abort
){
83 this._cancelingQuery
= true;
84 this._fetchHandle
.abort();
85 this._cancelingQuery
= false;
87 if(this._fetchHandle
.cancel
){
88 this._cancelingQuery
= true;
89 this._fetchHandle
.cancel();
90 this._cancelingQuery
= false;
92 this._fetchHandle
= null;
96 _processInput: function(/*Event*/ evt
){
98 // Handles input (keyboard/paste) events
99 if(this.disabled
|| this.readOnly
){ return; }
100 var key
= evt
.charOrCode
;
102 // except for cutting/pasting case - ctrl + x/v
103 if(evt
.altKey
|| ((evt
.ctrlKey
|| evt
.metaKey
) && (key
!= 'x' && key
!= 'v')) || key
== keys
.SHIFT
){
104 return; // throw out weird key combinations and spurious events
107 var doSearch
= false;
108 this._prev_key_backspace
= false;
113 this._prev_key_backspace
= true;
114 this._maskValidSubsetError
= true;
119 // Non char keys (F1-F12 etc..) shouldn't start a search..
120 // Ascii characters and IME input (Chinese, Japanese etc.) should.
121 //IME input produces keycode == 229.
122 doSearch
= typeof key
== 'string' || key
== 229;
125 // need to wait a tad before start search so that the event
126 // bubbles through DOM and we have value visible
130 this.searchTimer
= this.defer("_startSearchFromInput", 1);
135 onSearch: function(/*===== results, query, options =====*/){
137 // Callback when a search completes.
140 // An array of items from the originating _SearchMixin's store.
143 // A copy of the originating _SearchMixin's query property.
146 // The additional parameters sent to the originating _SearchMixin's store, including: start, count, queryOptions.
152 _startSearchFromInput: function(){
153 this._startSearch(this.focusNode
.value
.replace(/([\\\*\?])/g, "\\$1"));
156 _startSearch: function(/*String*/ text
){
158 // Starts a search for elements matching text (text=="" means to return all items),
159 // and calls onSearch(...) when the search completes, to display the results.
164 // Setup parameters to be passed to store.query().
165 // Create a new query to prevent accidentally querying for a hidden
166 // value from FilteringSelect's keyField
167 query
= lang
.clone(this.query
), // #5970
170 count
: this.pageSize
,
171 queryOptions
: { // remove for 2.0
172 ignoreCase
: this.ignoreCase
,
176 qs
= string
.substitute(this.queryExpr
, [text
]),
178 startQuery = function(){
179 var resPromise
= _this
._fetchHandle
= _this
.store
.query(query
, options
);
180 if(_this
.disabled
|| _this
.readOnly
|| (q
!== _this
._lastQuery
)){
182 } // avoid getting unwanted notify
183 when(resPromise
, function(res
){
184 _this
._fetchHandle
= null;
185 if(!_this
.disabled
&& !_this
.readOnly
&& (q
=== _this
._lastQuery
)){ // avoid getting unwanted notify
186 when(resPromise
.total
, function(total
){
188 var pageSize
= _this
.pageSize
;
189 if(isNaN(pageSize
) || pageSize
> res
.total
){ pageSize
= res
.total
; }
190 // Setup method to fetching the next page of results
191 res
.nextPage = function(direction
){
192 // tell callback the direction of the paging so the screen
193 // reader knows which menu option to shout
194 options
.direction
= direction
= direction
!== false;
195 options
.count
= pageSize
;
197 options
.start
+= res
.length
;
198 if(options
.start
>= res
.total
){
202 options
.start
-= pageSize
;
203 if(options
.start
< 0){
204 options
.count
= Math
.max(pageSize
+ options
.start
, 0);
208 if(options
.count
<= 0){
210 _this
.onSearch(res
, query
, options
);
215 _this
.onSearch(res
, query
, options
);
219 _this
._fetchHandle
= null;
220 if(!_this
._cancelingQuery
){ // don't treat canceled query as an error
221 console
.error(_this
.declaredClass
+ ' ' + err
.toString());
226 lang
.mixin(options
, this.fetchProperties
);
229 if(this.store
._oldAPI
){
230 // remove this branch for 2.0
233 // Query on searchAttr is a regex for benefit of dojo/store/Memory,
234 // but with a toString() method to help dojo/store/JsonRest.
235 // Search string like "Co*" converted to regex like /^Co.*$/i.
236 q
= filter
.patternToRegExp(qs
, this.ignoreCase
);
237 q
.toString = function(){ return qs
; };
240 // set _lastQuery, *then* start the timeout
241 // otherwise, if the user types and the last query returns before the timeout,
242 // _lastQuery won't be set and their input gets rewritten
243 this._lastQuery
= query
[this.searchAttr
] = q
;
244 this._queryDeferHandle
= this.defer(startQuery
, this.searchDelay
);
247 //////////// INITIALIZATION METHODS ///////////////////////////////////////
249 constructor: function(){
251 this.fetchProperties
={};
254 postMixInProperties: function(){
256 var list
= this.list
;
258 this.store
= registry
.byId(list
);
261 this.inherited(arguments
);