1jQuery.noConflict(); 2jQuery(function($) { 3 4SearchAutocomplete = Backbone.View.extend({ 5 url : null, 6 result : null, 7 suggest : null, 8 query : null, 9 delay : 100, 10 queryMinChars : 3, 11 shown : false, 12 13 events : { 14 'keydown .UI-SEARCH' : 'onKeydown', 15 'keyup .UI-SEARCH' : 'onKeyup', 16 'blur .UI-SEARCH' : 'onBlur', 17 'focus .UI-SEARCH' : 'onFocus', 18 'change .UI-CATEGORY' : 'onChangeCategory' 19 }, 20 21 initialize: function() 22 { 23 var self = this; 24 _.bindAll(self); 25 }, 26 27 init: function(el) 28 { 29 var self = this; 30 31 self.setElement(el); 32 33 self.url = self.$el.attr('data-url'); 34 self.delay = self.$el.attr('data-delay'); 35 self.queryMinChars = self.$el.attr('data-minchars'); 36 self.$listenField = $('.UI-SEARCH', self.$el); 37 self.$suggestField = $('.UI-SEARCH-SUGGEST', self.$el); 38 self.$placeholder = $('.UI-PLACEHOLDER', self.$el); 39 self.$loader = $('.UI-LOADER', self.$el); 40 self.$category = $('.UI-CATEGORY', self.$el);
41 self.$categoryText = $('.UI-CATEGORY-TEXT', self.$el); 42 self.result = ''; 43 self.query = self.$listenField.val(); 44 45 self.baseWidth = $('.UI-NAV-INPUT').width(); 46 47 self.onChangeCategory(); 48 }, 49 50 onChangeCategory: function() 51 { 52 var self = this; 53 var text = $('option:selected', self.$category).text(); 54 55 if (self.$categoryText.length) { 56 self.$categoryText.html(text); 57 $('.UI-NAV-INPUT').css('padding-left', self.$categoryText.width() + 35); 58 $('.UI-CATEGORY').css('width', self.$categoryText.width() + 35); 59 // $('.UI-NAV-INPUT').css('width', self.baseWidth -(self.$categoryText.width() + 35)); 60 } 61 62 self.result = ''; 63 }, 64 65 onKeydown: function(e) 66 { 67 var self = this; 68 e.stopPropagation(); 69 70 if (!self.shown) { 71 return; 72 } 73 74 switch(e.keyCode) { 75 case 13: // enter 76 return; 77 78 case 9: // tab 79 case 27: // escape 80 e.preventDefault(); 81 break; 82 83 case 38: // up arrow 84 e.preventDefault(); 85 self.prev(); 86 break; 87 88 case 40: // down arrow 89 e.preventDefault(); 90 self.next(); 91 break; 92 } 93 }, 94 95 onKeyup: function(e) 96 { 97 var self = this; 98 e.stopPropagation(); 99 e.preventDefault(); 100 101 switch(e.keyCode) { 102 case 40: // down arrow 103 case 38: // up arrow 104 break; 105 106 case 27: // escape 107 self.hide(); 108 break; 109 110 case 13: 111 if (!self.shown) { 112 return; 113 } 114 115 if ($('.active', self.$placeholder).length) { 116 self.select(); 117 } 118 break; 119 120 default: 121 var q = self.$listenField.val(); 122 window.setTimeout(function() { 123 if (q == self.$listenField.val() && self.$listenField.val() != self.query) { 124 self.lookup(); 125 } 126 }, self.delay); 127 128 self.$placeholder.html(self.result); 129 self.highlighter(self.$placeholder); 130 } 131 }, 132 133 onBlur: function(e) 134 { 135 var self = this; 136 137 setTimeout(function() { 138 self.select(); 139 }, 300); 140 }, 141 142 onFocus: function (e) 143 { 144 var self = this; 145 146 if (self.query.length >= self.queryMinChars) { 147 if (self.result == '') { 148 self.lookup(); 149 } else { 150 self.show(); 151 } 152 } 153 }, 154 155 mouseover: function (e) 156 { 157 var self = this; 158 159 $('.active', self.$placeholder).removeClass('active'); 160 161 $(e.currentTarget).addClass('active'); 162 }, 163 164 mouseout: function (e) 165 { 166 $(e.currentTarget).removeClass('active'); 167 }, 168 169 click: function (e) 170 { 171 var self = this; 172 e.stopPropagation(); 173 e.preventDefault(); 174 175 self.select(); 176 }, 177 178 next: function (e) 179 { 180 var self = this; 181 var next; 182 183 var $active = $('.active', self.$placeholder); 184 $active.removeClass('active'); 185 186 if ($active.length === 0) { 187 next = $($('li', self.$placeholder).get(0)); 188 } else { 189 next = $active.next(); 190 } 191 192 if (next) { 193 next.addClass('active'); 194 } 195 }, 196 197 prev: function (e) 198 { 199 var self = this; 200 var prev; 201 202 var active = $('.active', self.$placeholder); 203 active.removeClass('active'); 204 205 if (active.length === 0) { 206 prev = $($('li', self.$placeholder).get($('li', self.$placeholder).length - 1)); 207 } else { 208 prev = active.prev(); 209 } 210 211 if (prev) { 212 prev.addClass('active'); 213 } 214 }, 215 216 select: function() 217 { 218 var self = this; 219 220 if ($('.active', self.$placeholder).length) { 221 var val = $('.active', self.$placeholder).attr('data-url'); 222 window.location.href = val; 223 } 224 225 return this.hide(); 226 }, 227 228 lookup: function () 229 { 230 var self = this; 231 232 self.query = self.$listenField.val(); 233 if (self.query.length >= self.queryMinChars) { 234 self.process(self.query); 235 } else { 236 self.hide(); 237 } 238 }, 239 240 process: function(query) 241 { 242 var self = this; 243 244 var cat = ''; 245 if (self.$category.val() !== undefined) { 246 cat = '&' + self.$category.attr('name') + '=' + self.$category.val(); 247 } 248 249 $.ajax({
250 url : self.url + '?q=' + encodeURIComponent(query) + cat, 251 dataType : 'json', 252 type : 'GET', 253 beforeSend: function() { 254 clearTimeout(self.processTimer); 255 self.processTimer = setTimeout(function() { 256 self.$loader.show(); 257 }, 250); 258 }, 259 success : function(response) { 260 clearTimeout(self.processTimer); 261 262 self.$loader.hide(); 263 264 if (response.query.toLowerCase().trim() === self.$listenField.val().toLowerCase().trim()) { 265 if (response.items.length) { 266 self.show(response.items); 267 } else { 268 self.hide(); 269 } 270 } 271 } 272 }); 273 }, 274 275 show: function(html) 276 { 277 var self = this; 278 279 if (html ==- undefined) { 280 if (self.result === '') { 281 return; 282 } 283 } else { 284 self.result = html; 285 self.$placeholder.html(html); 286 self.highlighter(self.$placeholder); 287 } 288 289 self.$placeholder.show(); 290 self.shown = true; 291 292 $('li', self.$placeholder).each(function(key, el) { 293 var $el = $(el); 294 $el.on('mouseover', self.mouseover); 295 $el.on('mouseout', self.mouseout); 296 $el.on('click', self.click); 297 }); 298 299 return this; 300 }, 301 302 hide: function () 303 { 304 var self = this; 305 306 self.$placeholder.hide(); 307 self.shown = false; 308 309 return this; 310 }, 311 312 highlighter: function (item) 313 { 314 var self = this; 315 316 $('.highlight', item).each(function(key, el) { 317 var $el = $(el); 318 var arQuery = self.$listenField.val().split(' '); 319 var html = $el.text(); 320 321 arQuery.each(function(word) { 322 if ($.trim(word)) { 323 word = word.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); 324 if ("strong".indexOf(word) == -1) { 325 html = html.replace(new RegExp('(' + word + ')', 'ig'), function ($1, match) { 326 return '<strong>' + match + '</strong>'; 327 }); 328 } 329 } 330 }); 331 332 $el.html(html); 333 }); 334 } 335}); 336 337$(function() { 338 _.each($('.UI-SEARCHAUTOCOMPLETE'), function (el) { 339 var autocomplete = new SearchAutocomplete(); 340 autocomplete.init(el); 341 }); 342}); 343 344});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.