1 dojo.declare( 'JBrowse.Model.AutocompleteStore', null, 2 /** 3 * @lends JBrowse.Model.AutocompleteStore 4 */ 5 { 6 /** 7 * @constructs 8 */ 9 constructor: function( /**Object*/ args ) { 10 if( ! args.namesTrie ) 11 throw "must provide a namesTrie argument"; 12 13 this.namesTrie = args.namesTrie; 14 15 this.resultLimit = args.resultLimit || 15; 16 this.tooManyMatchesMessage = args.tooManyMatchesMessage || '(too many matches to display)'; 17 18 // generate stopPrefixes 19 var stopPrefixes = this.stopPrefixes = {}; 20 // make our stopPrefixes an object as { prefix: true, ... } 21 // with all possible prefixes of our stop prefixes 22 if( args.stopPrefixes ) { 23 var prefixesInput = typeof args.stopPrefixes == 'string' 24 ? [ args.stopPrefixes ] : args.stopPrefixes; 25 26 dojo.forEach( prefixesInput, function(prefix) { 27 while( prefix.length ) { 28 stopPrefixes[prefix] = true; 29 prefix = prefix.substr( 0, prefix.length - 1 ); 30 } 31 }); 32 } 33 34 // make a self-modifying method for extracting the that 35 // detects whether the name store is formatted with tools 36 // pre-1.4 or post-1.4. for pre-1.4 formats, will just 37 // complete with the lower-case version of the name. for 38 // post-1.4, use the original-case version that's stored in 39 // the name record. 40 this.nodeText = function(node) { 41 if( typeof node[1][0][0] == 'number' ) { 42 // pre-1.4, for backcompat 43 this.nodeText = function(node) { return node[0]; }; 44 } else { 45 // post-1.4 46 this.nodeText = function(node) { return node[1][0][0]; }; 47 } 48 return this.nodeText( node ); 49 }; 50 }, 51 52 // dojo.data.api.Read support 53 54 fetch: function( /**Object*/ request ) { 55 var start = request.start || 0; 56 var matchLimit = Math.min( this.resultLimit, Math.max(0, request.count) ); 57 var matchesRemaining = matchLimit; 58 var scope = request.scope || dojo.global; 59 var aborted = false; 60 61 // wrap our abort function to set a flag 62 request.abort = function() { 63 var oldabort = request.abort || function() {}; 64 return function() { 65 aborted = true; 66 oldabort.call( scope, request ); 67 }; 68 }.call(this); 69 70 if( ! request.store ) 71 request.store = this; 72 73 var gotTree = false; // stays false if tree isn't found 74 var matches = []; 75 var prefix = (request.query.name || '').replace(/\*$/,''); 76 77 if( ! this.stopPrefixes[ prefix ] ) { 78 this.namesTrie.mappingsFromPrefix( 79 prefix, 80 dojo.hitch( this, function(tree) { 81 gotTree = true; 82 // use dojo.some so that we can break out of the loop when we hit the limit 83 dojo.some( tree, function(node) { 84 if( matchesRemaining-- ) { 85 matches.push({ name: this.nodeText(node) }); 86 } 87 return matchesRemaining < 0; 88 },this); 89 })); 90 } 91 92 // if we found more than the match limit 93 if( matchesRemaining < 0 ) 94 matches.push({ name: this.tooManyMatchesMessage, hitLimit: true }); 95 96 if( request.onBegin ) 97 request.onBegin.call( scope, matches.length, request ); 98 if( request.sort ) 99 matches.sort(dojo.data.util.sorter.createSortFunction(request.sort, this)); 100 if( request.onItem ) { 101 dojo.forEach( matches, function( item ) { 102 if( !aborted ) 103 request.onItem.call( scope, item, request ); 104 }); 105 } 106 if(request.onComplete && !aborted){ 107 request.onComplete.call( scope, matches, request ); 108 } 109 }, 110 111 getValue: function( i, attr, defaultValue ) { 112 var v = i[attr]; 113 return typeof v == 'undefined' ? defaultValue : v; 114 }, 115 getValues: function( i, attr ) { 116 var a = [ i[attr] ]; 117 return typeof a[0] == 'undefined' ? [] : a; 118 }, 119 120 getAttributes: function(item) { 121 return dojof.keys( item ); 122 }, 123 124 hasAttribute: function(item,attr) { 125 return item.hasOwnProperty(attr); 126 }, 127 128 containsValue: function(item, attribute, value) { 129 return item[attribute] == value; 130 }, 131 132 isItem: function(item) { 133 return typeof item == 'object' && typeof item.label == 'string'; 134 }, 135 136 isItemLoaded: function() { 137 return true; 138 }, 139 140 loadItem: function( args ) { 141 }, 142 143 close: function() {}, 144 145 getLabel: function(i) { 146 return this.getValue(i,'name',undefined); 147 }, 148 getLabelAttributes: function(i) { 149 return ['name']; 150 } 151 }); 152