vendor: 7,234 bytes, lines 1-291
1/* ============================================================= 2 * bootstrap-typeahead.js v2.1.1 3 * http://twitter.github.com/bootstrap/javascript.html#typeahead 4 * ============================================================= 5 * Copyright 2012 Twitter, Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * ============================================================ */ 19 20 21!function($){ 22 23 "use strict"; // jshint ;_; 24 25 26 /* TYPEAHEAD PUBLIC CLASS DEFINITION 27 * ================================= */ 28 29 var Typeahead = function (element, options) { 30 this.$element = $(element) 31 this.options = $.extend({}, $.fn.typeahead.defaults, options) 32 this.matcher = this.options.matcher || this.matcher 33 this.sorter = this.options.sorter || this.sorter 34 this.highlighter = this.options.highlighter || this.highlighter 35 this.updater = this.options.updater || this.updater 36 this.$menu = $(this.options.menu).appendTo('body') 37 this.source = this.options.source 38 this.shown = false 39 this.listen() 40 } 41 42 Typeahead.prototype = { 43 44 constructor: Typeahead 45 46 , select: function () { 47 var val = this.$menu.find('.active').attr('data-value') 48 this.$element 49 .val(this.updater(val)) 50 .change() 51 return this.hide() 52 } 53 54 , updater: function (item) { 55 return item 56 } 57 58 , show: function () { 59 var pos = $.extend({}, this.$element.offset(), { 60 height: this.$element[0].offsetHeight 61 }) 62 63 this.$menu.css({ 64 top: pos.top + pos.height 65 , left: pos.left 66 }) 67 68 this.$menu.show() 69 this.shown = true 70 return this 71 } 72 73 , hide: function () { 74 this.$menu.hide() 75 this.shown = false 76 return this 77 } 78 79 , lookup: function (event) { 80 var items 81 82 this.query = this.$element.val() 83 84 if (!this.query || this.query.length < this.options.minLength) { 85 return this.shown ? this.hide() : this 86 } 87 88 items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source 89 90 return items ? this.process(items) : this 91 } 92 93 , process: function (items) { 94 var that = this 95 96 items = $.grep(items, function (item) { 97 return that.matcher(item) 98 }) 99 100 items = this.sorter(items) 101 102 if (!items.length) { 103 return this.shown ? this.hide() : this 104 } 105 106 return this.render(items.slice(0, this.options.items)).show() 107 } 108 109 , matcher: function (item) { 110 return ~item.toLowerCase().indexOf(this.query.toLowerCase()) 111 } 112 113 , sorter: function (items) { 114 var beginswith = [] 115 , caseSensitive = [] 116 , caseInsensitive = [] 117 , item 118 119 while (item = items.shift()) { 120 if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item) 121 else if (~item.indexOf(this.query)) caseSensitive.push(item) 122 else caseInsensitive.push(item) 123 } 124 125 return beginswith.concat(caseSensitive, caseInsensitive) 126 } 127 128 , highlighter: function (item) { 129 var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&') 130 return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) { 131 return '<strong>' + match + '</strong>' 132 }) 133 } 134 135 , render: function (items) { 136 var that = this 137 138 items = $(items).map(function (i, item) { 139 i = $(that.options.item).attr('data-value', item) 140 i.find('a').html(that.highlighter(item)) 141 return i[0] 142 }) 143 144 items.first().addClass('active') 145 this.$menu.html(items) 146 return this 147 } 148 149 , next: function (event) { 150 var active = this.$menu.find('.active').removeClass('active') 151 , next = active.next() 152 153 if (!next.length) { 154 next = $(this.$menu.find('li')[0]) 155 } 156 157 next.addClass('active') 158 } 159 160 , prev: function (event) { 161 var active = this.$menu.find('.active').removeClass('active') 162 , prev = active.prev() 163 164 if (!prev.length) { 165 prev = this.$menu.find('li').last() 166 } 167 168 prev.addClass('active') 169 } 170 171 , listen: function () { 172 this.$element 173 .on('blur', $.proxy(this.blur, this)) 174 .on('keypress', $.proxy(this.keypress, this)) 175 .on('keyup', $.proxy(this.keyup, this)) 176 177 if ($.browser.chrome || $.browser.webkit || $.browser.msie) { 178 this.$element.on('keydown', $.proxy(this.keydown, this)) 179 } 180 181 this.$menu 182 .on('click', $.proxy(this.click, this)) 183 .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) 184 } 185 186 , move: function (e) { 187 if (!this.shown) return 188 189 switch(e.keyCode) { 190 case 9: // tab 191 case 13: // enter 192 case 27: // escape 193 e.preventDefault() 194 break 195 196 case 38: // up arrow 197 e.preventDefault() 198 this.prev() 199 break 200 201 case 40: // down arrow 202 e.preventDefault() 203 this.next() 204 break 205 } 206 207 e.stopPropagation() 208 } 209 210 , keydown: function (e) { 211 this.suppressKeyPressRepeat = !~$.inArray(e.keyCode, [40,38,9,13,27]) 212 this.move(e) 213 } 214 215 , keypress: function (e) { 216 if (this.suppressKeyPressRepeat) return 217 this.move(e) 218 } 219 220 , keyup: function (e) { 221 switch(e.keyCode) { 222 case 40: // down arrow 223 case 38: // up arrow 224 break 225 226 case 9: // tab 227 case 13: // enter 228 if (!this.shown) return 229 this.select() 230 break 231 232 case 27: // escape 233 if (!this.shown) return 234 this.hide() 235 break 236 237 default: 238 this.lookup() 239 } 240 241 e.stopPropagation() 242 e.preventDefault() 243 } 244 245 , blur: function (e) { 246 var that = this 247 setTimeout(function () { that.hide() }, 150) 248 } 249 250 , click: function (e) { 251 e.stopPropagation() 252 e.preventDefault() 253 this.select() 254 } 255 256 , mouseenter: function (e) { 257 this.$menu.find('.active').removeClass('active') 258 $(e.currentTarget).addClass('active') 259 } 260 261 } 262 263 264 /* TYPEAHEAD PLUGIN DEFINITION 265 * =========================== */ 266 267 $.fn.typeahead = function (option) { 268 return this.each(function () { 269 var $this = $(this) 270 , data = $this.data('typeahead') 271 , options = typeof option == 'object' && option 272 if (!data) $this.data('typeahead', (data = new Typeahead(this, options))) 273 if (typeof option == 'string') data[option]() 274 }) 275 } 276 277 $.fn.typeahead.defaults = { 278 source: [] 279 , items: 8 280 , menu: '<ul class="typeahead dropdown-menu"></ul>' 281 , item: '<li><a href="#"></a></li>' 282 , minLength: 1 283 } 284 285 $.fn.typeahead.Constructor = Typeahead 286 287 288 /* TYPEAHEAD DATA-API 289 * ================== */ 290 291 $(function () {
292 $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) { 293 var $this = $(this) 294 if ($this.data('typeahead')) return 295 e.preventDefault() 296 $this.typeahead($this.data()) 297 }) 298 }) 299 300}(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.