summaryrefslogtreecommitdiff
path: root/lib/dijit/form/_SearchMixin.js.uncompressed.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dijit/form/_SearchMixin.js.uncompressed.js')
-rw-r--r--lib/dijit/form/_SearchMixin.js.uncompressed.js264
1 files changed, 264 insertions, 0 deletions
diff --git a/lib/dijit/form/_SearchMixin.js.uncompressed.js b/lib/dijit/form/_SearchMixin.js.uncompressed.js
new file mode 100644
index 000000000..9cd69fcf7
--- /dev/null
+++ b/lib/dijit/form/_SearchMixin.js.uncompressed.js
@@ -0,0 +1,264 @@
+define("dijit/form/_SearchMixin", [
+ "dojo/data/util/filter", // patternToRegExp
+ "dojo/_base/declare", // declare
+ "dojo/_base/event", // event.stop
+ "dojo/keys", // keys
+ "dojo/_base/lang", // lang.clone lang.hitch
+ "dojo/query", // query
+ "dojo/sniff", // has("ie")
+ "dojo/string", // string.substitute
+ "dojo/when",
+ "../registry" // registry.byId
+], function(filter, declare, event, keys, lang, query, has, string, when, registry){
+
+ // module:
+ // dijit/form/_SearchMixin
+
+
+ return declare("dijit.form._SearchMixin", null, {
+ // summary:
+ // A mixin that implements the base functionality to search a store based upon user-entered text such as
+ // with `dijit/form/ComboBox` or `dijit/form/FilteringSelect`
+ // tags:
+ // protected
+
+ // pageSize: Integer
+ // Argument to data provider.
+ // Specifies maximum number of search results to return per query
+ pageSize: Infinity,
+
+ // store: [const] dojo/store/api/Store
+ // Reference to data provider object used by this ComboBox.
+ // The store must accept an object hash of properties for its query. See `query` and `queryExpr` for details.
+ store: null,
+
+ // fetchProperties: Object
+ // Mixin to the store's fetch.
+ // For example, to set the sort order of the ComboBox menu, pass:
+ // | { sort: [{attribute:"name",descending: true}] }
+ // To override the default queryOptions so that deep=false, do:
+ // | { queryOptions: {ignoreCase: true, deep: false} }
+ fetchProperties:{},
+
+ // query: Object
+ // A query that can be passed to `store` to initially filter the items.
+ // ComboBox overwrites any reference to the `searchAttr` and sets it to the `queryExpr` with the user's input substituted.
+ query: {},
+
+ // searchDelay: Integer
+ // Delay in milliseconds between when user types something and we start
+ // searching based on that value
+ searchDelay: 200,
+
+ // searchAttr: String
+ // Search for items in the data store where this attribute (in the item)
+ // matches what the user typed
+ searchAttr: "name",
+
+ // queryExpr: String
+ // This specifies what query is sent to the data store,
+ // based on what the user has typed. Changing this expression will modify
+ // whether the results are only exact matches, a "starting with" match,
+ // etc.
+ // dojo.data query expression pattern.
+ // `${0}` will be substituted for the user text.
+ // `*` is used for wildcards.
+ // `${0}*` means "starts with", `*${0}*` means "contains", `${0}` means "is"
+ queryExpr: "${0}*",
+
+ // ignoreCase: Boolean
+ // Set true if the query should ignore case when matching possible items
+ ignoreCase: true,
+
+ _abortQuery: function(){
+ // stop in-progress query
+ if(this.searchTimer){
+ this.searchTimer = this.searchTimer.remove();
+ }
+ if(this._queryDeferHandle){
+ this._queryDeferHandle = this._queryDeferHandle.remove();
+ }
+ if(this._fetchHandle){
+ if(this._fetchHandle.abort){
+ this._cancelingQuery = true;
+ this._fetchHandle.abort();
+ this._cancelingQuery = false;
+ }
+ if(this._fetchHandle.cancel){
+ this._cancelingQuery = true;
+ this._fetchHandle.cancel();
+ this._cancelingQuery = false;
+ }
+ this._fetchHandle = null;
+ }
+ },
+
+ _processInput: function(/*Event*/ evt){
+ // summary:
+ // Handles input (keyboard/paste) events
+ if(this.disabled || this.readOnly){ return; }
+ var key = evt.charOrCode;
+
+ // except for cutting/pasting case - ctrl + x/v
+ if(evt.altKey || ((evt.ctrlKey || evt.metaKey) && (key != 'x' && key != 'v')) || key == keys.SHIFT){
+ return; // throw out weird key combinations and spurious events
+ }
+
+ var doSearch = false;
+ this._prev_key_backspace = false;
+
+ switch(key){
+ case keys.DELETE:
+ case keys.BACKSPACE:
+ this._prev_key_backspace = true;
+ this._maskValidSubsetError = true;
+ doSearch = true;
+ break;
+
+ default:
+ // Non char keys (F1-F12 etc..) shouldn't start a search..
+ // Ascii characters and IME input (Chinese, Japanese etc.) should.
+ //IME input produces keycode == 229.
+ doSearch = typeof key == 'string' || key == 229;
+ }
+ if(doSearch){
+ // need to wait a tad before start search so that the event
+ // bubbles through DOM and we have value visible
+ if(!this.store){
+ this.onSearch();
+ }else{
+ this.searchTimer = this.defer("_startSearchFromInput", 1);
+ }
+ }
+ },
+
+ onSearch: function(/*===== results, query, options =====*/){
+ // summary:
+ // Callback when a search completes.
+ //
+ // results: Object
+ // An array of items from the originating _SearchMixin's store.
+ //
+ // query: Object
+ // A copy of the originating _SearchMixin's query property.
+ //
+ // options: Object
+ // The additional parameters sent to the originating _SearchMixin's store, including: start, count, queryOptions.
+ //
+ // tags:
+ // callback
+ },
+
+ _startSearchFromInput: function(){
+ this._startSearch(this.focusNode.value.replace(/([\\\*\?])/g, "\\$1"));
+ },
+
+ _startSearch: function(/*String*/ text){
+ // summary:
+ // Starts a search for elements matching text (text=="" means to return all items),
+ // and calls onSearch(...) when the search completes, to display the results.
+
+ this._abortQuery();
+ var
+ _this = this,
+ // Setup parameters to be passed to store.query().
+ // Create a new query to prevent accidentally querying for a hidden
+ // value from FilteringSelect's keyField
+ query = lang.clone(this.query), // #5970
+ options = {
+ start: 0,
+ count: this.pageSize,
+ queryOptions: { // remove for 2.0
+ ignoreCase: this.ignoreCase,
+ deep: true
+ }
+ },
+ qs = string.substitute(this.queryExpr, [text]),
+ q,
+ startQuery = function(){
+ var resPromise = _this._fetchHandle = _this.store.query(query, options);
+ if(_this.disabled || _this.readOnly || (q !== _this._lastQuery)){
+ return;
+ } // avoid getting unwanted notify
+ when(resPromise, function(res){
+ _this._fetchHandle = null;
+ if(!_this.disabled && !_this.readOnly && (q === _this._lastQuery)){ // avoid getting unwanted notify
+ when(resPromise.total, function(total){
+ res.total = total;
+ var pageSize = _this.pageSize;
+ if(isNaN(pageSize) || pageSize > res.total){ pageSize = res.total; }
+ // Setup method to fetching the next page of results
+ res.nextPage = function(direction){
+ // tell callback the direction of the paging so the screen
+ // reader knows which menu option to shout
+ options.direction = direction = direction !== false;
+ options.count = pageSize;
+ if(direction){
+ options.start += res.length;
+ if(options.start >= res.total){
+ options.count = 0;
+ }
+ }else{
+ options.start -= pageSize;
+ if(options.start < 0){
+ options.count = Math.max(pageSize + options.start, 0);
+ options.start = 0;
+ }
+ }
+ if(options.count <= 0){
+ res.length = 0;
+ _this.onSearch(res, query, options);
+ }else{
+ startQuery();
+ }
+ };
+ _this.onSearch(res, query, options);
+ });
+ }
+ }, function(err){
+ _this._fetchHandle = null;
+ if(!_this._cancelingQuery){ // don't treat canceled query as an error
+ console.error(_this.declaredClass + ' ' + err.toString());
+ }
+ });
+ };
+
+ lang.mixin(options, this.fetchProperties);
+
+ // Generate query
+ if(this.store._oldAPI){
+ // remove this branch for 2.0
+ q = qs;
+ }else{
+ // Query on searchAttr is a regex for benefit of dojo/store/Memory,
+ // but with a toString() method to help dojo/store/JsonRest.
+ // Search string like "Co*" converted to regex like /^Co.*$/i.
+ q = filter.patternToRegExp(qs, this.ignoreCase);
+ q.toString = function(){ return qs; };
+ }
+
+ // set _lastQuery, *then* start the timeout
+ // otherwise, if the user types and the last query returns before the timeout,
+ // _lastQuery won't be set and their input gets rewritten
+ this._lastQuery = query[this.searchAttr] = q;
+ this._queryDeferHandle = this.defer(startQuery, this.searchDelay);
+ },
+
+ //////////// INITIALIZATION METHODS ///////////////////////////////////////
+
+ constructor: function(){
+ this.query={};
+ this.fetchProperties={};
+ },
+
+ postMixInProperties: function(){
+ if(!this.store){
+ var list = this.list;
+ if(list){
+ this.store = registry.byId(list);
+ }
+ }
+ this.inherited(arguments);
+ }
+ });
+});