1/*! 2 * bootstrap-typeahead.js v0.0.5 (http://www.upbootstrap.com) 3 * Copyright 2012-2015 Twitter Inc. 4 * Licensed under MIT (https://github.com/biggora/bootstrap-ajax-typeahead/blob/master/LICENSE) 5 * See Demo: http://plugins.upbootstrap.com/bootstrap-ajax-typeahead 6 * Updated: 2015-04-05 11:43:56 7 * 8 * Modifications by Paul Warelis and Alexey Gordeyev 9 */ 10!function ($) { 11 "use strict"; // jshint ;_; 12 13 /* TYPEAHEAD PUBLIC CLASS DEFINITION 14 * ================================= */ 15 16 var Typeahead = function (element, options) { 17 //deal with scrollBar 18 var defaultOptions = $.fn.typeahead.defaults; 19 if (options.scrollBar) { 20 options.items = 100; 21 options.menu = '<ul class="typeahead dropdown-menu" style="max-height:220px;overflow:auto;"></ul>'; 22 } 23 24 var that = this; 25 that.$element = $(element); 26 that.options = $.extend({}, $.fn.typeahead.defaults, options); 27 that.$menu = $(that.options.menu).insertAfter(that.$element); 28 29 // Method overrides 30 that.eventSupported = that.options.eventSupported || that.eventSupported; 31 that.grepper = that.options.grepper || that.grepper; 32 that.highlighter = that.options.highlighter || that.highlighter; 33 that.lookup = that.options.lookup || that.lookup; 34 that.matcher = that.options.matcher || that.matcher; 35 that.render = that.options.render || that.render; 36 that.onSelect = that.options.onSelect || null; 37 that.sorter = that.options.sorter || that.sorter; 38 that.source = that.options.source || that.source; 39 that.displayField = that.options.displayField || that.displayField; 40 that.valueField = that.options.valueField || that.valueField; 41 42 if (that.options.ajax) { 43 var ajax = that.options.ajax; 44 45 if (typeof ajax === 'string') { 46 that.ajax = $.extend({}, $.fn.typeahead.defaults.ajax, { 47 url: ajax 48 }); 49 } else { 50 if (typeof ajax.displayField === 'string') { 51 that.displayField = that.options.displayField = ajax.displayField; 52 } 53 if (typeof ajax.valueField === 'string') { 54 that.valueField = that.options.valueField = ajax.valueField; 55 } 56 57 that.ajax = $.extend({}, $.fn.typeahead.defaults.ajax, ajax); 58 } 59 60 if (!that.ajax.url) { 61 that.ajax = null; 62 } 63 that.query = ""; 64 } else { 65 that.source = that.options.source; 66 that.ajax = null; 67 } 68 that.shown = false; 69 that.listen(); 70 }; 71 72 Typeahead.prototype = { 73 constructor: Typeahead, 74 //============================================================================================================= 75 // Utils 76 // Check if an event is supported by the browser eg. 'keypress' 77 // * This was included to handle the "exhaustive deprecation" of jQuery.browser in jQuery 1.8 78 //============================================================================================================= 79 eventSupported: function (eventName) { 80 var isSupported = (eventName in this.$element); 81 82 if (!isSupported) { 83 this.$element.setAttribute(eventName, 'return;'); 84 isSupported = typeof this.$element[eventName] === 'function'; 85 } 86 87 return isSupported; 88 }, 89 select: function () { 90 var $selectedItem = this.$menu.find('.active'); 91 if ($selectedItem.length) { 92 var value = $selectedItem.attr('data-value'); 93 var text = this.$menu.find('.active a').text(); 94 95 if (this.options.onSelect) { 96 this.options.onSelect({ 97 value: value, 98 text: text 99 }); 100 } 101 this.$element 102 .val(this.updater(text)) 103 .change(); 104 } 105 return this.hide(); 106 }, 107 updater: function (item) { 108 return item; 109 }, 110 show: function () { 111 var pos = $.extend({}, this.$element.position(), { 112 height: this.$element[0].offsetHeight 113 }); 114 115 this.$menu.css({ 116 top: pos.top + pos.height, 117 left: pos.left 118 }); 119 120 if (this.options.alignWidth) { 121 var width = $(this.$element[0]).outerWidth(); 122 this.$menu.css({ 123 width: width 124 }); 125 } 126 127 new Tether({ 128 element: this.$menu[0], 129 target: this.$element[0], 130 attachment: 'top left', 131 targetAttachment: 'bottom left', 132 constraints: [ 133 { 134 to: 'scrollParent', 135 attachment: 'together', 136 pin: true 137 } 138 ] 139 }) 140 this.$menu.show(); 141 this.shown = true; 142 return this; 143 }, 144 hide: function () { 145 this.$menu.hide(); 146 this.shown = false; 147 return this; 148 }, 149 ajaxLookup: function () { 150 var query = $.trim(this.$element.val()); 151 152 //if (query === this.query) { 153 // return this; 154 //} 155 156 // Query changed 157 this.query = query; 158 159 // Cancel last timer if set 160 if (this.ajax.timerId) { 161 clearTimeout(this.ajax.timerId); 162 this.ajax.timerId = null; 163 } 164 165 if (!query || query.length < this.ajax.triggerLength) { 166 // cancel the ajax callback if in progress 167 if (this.ajax.xhr) { 168 this.ajax.xhr.abort(); 169 this.ajax.xhr = null; 170 this.ajaxToggleLoadClass(false); 171 } 172 173 return this.shown ? this.hide() : this; 174 } 175 176 function execute() { 177 this.ajaxToggleLoadClass(true); 178 179 // Cancel last call if already in progress 180 if (this.ajax.xhr) 181 this.ajax.xhr.abort(); 182 183 var params = this.ajax.preDispatch ? this.ajax.preDispatch(query) : { 184 query: query 185 }; 186 this.ajax.xhr = $.ajax({
187 url: this.ajax.url, 188 data: params, 189 success: $.proxy(this.ajaxSource, this), 190 type: this.ajax.method || 'get', 191 dataType: 'json' 192 }); 193 this.ajax.timerId = null; 194 } 195 196 // Query is good to send, set a timer 197 this.ajax.timerId = setTimeout($.proxy(execute, this), this.ajax.timeout); 198 199 return this; 200 }, 201 ajaxSource: function (data) { 202 this.ajaxToggleLoadClass(false); 203 var that = this, items; 204 if (!that.ajax.xhr) 205 return; 206 if (that.ajax.preProcess) { 207 data = that.ajax.preProcess(data); 208 } 209 // Save for selection retreival 210 that.ajax.data = data; 211 212 // Manipulate objects 213 items = that.grepper(that.ajax.data) || []; 214 if (!items.length) { 215 return that.shown ? that.hide() : that; 216 } 217 218 that.ajax.xhr = null; 219 return that.render(items.slice(0, that.options.items)).show(); 220 }, 221 ajaxToggleLoadClass: function (enable) { 222 if (!this.ajax.loadingClass) 223 return; 224 this.$element.toggleClass(this.ajax.loadingClass, enable); 225 }, 226 lookup: function (event) { 227 var that = this, items; 228 if (that.ajax) { 229 that.ajaxLookup(); 230 } 231 else { 232 that.query = that.$element.val(); 233 234 if (!that.query) { 235 return that.shown ? that.hide() : that; 236 } 237 238 items = that.grepper(that.source); 239 240 if (!items) { 241 return that.shown ? that.hide() : that; 242 } 243 //Bhanu added a custom message- Result not Found when no result is found 244 if (items.length == 0) { 245 items[0] = { 'id': -21, 'name': "Result not Found" } 246 } 247 return that.render(items.slice(0, that.options.items)).show(); 248 } 249 }, 250 matcher: function (item) { 251 return ~item.toLowerCase().indexOf(this.query.toLowerCase()); 252 }, 253 sorter: function (items) { 254 if (!this.options.ajax) { 255 var beginswith = [], 256 caseSensitive = [], 257 caseInsensitive = [], 258 item; 259 260 while (item = items.shift()) { 261 if (!item.toLowerCase().indexOf(this.query.toLowerCase())) 262 beginswith.push(item); 263 else if (~item.indexOf(this.query)) 264 caseSensitive.push(item); 265 else 266 caseInsensitive.push(item); 267 } 268 269 return beginswith.concat(caseSensitive, caseInsensitive); 270 } else { 271 return items; 272 } 273 }, 274 highlighter: function (item) { 275 var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); 276 return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) { 277 return '<strong>' + match + '</strong>'; 278 }); 279 }, 280 render: function (items) { 281 var that = this, display, isString = typeof that.options.displayField === 'string'; 282 283 items = $(items).map(function (i, item) { 284 if (typeof item === 'object') { 285 display = isString ? item[that.options.displayField] : that.options.displayField(item); 286 i = $(that.options.item).attr('data-value', item[that.options.valueField]); 287 } else { 288 display = item; 289 i = $(that.options.item).attr('data-value', item); 290 } 291 i.find('a').html(that.highlighter(display)); 292 return i[0]; 293 }); 294 295 if (that.options.autoselect) items.first().addClass('active'); 296 297 this.$menu.html(items); 298 return this; 299 }, 300 //------------------------------------------------------------------ 301 // Filters relevent results 302 // 303 grepper: function (data) { 304 var that = this, items, display, isString = typeof that.options.displayField === 'string'; 305 306 if (isString && data && data.length) { 307 if (data[0].hasOwnProperty(that.options.displayField)) { 308 items = $.grep(data, function (item) { 309 display = isString ? item[that.options.displayField] : that.options.displayField(item); 310 return that.matcher(display); 311 }); 312 } else if (typeof data[0] === 'string') { 313 items = $.grep(data, function (item) { 314 return that.matcher(item); 315 }); 316 } else { 317 return null; 318 } 319 } else { 320 return null; 321 } 322 return this.sorter(items); 323 }, 324 next: function (event) { 325 var active = this.$menu.find('.active').removeClass('active'), 326 next = active.next(); 327 328 if (!next.length) { 329 next = $(this.$menu.find('li')[0]); 330 } 331 332 if (this.options.scrollBar) { 333 var index = this.$menu.children("li").index(next); 334 if (index % 8 == 0) { 335 this.$menu.scrollTop(index * 26); 336 } 337 } 338 339 next.addClass('active'); 340 }, 341 prev: function (event) { 342 var active = this.$menu.find('.active').removeClass('active'), 343 prev = active.prev(); 344 345 if (!prev.length) { 346 prev = this.$menu.find('li').last(); 347 } 348 349 if (this.options.scrollBar) { 350 var $li = this.$menu.children("li"); 351 var total = $li.length - 1; 352 var index = $li.index(prev); 353 354 if ((total - index) % 8 == 0) { 355 this.$menu.scrollTop((index - 7) * 26); 356 } 357 } 358 359 prev.addClass('active'); 360 }, 361 listen: function () { 362 this.$element 363 .on('focus', $.proxy(this.focus, this)) 364 .on('blur', $.proxy(this.blur, this)) 365 .on('keypress', $.proxy(this.keypress, this)) 366 .on('keyup', $.proxy(this.keyup, this)); 367 368 if (this.eventSupported('keydown')) { 369 this.$element.on('keydown', $.proxy(this.keydown, this)) 370 } 371 372 this.$menu 373 .on('click', $.proxy(this.click, this)) 374 .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) 375 .on('mouseleave', 'li', $.proxy(this.mouseleave, this)) 376 }, 377 move: function (e) { 378 if (!this.shown) 379 return 380 381 switch (e.keyCode) { 382 case 9: // tab 383 case 13: // enter 384 case 27: // escape 385 e.preventDefault(); 386 break 387 388 case 38: // up arrow 389 e.preventDefault() 390 this.prev() 391 break 392 393 case 40: // down arrow 394 e.preventDefault() 395 this.next() 396 break 397 } 398 399 e.stopPropagation(); 400 }, 401 keydown: function (e) { 402 this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40, 38, 9, 13, 27]) 403 this.move(e) 404 }, 405 keypress: function (e) { 406 if (this.suppressKeyPressRepeat) 407 return 408 this.move(e) 409 }, 410 keyup: function (e) { 411 switch (e.keyCode) { 412 case 40: // down arrow 413 case 38: // up arrow 414 case 16: // shift 415 case 17: // ctrl 416 case 18: // alt 417 break 418 419 case 9: // tab 420 case 13: // enter 421 if (!this.shown) 422 return 423 this.select() 424 break 425 426 case 27: // escape 427 if (!this.shown) 428 return 429 this.hide() 430 break 431 432 default: 433 if (this.ajax) 434 this.ajaxLookup() 435 else 436 this.lookup() 437 } 438 439 e.stopPropagation() 440 e.preventDefault() 441 }, 442 focus: function (e) { 443 this.focused = true 444 }, 445 blur: function (e) { 446 this.focused = false 447 if (!this.mousedover && this.shown) 448 this.hide() 449 }, 450 click: function (e) { 451 e.stopPropagation() 452 e.preventDefault() 453 this.select() 454 this.$element.focus() 455 }, 456 mouseenter: function (e) { 457 this.mousedover = true 458 this.$menu.find('.active').removeClass('active') 459 $(e.currentTarget).addClass('active') 460 }, 461 mouseleave: function (e) { 462 this.mousedover = false 463 if (!this.focused && this.shown) 464 this.hide() 465 }, 466 destroy: function () { 467 this.$element 468 .off('focus', $.proxy(this.focus, this)) 469 .off('blur', $.proxy(this.blur, this)) 470 .off('keypress', $.proxy(this.keypress, this)) 471 .off('keyup', $.proxy(this.keyup, this)); 472 473 if (this.eventSupported('keydown')) { 474 this.$element.off('keydown', $.proxy(this.keydown, this)) 475 } 476 477 this.$menu 478 .off('click', $.proxy(this.click, this)) 479 .off('mouseenter', 'li', $.proxy(this.mouseenter, this)) 480 .off('mouseleave', 'li', $.proxy(this.mouseleave, this)) 481 this.$element.removeData('typeahead'); 482 } 483 }; 484 485 /* TYPEAHEAD PLUGIN DEFINITION 486 * =========================== */ 487 488 $.fn.typeahead = function (option) { 489 return this.each(function () { 490 var $this = $(this), 491 data = $this.data('typeahead'), 492 options = typeof option === 'object' && option; 493 if (!data) 494 $this.data('typeahead', (data = new Typeahead(this, options))); 495 if (typeof option === 'string') 496 data[option](); 497 }); 498 }; 499 500 $.fn.typeahead.defaults = { 501 source: [], 502 items: 10, 503 scrollBar: false, 504 alignWidth: true, 505 menu: '<ul class="typeahead dropdown-menu"></ul>', 506 item: '<li><a href="#"></a></li>',
507 valueField: 'id', 508 displayField: 'name', 509 autoselect: true, 510 onSelect: function () { 511 }, 512 ajax: { 513 url: null, 514 timeout: 300, 515 method: 'get', 516 triggerLength: 1, 517 loadingClass: null, 518 preDispatch: null, 519 preProcess: null 520 } 521 }; 522 523 $.fn.typeahead.Constructor = Typeahead; 524 525 /* TYPEAHEAD DATA-API 526 * ================== */ 527 528 $(function () { 529 $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) { 530 var $this = $(this); 531 if ($this.data('typeahead')) 532 return; 533 e.preventDefault(); 534 $this.typeahead($this.data()); 535 }); 536 }); 537}(window.jQuery);
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.